bearch_arm.c 29.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
/* The main arm backend driver file. */
/* $Id$ */

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include "pseudo_irg.h"
#include "irgwalk.h"
#include "irprog.h"
#include "irprintf.h"
#include "ircons.h"
#include "irgmod.h"
#include "lower_intrinsics.h"

#include "bitset.h"
#include "debug.h"

#include "../bearch.h"                /* the general register allocator interface */
#include "../benode_t.h"
#include "../belower.h"
#include "../besched_t.h"
#include "../be.h"
#include "../beabi.h"

#include "bearch_arm_t.h"

#include "arm_new_nodes.h"           /* arm nodes interface */
#include "gen_arm_regalloc_if.h"     /* the generated interface (register type and class defenitions) */
#include "arm_gen_decls.h"           /* interface declaration emitter */
#include "arm_transform.h"
#include "arm_emitter.h"
#include "arm_map_regs.h"

#define DEBUG_MODULE "firm.be.arm.isa"

/* TODO: ugly, but we need it to get access to the registers assigned to Phi nodes */
static set *cur_reg_set = NULL;

/**************************************************
 *                         _ _              _  __
 *                        | | |            (_)/ _|
 *  _ __ ___  __ _    __ _| | | ___   ___   _| |_
 * | '__/ _ \/ _` |  / _` | | |/ _ \ / __| | |  _|
 * | | |  __/ (_| | | (_| | | | (_) | (__  | | |
 * |_|  \___|\__, |  \__,_|_|_|\___/ \___| |_|_|
 *            __/ |
 *           |___/
 **************************************************/

static ir_node *my_skip_proj(const ir_node *n) {
	while (is_Proj(n))
		n = get_Proj_pred(n);
	return (ir_node *)n;
}

/**
 * Return register requirements for a arm node.
 * If the node returns a tuple (mode_T) then the proj's
 * will be asked for this information.
 */
static const arch_register_req_t *arm_get_irn_reg_req(const void *self, arch_register_req_t *req, const ir_node *irn, int pos) {
	const arm_register_req_t *irn_req;
	long               node_pos = pos == -1 ? 0 : pos;
	ir_mode           *mode     = get_irn_mode(irn);
66
	FIRM_DBG_REGISTER(firm_dbg_module_t *mod, DEBUG_MODULE);
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124

	if (is_Block(irn) || mode == mode_X || mode == mode_M) {
		DBG((mod, LEVEL_1, "ignoring mode_T, mode_M node %+F\n", irn));
		return NULL;
	}

	if (mode == mode_T && pos < 0) {
		DBG((mod, LEVEL_1, "ignoring request for OUT requirements at %+F\n", irn));
		return NULL;
	}

	DBG((mod, LEVEL_1, "get requirements at pos %d for %+F ... ", pos, irn));

	if (is_Proj(irn)) {
		/* in case of a proj, we need to get the correct OUT slot */
		/* of the node corresponding to the proj number */
		if (pos == -1) {
			node_pos = arm_translate_proj_pos(irn);
		}
		else {
			node_pos = pos;
		}

		irn = my_skip_proj(irn);

		DB((mod, LEVEL_1, "skipping Proj, going to %+F at pos %d ... ", irn, node_pos));
	}

	/* get requirements for our own nodes */
	if (is_arm_irn(irn)) {
		if (pos >= 0) {
			irn_req = get_arm_in_req(irn, pos);
		}
		else {
			irn_req = get_arm_out_req(irn, node_pos);
		}

		DB((mod, LEVEL_1, "returning reqs for %+F at pos %d\n", irn, pos));

		memcpy(req, &(irn_req->req), sizeof(*req));

		if (arch_register_req_is(&(irn_req->req), should_be_same)) {
			assert(irn_req->same_pos >= 0 && "should be same constraint for in -> out NYI");
			req->other_same = get_irn_n(irn, irn_req->same_pos);
		}

		if (arch_register_req_is(&(irn_req->req), should_be_different)) {
			assert(irn_req->different_pos >= 0 && "should be different constraint for in -> out NYI");
			req->other_different = get_irn_n(irn, irn_req->different_pos);
		}
	}
	/* get requirements for FIRM nodes */
	else {
		/* treat Phi like Const with default requirements */
		if (is_Phi(irn)) {
			DB((mod, LEVEL_1, "returning standard reqs for %+F\n", irn));

			if (mode_is_float(mode)) {
Michael Beck's avatar
Michael Beck committed
125
				memcpy(req, &(arm_default_req_arm_fp.req), sizeof(*req));
126
127
			}
			else if (mode_is_int(mode) || mode_is_reference(mode)) {
Michael Beck's avatar
Michael Beck committed
128
				memcpy(req, &(arm_default_req_arm_gp.req), sizeof(*req));
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
155
156
157
158
159
160
161
162
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
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
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
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
			}
			else if (mode == mode_T || mode == mode_M) {
				DBG((mod, LEVEL_1, "ignoring Phi node %+F\n", irn));
				return NULL;
			}
			else {
				assert(0 && "unsupported Phi-Mode");
			}
		}
		else {
			DB((mod, LEVEL_1, "returning NULL for %+F (node not supported)\n", irn));
			req = NULL;
		}
	}

	return req;
}

static void arm_set_irn_reg(const void *self, ir_node *irn, const arch_register_t *reg) {
	int pos = 0;

	if (is_Proj(irn)) {

		if (get_irn_mode(irn) == mode_X) {
			return;
		}

		pos = arm_translate_proj_pos(irn);
		irn = my_skip_proj(irn);
	}

	if (is_arm_irn(irn)) {
		const arch_register_t **slots;

		slots      = get_arm_slots(irn);
		slots[pos] = reg;
	}
	else {
		/* here we set the registers for the Phi nodes */
		arm_set_firm_reg(irn, reg, cur_reg_set);
	}
}

static const arch_register_t *arm_get_irn_reg(const void *self, const ir_node *irn) {
	int pos = 0;
	const arch_register_t *reg = NULL;

	if (is_Proj(irn)) {

		if (get_irn_mode(irn) == mode_X) {
			return NULL;
		}

		pos = arm_translate_proj_pos(irn);
		irn = my_skip_proj(irn);
	}

	if (is_arm_irn(irn)) {
		const arch_register_t **slots;
		slots = get_arm_slots(irn);
		reg   = slots[pos];
	}
	else {
		reg = arm_get_firm_reg(irn, cur_reg_set);
	}

	return reg;
}

static arch_irn_class_t arm_classify(const void *self, const ir_node *irn) {
	irn = my_skip_proj(irn);

	if (is_cfop(irn)) {
		return arch_irn_class_branch;
	}
	else if (is_arm_irn(irn)) {
		return arch_irn_class_normal;
	}

	return 0;
}

static arch_irn_flags_t arm_get_flags(const void *self, const ir_node *irn) {
	irn = my_skip_proj(irn);

	if (is_arm_irn(irn)) {
		return get_arm_flags(irn);
	}
	else if (is_Unknown(irn)) {
		return arch_irn_flags_ignore;
	}

	return 0;
}

static entity *arm_get_frame_entity(const void *self, const ir_node *irn) {
	/* TODO: return the entity assigned to the frame */
	return NULL;
}

/**
 * This function is called by the generic backend to correct offsets for
 * nodes accessing the stack.
 */
static void arm_set_stack_bias(const void *self, ir_node *irn, int bias) {
	/* TODO: correct offset if irn accesses the stack */
}

/* fill register allocator interface */

static const arch_irn_ops_if_t arm_irn_ops_if = {
	arm_get_irn_reg_req,
	arm_set_irn_reg,
	arm_get_irn_reg,
	arm_classify,
	arm_get_flags,
	arm_get_frame_entity,
	arm_set_stack_bias
};

arm_irn_ops_t arm_irn_ops = {
	&arm_irn_ops_if,
	NULL
};



/**************************************************
 *                _                         _  __
 *               | |                       (_)/ _|
 *   ___ ___   __| | ___  __ _  ___ _ __    _| |_
 *  / __/ _ \ / _` |/ _ \/ _` |/ _ \ '_ \  | |  _|
 * | (_| (_) | (_| |  __/ (_| |  __/ | | | | | |
 *  \___\___/ \__,_|\___|\__, |\___|_| |_| |_|_|
 *                        __/ |
 *                       |___/
 **************************************************/

/**
Michael Beck's avatar
Michael Beck committed
268
269
 * Transforms the standard Firm graph into
 * a ARM firm graph.
270
271
272
273
 */
static void arm_prepare_graph(void *self) {
	arm_code_gen_t *cg = self;

Michael Beck's avatar
Michael Beck committed
274
	arm_register_transformers();
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
	irg_walk_blkwise_graph(cg->irg, arm_move_consts, arm_transform_node, cg);
}



/**
 * Called immediately before emit phase.
 */
static void arm_finish_irg(ir_graph *irg, arm_code_gen_t *cg) {
	/* TODO: - fix offsets for nodes accessing stack
			 - ...
	*/
}


/**
 * These are some hooks which must be filled but are probably not needed.
 */
static void arm_before_sched(void *self) {
	/* Some stuff you need to do after scheduling but before register allocation */
}

static void arm_before_ra(void *self) {
	/* Some stuff you need to do immediately after register allocation */
}


/**
 * Emits the code, closes the output file and frees
 * the code generator interface.
 */
static void arm_emit_and_done(void *self) {
	arm_code_gen_t *cg = self;
	ir_graph           *irg = cg->irg;
309
	FILE               *out = cg->isa->out;
310
311

	if (cg->emit_decls) {
312
		arm_gen_decls(out);
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
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
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
		cg->emit_decls = 0;
	}

	arm_finish_irg(irg, cg);
	dump_ir_block_graph_sched(irg, "-arm-finished");
	arm_gen_routine(out, irg, cg);

	cur_reg_set = NULL;

	/* de-allocate code generator */
	del_set(cg->reg_set);
	free(self);
}

enum convert_which { low, high };

/**
 * Move an floating point value to a integer register.
 * Place the move operation into block bl.
 */
static ir_node *convert_to_int(ir_node *bl, ir_node *arg, enum convert_which which) {
	return NULL;
}

/**
 * Convert the arguments of a call to support the
 * ARM calling convention of general purpose AND floating
 * point arguments
 */
static void handle_calls(ir_node *call, void *env)
{
	arm_code_gen_t *cg = env;
	int i, j, n, size, idx, flag, n_param, n_res;
	ir_type *mtp, *new_mtd, *new_tp[5];
	ir_node *new_in[5], **in;
	ir_node *bl;

	if (! is_Call(call))
		return;

	/* check, if we need conversions */
	n = get_Call_n_params(call);
	mtp = get_Call_type(call);
	assert(get_method_n_params(mtp) == n);

	/* it's always enough to handle the first 4 parameters */
	if (n > 4)
		n = 4;
	flag = size = idx = 0;
	bl = get_nodes_block(call);
	for (i = 0; i < n; ++i) {
		ir_type *param_tp = get_method_param_type(mtp, i);

		if (is_compound_type(param_tp)) {
			/* an aggregate parameter: bad case */
			assert(0);
		}
		else {
			/* a primitive parameter */
			ir_mode *mode = get_type_mode(param_tp);

			if (mode_is_float(mode)) {
				if (get_mode_size_bits(mode) > 32) {
					size += 2 * 4;
					new_tp[idx] = cg->int_tp;
					new_in[idx] = convert_to_int(bl, get_Call_param(call, i), low);
					++idx;
					new_tp[idx] = cg->int_tp;
					new_in[idx] = convert_to_int(bl, get_Call_param(call, i), high);
					++idx;
				}
				else {
					size += 4;
					new_tp[idx] = cg->int_tp;
					new_in[idx] = convert_to_int(bl, get_Call_param(call, i), low);
					++idx;
				}
				flag = 1;
			}
			else {
				size += 4;
				new_tp[idx] = param_tp;
				new_in[idx] = get_Call_param(call, i);
				++idx;
			}
		}

		if (size >= 16)
			break;
	}

	/* if flag is NOT set, no need to translate the method type */
	if (! flag)
		return;

	/* construct a new method type */
	n       = i;
	n_param = get_method_n_params(mtp) - n + idx;
	n_res   = get_method_n_ress(mtp);
	new_mtd = new_d_type_method(get_type_ident(mtp), n_param, n_res, get_type_dbg_info(mtp));

	for (i = 0; i < idx; ++i)
		set_method_param_type(new_mtd, i, new_tp[i]);
	for (i = n, j = idx; i < get_method_n_params(mtp); ++i)
		set_method_param_type(new_mtd, j++, get_method_param_type(mtp, i));
	for (i = 0; i < n_res; ++i)
		set_method_res_type(new_mtd, i, get_method_res_type(mtp, i));

	set_method_calling_convention(new_mtd, get_method_calling_convention(mtp));
	set_method_first_variadic_param_index(new_mtd, get_method_first_variadic_param_index(mtp));

	if (is_lowered_type(mtp)) {
		mtp = get_associated_type(mtp);
	}
	set_lowered_type(mtp, new_mtd);

	set_Call_type(call, new_mtd);

	/* calculate new in array of the Call */
	NEW_ARR_A(ir_node *, in, n_param + 2);
	for (i = 0; i < idx; ++i)
		in[2 + i] = new_in[i];
	for (i = n, j = idx; i < get_method_n_params(mtp); ++i)
		in[2 + j++] = get_Call_param(call, i);

	in[0] = get_Call_mem(call);
	in[1] = get_Call_ptr(call);

	/* finally, change the call inputs */
	set_irn_in(call, n_param + 2, in);
}

/**
 * Handle graph transformations before the abi converter does it's work
 */
static void arm_before_abi(void *self) {
	arm_code_gen_t *cg = self;

	irg_walk_graph(cg->irg, NULL, handle_calls, cg);
}

454
static void *arm_cg_init(const be_irg_t *birg);
455
456
457

static const arch_code_generator_if_t arm_code_gen_if = {
	arm_cg_init,
458
	arm_before_abi,     /* before abi introduce */
459
460
461
462
463
464
465
466
467
468
	arm_prepare_graph,
	arm_before_sched,   /* before scheduling hook */
	arm_before_ra,      /* before register allocation hook */
	NULL, /* after register allocation */
	arm_emit_and_done,
};

/**
 * Initializes the code generator.
 */
469
static void *arm_cg_init(const be_irg_t *birg) {
470
471
472
473
	static ir_type *int_tp = NULL;
	arm_isa_t      *isa = (arm_isa_t *)birg->main_env->arch_env->isa;
	arm_code_gen_t *cg;

Michael Beck's avatar
Michael Beck committed
474
	if (! int_tp) {
475
476
477
478
479
480
481
482
483
		/* create an integer type with machine size */
		int_tp = new_type_primitive(new_id_from_chars("int", 3), mode_Is);
	}

	cg = xmalloc(sizeof(*cg));
	cg->impl     = &arm_code_gen_if;
	cg->irg      = birg->irg;
	cg->reg_set  = new_set(arm_cmp_irn_reg_assoc, 1024);
	cg->arch_env = birg->main_env->arch_env;
484
	cg->isa      = isa;
485
486
	cg->birg     = birg;
	cg->int_tp   = int_tp;
Michael Beck's avatar
Michael Beck committed
487
	cg->have_fp  = 0;
488

489
	FIRM_DBG_REGISTER(cg->mod, "firm.be.arm.cg");
490
491
492
493
494
495
496
497
498
499
500
501

	isa->num_codegens++;

	if (isa->num_codegens > 1)
		cg->emit_decls = 0;
	else
		cg->emit_decls = 1;

	cur_reg_set = cg->reg_set;

	arm_irn_ops.cg = cg;

Michael Beck's avatar
Michael Beck committed
502
503
504
	/* enter the current code generator */
	isa->cg = cg;

505
506
507
508
509
510
511
512
513
	return (arch_code_generator_t *)cg;
}


/**
 * Maps all intrinsic calls that the backend support
 * and map all instructions the backend did not support
 * to runtime calls.
 */
Michael Beck's avatar
Michael Beck committed
514
static void arm_global_init(void) {
515
516
517
518
519
520
521
522
523
  ir_type *tp, *int_tp, *uint_tp;
  i_record records[8];
  int n_records = 0;

#define ID(x) new_id_from_chars(x, sizeof(x)-1)

  int_tp  = new_type_primitive(ID("int"), mode_Is);
  uint_tp = new_type_primitive(ID("uint"), mode_Iu);

Michael Beck's avatar
Michael Beck committed
524
	/* ARM has neither a signed div instruction ... */
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
  {
    runtime_rt rt_Div;
    i_instr_record *map_Div = &records[n_records++].i_instr;

    tp = new_type_method(ID("rt_iDiv"), 2, 1);
    set_method_param_type(tp, 0, int_tp);
    set_method_param_type(tp, 1, int_tp);
    set_method_res_type(tp, 0, int_tp);

    rt_Div.ent             = new_entity(get_glob_type(), ID("__divsi3"), tp);
    rt_Div.mode            = mode_T;
    rt_Div.mem_proj_nr     = pn_Div_M;
    rt_Div.exc_proj_nr     = pn_Div_X_except;
    rt_Div.exc_mem_proj_nr = pn_Div_M;
    rt_Div.res_proj_nr     = pn_Div_res;

    set_entity_visibility(rt_Div.ent, visibility_external_allocated);

    map_Div->kind     = INTRINSIC_INSTR;
    map_Div->op       = op_Div;
Christian Würdig's avatar
Christian Würdig committed
545
    map_Div->i_mapper = (i_mapper_func)i_mapper_RuntimeCall;
546
547
    map_Div->ctx      = &rt_Div;
  }
Michael Beck's avatar
Michael Beck committed
548
	/* ... nor a signed div instruction ... */
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
  {
    runtime_rt rt_Div;
    i_instr_record *map_Div = &records[n_records++].i_instr;

    tp = new_type_method(ID("rt_uDiv"), 2, 1);
    set_method_param_type(tp, 0, uint_tp);
    set_method_param_type(tp, 1, uint_tp);
    set_method_res_type(tp, 0, uint_tp);

    rt_Div.ent             = new_entity(get_glob_type(), ID("__udivsi3"), tp);
    rt_Div.mode            = mode_T;
    rt_Div.mem_proj_nr     = pn_Div_M;
    rt_Div.exc_proj_nr     = pn_Div_X_except;
    rt_Div.exc_mem_proj_nr = pn_Div_M;
    rt_Div.res_proj_nr     = pn_Div_res;

    set_entity_visibility(rt_Div.ent, visibility_external_allocated);

    map_Div->kind     = INTRINSIC_INSTR;
    map_Div->op       = op_Div;
Christian Würdig's avatar
Christian Würdig committed
569
    map_Div->i_mapper = (i_mapper_func)i_mapper_RuntimeCall;
570
571
    map_Div->ctx      = &rt_Div;
  }
Michael Beck's avatar
Michael Beck committed
572
	/* ... nor a signed mod instruction ... */
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
  {
    runtime_rt rt_Mod;
    i_instr_record *map_Mod = &records[n_records++].i_instr;

    tp = new_type_method(ID("rt_iMod"), 2, 1);
    set_method_param_type(tp, 0, int_tp);
    set_method_param_type(tp, 1, int_tp);
    set_method_res_type(tp, 0, int_tp);

    rt_Mod.ent             = new_entity(get_glob_type(), ID("__modsi3"), tp);
    rt_Mod.mode            = mode_T;
    rt_Mod.mem_proj_nr     = pn_Mod_M;
    rt_Mod.exc_proj_nr     = pn_Mod_X_except;
    rt_Mod.exc_mem_proj_nr = pn_Mod_M;
    rt_Mod.res_proj_nr     = pn_Mod_res;

    set_entity_visibility(rt_Mod.ent, visibility_external_allocated);

    map_Mod->kind     = INTRINSIC_INSTR;
    map_Mod->op       = op_Mod;
Christian Würdig's avatar
Christian Würdig committed
593
    map_Mod->i_mapper = (i_mapper_func)i_mapper_RuntimeCall;
594
595
    map_Mod->ctx      = &rt_Mod;
  }
Michael Beck's avatar
Michael Beck committed
596
	/* ... nor a unsigned mod. */
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
  {
    runtime_rt rt_Mod;
    i_instr_record *map_Mod = &records[n_records++].i_instr;

    tp = new_type_method(ID("rt_uMod"), 2, 1);
    set_method_param_type(tp, 0, uint_tp);
    set_method_param_type(tp, 1, uint_tp);
    set_method_res_type(tp, 0, uint_tp);

    rt_Mod.ent             = new_entity(get_glob_type(), ID("__umodsi3"), tp);
    rt_Mod.mode            = mode_T;
    rt_Mod.mem_proj_nr     = pn_Mod_M;
    rt_Mod.exc_proj_nr     = pn_Mod_X_except;
    rt_Mod.exc_mem_proj_nr = pn_Mod_M;
    rt_Mod.res_proj_nr     = pn_Mod_res;

    set_entity_visibility(rt_Mod.ent, visibility_external_allocated);

    map_Mod->kind     = INTRINSIC_INSTR;
    map_Mod->op       = op_Mod;
Christian Würdig's avatar
Christian Würdig committed
617
    map_Mod->i_mapper = (i_mapper_func)i_mapper_RuntimeCall;
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
    map_Mod->ctx      = &rt_Mod;
  }

  if (n_records > 0)
    lower_intrinsics(records, n_records);
}

/*****************************************************************
 *  ____             _                  _   _____  _____
 * |  _ \           | |                | | |_   _|/ ____|  /\
 * | |_) | __ _  ___| | _____ _ __   __| |   | | | (___   /  \
 * |  _ < / _` |/ __| |/ / _ \ '_ \ / _` |   | |  \___ \ / /\ \
 * | |_) | (_| | (__|   <  __/ | | | (_| |  _| |_ ____) / ____ \
 * |____/ \__,_|\___|_|\_\___|_| |_|\__,_| |_____|_____/_/    \_\
 *
 *****************************************************************/

static arm_isa_t arm_isa_template = {
Michael Beck's avatar
Michael Beck committed
636
637
638
639
640
641
	&arm_isa_if,           /* isa interface */
	&arm_gp_regs[REG_SP],  /* stack pointer */
	&arm_gp_regs[REG_R11], /* base pointer */
	-1,                    /* stack direction */
	0,                     /* number of codegenerator objects */
	0,                     /* use generic register names instead of SP, LR, PC */
642
643
	NULL,                  /* current code generator */
	NULL,                  /* output file */
644
645
646
647
648
};

/**
 * Initializes the backend ISA and opens the output file.
 */
649
static void *arm_init(FILE *file_handle) {
650
651
652
653
654
655
	static int inited = 0;
	arm_isa_t *isa;

	if(inited)
		return NULL;

Michael Beck's avatar
Michael Beck committed
656
	isa = xmalloc(sizeof(*isa));
657
658
659
	memcpy(isa, &arm_isa_template, sizeof(*isa));

	arm_register_init(isa);
Michael Beck's avatar
Michael Beck committed
660
661
662
663
664
665
666
667
	if (isa->gen_reg_names) {
		/* patch register names */
		arm_gp_regs[REG_R11].name = "r11";
		arm_gp_regs[REG_SP].name  = "r13";
		arm_gp_regs[REG_LR].name  = "r14";
		arm_gp_regs[REG_PC].name  = "r15";
	}

668
669
	isa->cg  = NULL;
	isa->out = file_handle;
Michael Beck's avatar
Michael Beck committed
670

671
	arm_create_opcodes();
Michael Beck's avatar
Michael Beck committed
672
673
	arm_global_init();
	arm_switch_section(NULL, NO_SECTION);
674
675
676
677
678
679
680
681

	inited = 1;
	return isa;
}



/**
Michael Beck's avatar
Michael Beck committed
682
 * frees the ISA structure.
683
684
685
686
687
688
 */
static void arm_done(void *self) {
	free(self);
}


Michael Beck's avatar
Michael Beck committed
689
690
691
692
693
694
/**
 * Report the number of register classes.
 * If we don't have fp instructions, report only GP
 * here to speed up register allocation (and makes dumps
 * smaller and more readable).
 */
695
static int arm_get_n_reg_class(const void *self) {
Michael Beck's avatar
Michael Beck committed
696
697
698
	const arm_isa_t *isa = self;

	return isa->cg->have_fp ? 2 : 1;
699
700
}

Michael Beck's avatar
Michael Beck committed
701
702
703
/**
 * Return the register class with requested index.
 */
704
static const arch_register_class_t *arm_get_reg_class(const void *self, int i) {
Michael Beck's avatar
Michael Beck committed
705
	return i == 0 ? &arm_reg_classes[CLASS_arm_gp] : &arm_reg_classes[CLASS_arm_fp];
706
707
708
709
710
711
712
713
714
715
}

/**
 * Get the register class which shall be used to store a value of a given mode.
 * @param self The this pointer.
 * @param mode The mode in question.
 * @return A register class which can hold values of the given mode.
 */
const arch_register_class_t *arm_get_reg_class_for_mode(const void *self, const ir_mode *mode) {
	if (mode_is_float(mode))
Michael Beck's avatar
Michael Beck committed
716
		return &arm_reg_classes[CLASS_arm_fp];
717
	else
Michael Beck's avatar
Michael Beck committed
718
		return &arm_reg_classes[CLASS_arm_gp];
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
}

/**
 * Produces the type which sits between the stack args and the locals on the stack.
 * it will contain the return address and space to store the old base pointer.
 * @return The Firm type modelling the ABI between type.
 */
static ir_type *arm_get_between_type(void *self) {
	static ir_type *between_type = NULL;
	static entity *old_bp_ent    = NULL;

	if(!between_type) {
		entity *ret_addr_ent;
		ir_type *ret_addr_type = new_type_primitive(new_id_from_str("return_addr"), mode_P);
		ir_type *old_bp_type   = new_type_primitive(new_id_from_str("bp"), mode_P);

		between_type           = new_type_class(new_id_from_str("arm_between_type"));
		old_bp_ent             = new_entity(between_type, new_id_from_str("old_bp"), old_bp_type);
		ret_addr_ent           = new_entity(between_type, new_id_from_str("old_bp"), ret_addr_type);

		set_entity_offset_bytes(old_bp_ent, 0);
		set_entity_offset_bytes(ret_addr_ent, get_type_size_bytes(old_bp_type));
		set_type_size_bytes(between_type, get_type_size_bytes(old_bp_type) + get_type_size_bytes(ret_addr_type));
	}

	return between_type;
}


typedef struct {
	be_abi_call_flags_bits_t flags;
	const arch_env_t *arch_env;
	const arch_isa_t *isa;
	ir_graph *irg;
} arm_abi_env_t;

static void *arm_abi_init(const be_abi_call_t *call, const arch_env_t *arch_env, ir_graph *irg)
{
Michael Beck's avatar
Michael Beck committed
757
	arm_abi_env_t *env     = xmalloc(sizeof(env[0]));
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
	be_abi_call_flags_t fl = be_abi_call_get_flags(call);
	env->flags    = fl.bits;
	env->irg      = irg;
	env->arch_env = arch_env;
	env->isa      = arch_env->isa;
	return env;
}

static void arm_abi_dont_save_regs(void *self, pset *s)
{
	arm_abi_env_t *env = self;
	if(env->flags.try_omit_fp)
		pset_insert_ptr(s, env->isa->bp);
}



/**
 * Build the ARM prolog
 */
static const arch_register_t *arm_abi_prologue(void *self, ir_node **mem, pmap *reg_map) {
	ir_node *keep, *store;
	arm_abi_env_t *env = self;
	ir_graph *irg = env->irg;
	ir_node *block = get_irg_start_block(irg);
//	ir_node *regs[16];
//	int n_regs = 0;
Michael Beck's avatar
Michael Beck committed
785
	arch_register_class_t *gp = &arm_reg_classes[CLASS_arm_gp];
786
	static const arm_register_req_t *fp_req[] = {
Michael Beck's avatar
Michael Beck committed
787
		&arm_default_req_arm_gp_r11
788
789
790
	};

	ir_node *fp = be_abi_reg_map_get(reg_map, env->isa->bp);
Michael Beck's avatar
Michael Beck committed
791
	ir_node *ip = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_R12]);
792
	ir_node *sp = be_abi_reg_map_get(reg_map, env->isa->sp);
Michael Beck's avatar
Michael Beck committed
793
794
795
796
797
798
	ir_node *lr = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_LR]);
	ir_node *pc = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_PC]);
// 	ir_node *r0 = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_R0]);
// 	ir_node *r1 = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_R1]);
// 	ir_node *r2 = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_R2]);
// 	ir_node *r3 = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_R3]);
799
800
801
802
803

	if(env->flags.try_omit_fp)
		return env->isa->sp;

	ip = be_new_Copy(gp, irg, block, sp );
Michael Beck's avatar
Michael Beck committed
804
805
		arch_set_irn_register(env->arch_env, ip, &arm_gp_regs[REG_R12]);
		be_set_constr_single_reg(ip, BE_OUT_POS(0), &arm_gp_regs[REG_R12] );
806
807
808
809
810
811

//	if (r0) regs[n_regs++] = r0;
//	if (r1) regs[n_regs++] = r1;
//	if (r2) regs[n_regs++] = r2;
//	if (r3) regs[n_regs++] = r3;
//	sp = new_r_arm_StoreStackMInc(irg, block, *mem, sp, n_regs, regs, get_irn_mode(sp));
Michael Beck's avatar
Michael Beck committed
812
//		set_arm_req_out(sp, &arm_default_req_arm_gp_sp, 0);
813
//		arch_set_irn_register(env->arch_env, sp, env->isa->sp);
Michael Beck's avatar
Michael Beck committed
814
	store = new_rd_arm_StoreStackM4Inc(NULL, irg, block, sp, fp, ip, lr, pc, *mem);
Michael Beck's avatar
Michael Beck committed
815
		set_arm_req_out(store, &arm_default_req_arm_gp_sp, 0);
816
817
//		arch_set_irn_register(env->arch_env, store, env->isa->sp);

Michael Beck's avatar
Michael Beck committed
818
	sp = new_r_Proj(irg, block, store, env->isa->sp->reg_class->mode, pn_arm_StoreStackM4Inc_ptr);
819
		arch_set_irn_register(env->arch_env, sp, env->isa->sp);
Michael Beck's avatar
Michael Beck committed
820
	*mem = new_r_Proj(irg, block, store, mode_M, pn_arm_StoreStackM4Inc_M);
821
822
823

	keep = be_new_CopyKeep_single(gp, irg, block, ip, sp, get_irn_mode(ip));
		be_node_set_reg_class(keep, 1, gp);
Michael Beck's avatar
Michael Beck committed
824
825
		arch_set_irn_register(env->arch_env, keep, &arm_gp_regs[REG_R12]);
		be_set_constr_single_reg(keep, BE_OUT_POS(0), &arm_gp_regs[REG_R12] );
826

Michael Beck's avatar
Michael Beck committed
827
828
	fp = new_rd_arm_Sub_i(NULL, irg, block, keep, get_irn_mode(fp),
	                      new_tarval_from_long(4, get_irn_mode(fp)));
829
		set_arm_req_out_all(fp, fp_req);
Michael Beck's avatar
Michael Beck committed
830
		//set_arm_req_out(fp, &arm_default_req_arm_gp_r11, 0);
831
832
		arch_set_irn_register(env->arch_env, fp, env->isa->bp);

Michael Beck's avatar
Michael Beck committed
833
834
835
836
// 	be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_R0], r0);
// 	be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_R1], r1);
// 	be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_R2], r2);
// 	be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_R3], r3);
837
	be_abi_reg_map_set(reg_map, env->isa->bp, fp);
Michael Beck's avatar
Michael Beck committed
838
	be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_R12], keep);
839
	be_abi_reg_map_set(reg_map, env->isa->sp, sp);
Michael Beck's avatar
Michael Beck committed
840
841
	be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_LR], lr);
	be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_PC], pc);
842
843
844
845
846
847
848
849

	return env->isa->bp;
}

static void arm_abi_epilogue(void *self, ir_node *bl, ir_node **mem, pmap *reg_map) {
	arm_abi_env_t *env = self;
	ir_node *curr_sp = be_abi_reg_map_get(reg_map, env->isa->sp);
	ir_node *curr_bp = be_abi_reg_map_get(reg_map, env->isa->bp);
Michael Beck's avatar
Michael Beck committed
850
851
	ir_node *curr_pc = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_PC]);
	ir_node	*curr_lr = be_abi_reg_map_get(reg_map, &arm_gp_regs[REG_LR]);
852
	static const arm_register_req_t *sub12_req[] = {
Michael Beck's avatar
Michael Beck committed
853
		&arm_default_req_arm_gp_sp
854
855
856
857
858
859
	};

//	TODO: Activate Omit fp in epilogue
	if(env->flags.try_omit_fp) {
		curr_sp = be_new_IncSP(env->isa->sp, env->irg, bl, curr_sp, *mem, BE_STACK_FRAME_SIZE, be_stack_dir_shrink);

Michael Beck's avatar
Michael Beck committed
860
861
862
863
		curr_lr = be_new_CopyKeep_single(&arm_reg_classes[CLASS_arm_gp], env->irg, bl, curr_lr, curr_sp, get_irn_mode(curr_lr));
		be_node_set_reg_class(curr_lr, 1, &arm_reg_classes[CLASS_arm_gp]);
		arch_set_irn_register(env->arch_env, curr_lr, &arm_gp_regs[REG_LR]);
		be_set_constr_single_reg(curr_lr, BE_OUT_POS(0), &arm_gp_regs[REG_LR] );
864

Michael Beck's avatar
Michael Beck committed
865
866
867
		curr_pc = be_new_Copy(&arm_reg_classes[CLASS_arm_gp], env->irg, bl, curr_lr );
		arch_set_irn_register(env->arch_env, curr_pc, &arm_gp_regs[REG_PC]);
		be_set_constr_single_reg(curr_pc, BE_OUT_POS(0), &arm_gp_regs[REG_PC] );
868
869
870
	} else {
		ir_node *sub12_node;
		ir_node *load_node;
Michael Beck's avatar
Michael Beck committed
871
872
		tarval *tv = new_tarval_from_long(12,mode_Iu);
		sub12_node = new_rd_arm_Sub_i(NULL, env->irg, bl, curr_bp, mode_Iu, tv);
873
874
		set_arm_req_out_all(sub12_node, sub12_req);
		arch_set_irn_register(env->arch_env, sub12_node, env->isa->sp);
Michael Beck's avatar
Michael Beck committed
875
		load_node = new_rd_arm_LoadStackM3( NULL, env->irg, bl, sub12_node, *mem );
Michael Beck's avatar
Michael Beck committed
876
877
878
		set_arm_req_out(load_node, &arm_default_req_arm_gp_r11, 0);
		set_arm_req_out(load_node, &arm_default_req_arm_gp_sp, 1);
		set_arm_req_out(load_node, &arm_default_req_arm_gp_pc, 2);
Michael Beck's avatar
Michael Beck committed
879
880
881
882
		curr_bp = new_r_Proj(env->irg, bl, load_node, env->isa->bp->reg_class->mode, pn_arm_LoadStackM3_res0);
		curr_sp = new_r_Proj(env->irg, bl, load_node, env->isa->sp->reg_class->mode, pn_arm_LoadStackM3_res1);
		curr_pc = new_r_Proj(env->irg, bl, load_node, mode_Iu, pn_arm_LoadStackM3_res2);
		*mem    = new_r_Proj(env->irg, bl, load_node, mode_M, pn_arm_LoadStackM3_M);
883
884
		arch_set_irn_register(env->arch_env, curr_bp, env->isa->bp);
		arch_set_irn_register(env->arch_env, curr_sp, env->isa->sp);
Michael Beck's avatar
Michael Beck committed
885
		arch_set_irn_register(env->arch_env, curr_pc, &arm_gp_regs[REG_PC]);
886
887
888
	}
	be_abi_reg_map_set(reg_map, env->isa->sp, curr_sp);
	be_abi_reg_map_set(reg_map, env->isa->bp, curr_bp);
Michael Beck's avatar
Michael Beck committed
889
890
	be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_LR], curr_lr);
	be_abi_reg_map_set(reg_map, &arm_gp_regs[REG_PC], curr_pc);
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
}

static const be_abi_callbacks_t arm_abi_callbacks = {
	arm_abi_init,
	free,
	arm_get_between_type,
	arm_abi_dont_save_regs,
	arm_abi_prologue,
	arm_abi_epilogue,
};


/**
 * Get the ABI restrictions for procedure calls.
 * @param self        The this pointer.
 * @param method_type The type of the method (procedure) in question.
 * @param abi         The abi object to be modified
 */
void arm_get_call_abi(const void *self, ir_type *method_type, be_abi_call_t *abi) {
	ir_type  *tp;
	ir_mode  *mode;
	int       i;
	int       n = get_method_n_params(method_type);
	be_abi_call_flags_t flags = {
Christian Würdig's avatar
Christian Würdig committed
915
916
917
918
919
920
921
		{
			0, /* store from left to right */
			0, /* store arguments sequential */
			1, /* try to omit the frame pointer */
			1, /* the function can use any register as frame pointer */
			1  /* a call can take the callee's address as an immediate */
		}
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
	};

	/* set stack parameter passing style */
	be_abi_call_set_flags(abi, flags, &arm_abi_callbacks);

	for (i = 0; i < n; i++) {
		/* reg = get reg for param i;          */
		/* be_abi_call_param_reg(abi, i, reg); */
		if (i < 4)

			be_abi_call_param_reg(abi, i, arm_get_RegParam_reg(i));
		else
			be_abi_call_param_stack(abi, i, 4, 0, 0);
	}

	/* default: return value is in R0 resp. F0 */
	assert(get_method_n_ress(method_type) < 2);
	if (get_method_n_ress(method_type) > 0) {
		tp   = get_method_res_type(method_type, 0);
		mode = get_type_mode(tp);

		be_abi_call_res_reg(abi, 0,
Michael Beck's avatar
Michael Beck committed
944
			mode_is_float(mode) ? &arm_fp_regs[REG_F0] : &arm_gp_regs[REG_R0]);
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
	}
}

static const void *arm_get_irn_ops(const arch_irn_handler_t *self, const ir_node *irn) {
	return &arm_irn_ops;
}

const arch_irn_handler_t arm_irn_handler = {
	arm_get_irn_ops
};

const arch_irn_handler_t *arm_get_irn_handler(const void *self) {
	return &arm_irn_handler;
}

int arm_to_appear_in_schedule(void *block_env, const ir_node *irn) {
	return is_arm_irn(irn);
}

/**
 * Initializes the code generator interface.
 */
static const arch_code_generator_if_t *arm_get_code_generator_if(void *self) {
	return &arm_code_gen_if;
}

list_sched_selector_t arm_sched_selector;

/**
 * Returns the reg_pressure scheduler with to_appear_in_schedule() over\loaded
 */
static const list_sched_selector_t *arm_get_list_sched_selector(const void *self) {
	memcpy(&arm_sched_selector, reg_pressure_selector, sizeof(list_sched_selector_t));
	arm_sched_selector.to_appear_in_schedule = arm_to_appear_in_schedule;
	return &arm_sched_selector;
}

982
983
984
985
986
987
988
989
/**
 * Returns the necessary byte alignment for storing a register of given class.
 */
static int arm_get_reg_class_alignment(const void *self, const arch_register_class_t *cls) {
	ir_mode *mode = arch_register_class_mode(cls);
	return get_mode_size_bytes(mode);
}

990
#ifdef WITH_LIBCORE
Michael Beck's avatar
Michael Beck committed
991
992
993
994
995
996
997
998
999
1000
static const lc_opt_table_entry_t arm_options[] = {
	LC_OPT_ENT_BOOL("gen_reg_names", "use generic register names", &arm_isa_template.gen_reg_names),
	{ NULL }
};

/**
 * Register command line options for the ARM backend.
 *
 * Options so far:
 *
For faster browsing, not all history is shown. View entire blame