arm_emitter.c 19.4 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   arm emitter
Matthias Braun's avatar
Matthias Braun committed
9
 * @author  Oliver Richter, Tobias Gneist, Michael Beck, Matthias Braun
10
 */
Matthias Braun's avatar
Matthias Braun committed
11
#include <inttypes.h>
12

13
14
15
16
#include "arm_cconv.h"
#include "arm_emitter.h"
#include "arm_new_nodes.h"
#include "be_t.h"
17
#include "bearch_arm_t.h"
18
#include "beblocksched.h"
19
#include "bediagnostic.h"
20
21
22
#include "begnuas.h"
#include "benode.h"
#include "besched.h"
23
#include "debug.h"
24
25
#include "gen_arm_emitter.h"
#include "gen_arm_regalloc_if.h"
26
#include "irgwalk.h"
Matthias Braun's avatar
Matthias Braun committed
27
#include "panic.h"
28
29
#include "pmap.h"
#include "util.h"
30

31
32
33
34
35
36
37
38
39
40
41
42
43
/** An entry in the ent_or_tv set. */
typedef struct ent_or_tv_t ent_or_tv_t;
struct ent_or_tv_t {
	union {
		ir_entity  *entity;  /**< An entity. */
		ir_tarval  *tv;      /**< A tarval. */
		const void *generic; /**< For generic compare. */
	} u;
	unsigned     label;      /**< the associated label. */
	bool         is_entity;  /**< true if an entity is stored. */
	ent_or_tv_t *next;       /**< next in list. */
};

44
45
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

46
47
48
static struct obstack obst;
static pmap          *ent_or_tv;
static ent_or_tv_t   *ent_or_tv_first;
49
static ent_or_tv_t  **ent_or_tv_anchor;
50

51
52
static void arm_emit_register(const arch_register_t *reg)
{
53
	be_emit_string(reg->name);
54
55
}

Matthias Braun's avatar
Matthias Braun committed
56
static void arm_emit_source_register(const ir_node *node, int pos)
57
{
58
	const arch_register_t *reg = arch_get_irn_register_in(node, pos);
59
	arm_emit_register(reg);
Michael Beck's avatar
Michael Beck committed
60
}
61

Matthias Braun's avatar
Matthias Braun committed
62
static void arm_emit_dest_register(const ir_node *node, int pos)
63
{
64
	const arch_register_t *reg = arch_get_irn_register_out(node, pos);
65
	arm_emit_register(reg);
66
67
}

Matthias Braun's avatar
Matthias Braun committed
68
static void arm_emit_offset(const ir_node *node)
69
70
71
{
	const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
	assert(attr->base.is_load_store);
Michael Beck's avatar
Michael Beck committed
72

73
	be_emit_irprintf("0x%X", attr->offset);
74
75
76
}

/**
Michael Beck's avatar
Michael Beck committed
77
 * Emit the arm fpa instruction suffix depending on the mode.
78
 */
79
80
static void arm_emit_fpa_postfix(const ir_mode *mode)
{
Michael Beck's avatar
Michael Beck committed
81
	int bits = get_mode_size_bits(mode);
Michael Beck's avatar
Michael Beck committed
82
83
	char c = 'e';

Michael Beck's avatar
Michael Beck committed
84
	if (bits == 32)
Michael Beck's avatar
Michael Beck committed
85
		c = 's';
Michael Beck's avatar
Michael Beck committed
86
	else if (bits == 64)
Michael Beck's avatar
Michael Beck committed
87
88
		c = 'd';
	be_emit_char(c);
89
90
}

Matthias Braun's avatar
Matthias Braun committed
91
static void arm_emit_float_load_store_mode(const ir_node *node)
92
{
93
94
95
	const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
	arm_emit_fpa_postfix(attr->load_store_mode);
}
Michael Beck's avatar
Michael Beck committed
96

Matthias Braun's avatar
Matthias Braun committed
97
static void arm_emit_float_arithmetic_mode(const ir_node *node)
98
99
100
{
	const arm_farith_attr_t *attr = get_arm_farith_attr_const(node);
	arm_emit_fpa_postfix(attr->mode);
Michael Beck's avatar
Michael Beck committed
101
102
}

103
static void arm_emit_address(const ir_node *node)
104
{
105
106
	const arm_Address_attr_t *address = get_arm_Address_attr_const(node);
	ir_entity                *entity  = address->entity;
107
108
109
110
111
112

	be_gas_emit_entity(entity);

	/* TODO do something with offset */
}

Matthias Braun's avatar
Matthias Braun committed
113
static void arm_emit_load_mode(const ir_node *node)
114
115
116
117
118
119
120
121
122
123
124
125
126
127
{
	const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
	ir_mode *mode      = attr->load_store_mode;
	int      bits      = get_mode_size_bits(mode);
	bool     is_signed = mode_is_signed(mode);
	if (bits == 16) {
		be_emit_string(is_signed ? "sh" : "h");
	} else if (bits == 8) {
		be_emit_string(is_signed ? "sb" : "b");
	} else {
		assert(bits == 32);
	}
}

Matthias Braun's avatar
Matthias Braun committed
128
static void arm_emit_store_mode(const ir_node *node)
129
130
131
132
133
134
135
136
137
138
139
140
141
{
	const arm_load_store_attr_t *attr = get_arm_load_store_attr_const(node);
	ir_mode *mode      = attr->load_store_mode;
	int      bits      = get_mode_size_bits(mode);
	if (bits == 16) {
		be_emit_cstring("h");
	} else if (bits == 8) {
		be_emit_cstring("b");
	} else {
		assert(bits == 32);
	}
}

142
static char const *get_shf_mod_name(arm_shift_modifier_t mod)
143
144
145
{
	switch (mod) {
	case ARM_SHF_ASR_REG:
146
	case ARM_SHF_ASR_IMM: return "asr";
147
	case ARM_SHF_LSL_REG:
148
	case ARM_SHF_LSL_IMM: return "lsl";
149
	case ARM_SHF_LSR_REG:
150
	case ARM_SHF_LSR_IMM: return "lsr";
151
	case ARM_SHF_ROR_REG:
152
	case ARM_SHF_ROR_IMM: return "ror";
153
154
155
156
157
158
	default:
		break;
	}
	panic("can't emit this shf_mod_name %d", (int) mod);
}

Matthias Braun's avatar
Matthias Braun committed
159
static void arm_emit_shifter_operand(const ir_node *node)
160
{
161
	const arm_shifter_operand_t *attr = get_arm_shifter_operand_attr_const(node);
162
163
164

	switch (attr->shift_modifier) {
	case ARM_SHF_REG:
165
		arm_emit_source_register(node, attr->shifter_op_input);
166
167
168
169
		return;
	case ARM_SHF_IMM: {
		unsigned val = attr->immediate_value;
		val = (val >> attr->shift_immediate)
Matthias Braun's avatar
Matthias Braun committed
170
			| (val << ((32-attr->shift_immediate) & 31));
171
172
173
174
175
176
177
		val &= 0xFFFFFFFF;
		be_emit_irprintf("#0x%X", val);
		return;
	}
	case ARM_SHF_ASR_IMM:
	case ARM_SHF_LSL_IMM:
	case ARM_SHF_LSR_IMM:
178
	case ARM_SHF_ROR_IMM: {
179
		arm_emit_source_register(node, attr->shifter_op_input);
180
		char const *const mod = get_shf_mod_name(attr->shift_modifier);
181
		be_emit_irprintf(", %s #%u", mod, attr->shift_immediate);
182
		return;
183
	}
184
185
186
187

	case ARM_SHF_ASR_REG:
	case ARM_SHF_LSL_REG:
	case ARM_SHF_LSR_REG:
188
	case ARM_SHF_ROR_REG: {
189
		arm_emit_source_register(node, attr->shifter_op_input);
190
191
		char const *const mod = get_shf_mod_name(attr->shift_modifier);
		be_emit_irprintf(", %s ", mod);
192
		arm_emit_source_register(node, attr->shifter_op_input+1);
193
		return;
194
	}
Michael Beck's avatar
Michael Beck committed
195

196
	case ARM_SHF_RRX:
197
		arm_emit_source_register(node, attr->shifter_op_input);
198
		panic("RRX shifter emitter TODO");
199

200
201
	case ARM_SHF_INVALID:
		break;
202
	}
203
	panic("invalid shift_modifier while emitting %+F", node);
204
205
}

Michael Beck's avatar
Michael Beck committed
206
207
/**
 * Returns a unique label. This number will not be used a second time.
208
 */
209
210
static unsigned get_unique_label(void)
{
Michael Beck's avatar
Michael Beck committed
211
212
	static unsigned id = 0;
	return ++id;
213
214
}

215
static void emit_constant_name(const ent_or_tv_t *entry)
216
217
218
219
{
	be_emit_irprintf("%sC%u", be_gas_get_private_prefix(), entry->label);
}

Matthias Braun's avatar
Matthias Braun committed
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
/**
 * Returns the target block for a control flow node.
 */
static ir_node *get_cfop_target_block(const ir_node *irn)
{
	return (ir_node*)get_irn_link(irn);
}

/**
 * Emit the target label for a control flow node.
 */
static void arm_emit_cfop_target(const ir_node *irn)
{
	ir_node *block = get_cfop_target_block(irn);
	be_gas_emit_block_name(block);
}

void arm_emitf(const ir_node *node, const char *format, ...)
{
	va_list ap;
	va_start(ap, format);
	be_emit_char('\t');
	for (;;) {
		const char *start = format;
244
		while (*format != '%' && *format != '\n'  && *format != '\0')
Matthias Braun's avatar
Matthias Braun committed
245
			++format;
246
247
		be_emit_string_len(start, format - start);

Matthias Braun's avatar
Matthias Braun committed
248
249
		if (*format == '\0')
			break;
250
251
252
253
254
255
256
257
258

		if (*format == '\n') {
			++format;
			be_emit_char('\n');
			be_emit_write_line();
			be_emit_char('\t');
			continue;
		}

Matthias Braun's avatar
Matthias Braun committed
259
260
261
262
263
264
265
266
		++format;

		switch (*format++) {
		case '%':
			be_emit_char('%');
			break;

		case 'S': {
267
			if (!is_digit(*format))
Matthias Braun's avatar
Matthias Braun committed
268
269
270
271
272
273
274
				goto unknown;
			unsigned const pos = *format++ - '0';
			arm_emit_source_register(node, pos);
			break;
		}

		case 'D': {
275
			if (!is_digit(*format))
Matthias Braun's avatar
Matthias Braun committed
276
277
278
279
280
281
282
				goto unknown;
			unsigned const pos = *format++ - '0';
			arm_emit_dest_register(node, pos);
			break;
		}

		case 'I':
283
			arm_emit_address(node);
Matthias Braun's avatar
Matthias Braun committed
284
285
286
287
288
289
290
291
292
293
294
			break;

		case 'o':
			arm_emit_offset(node);
			break;

		case 'O':
			arm_emit_shifter_operand(node);
			break;

		case 'C': {
295
			const ent_or_tv_t *name = va_arg(ap, const ent_or_tv_t*);
Matthias Braun's avatar
Matthias Braun committed
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
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
			emit_constant_name(name);
			break;
		}

		case 'm': {
			ir_mode *mode = va_arg(ap, ir_mode*);
			arm_emit_fpa_postfix(mode);
			break;
		}

		case 'M':
			switch (*format++) {
			case 'L': arm_emit_load_mode(node);             break;
			case 'S': arm_emit_store_mode(node);            break;
			case 'A': arm_emit_float_arithmetic_mode(node); break;
			case 'F': arm_emit_float_load_store_mode(node); break;
			default:
				--format;
				goto unknown;
			}
			break;

		case 'X': {
			int num = va_arg(ap, int);
			be_emit_irprintf("%X", num);
			break;
		}

		case 'u': {
			unsigned num = va_arg(ap, unsigned);
			be_emit_irprintf("%u", num);
			break;
		}

		case 'd': {
			int num = va_arg(ap, int);
			be_emit_irprintf("%d", num);
			break;
		}

		case 's': {
			const char *string = va_arg(ap, const char *);
			be_emit_string(string);
			break;
		}

		case 'r': {
			arch_register_t *reg = va_arg(ap, arch_register_t*);
			arm_emit_register(reg);
			break;
		}

		case 't': {
			const ir_node *n = va_arg(ap, const ir_node*);
			arm_emit_cfop_target(n);
			break;
		}

		default:
unknown:
356
			panic("unknown format conversion");
Matthias Braun's avatar
Matthias Braun committed
357
358
359
360
361
362
		}
	}
	va_end(ap);
	be_emit_finish_line_gas(node);
}

363
364
365
366
367
368
369
370
static ent_or_tv_t *get_ent_or_tv_entry(const ent_or_tv_t *key)
{
	ent_or_tv_t *entry = pmap_get(ent_or_tv_t, ent_or_tv, key->u.generic);
	if (entry == NULL) {
		entry = OALLOC(&obst, ent_or_tv_t);
		*entry = *key;
		entry->label = get_unique_label();
		entry->next  = NULL;
371
372
		*ent_or_tv_anchor = entry;
		ent_or_tv_anchor  = &entry->next;
373
374
375
376
377
		pmap_insert(ent_or_tv, key->u.generic, entry);
	}
	return entry;
}

Michael Beck's avatar
Michael Beck committed
378
/**
379
 * Emit an Address.
Michael Beck's avatar
Michael Beck committed
380
 */
381
static void emit_arm_Address(const ir_node *irn)
382
{
383
	const arm_Address_attr_t *attr = get_arm_Address_attr_const(irn);
384
	ent_or_tv_t key;
385
386
387
	key.u.entity  = attr->entity;
	key.is_entity = true;
	key.label     = 0;
388
	ent_or_tv_t *entry = get_ent_or_tv_entry(&key);
Michael Beck's avatar
Michael Beck committed
389

Michael Beck's avatar
Michael Beck committed
390
	/* load the symbol indirect */
Matthias Braun's avatar
Matthias Braun committed
391
	arm_emitf(irn, "ldr %D0, %C", entry);
392
393
}

394
395
static void emit_arm_FrameAddr(const ir_node *irn)
{
396
	const arm_Address_attr_t *attr = get_arm_Address_attr_const(irn);
Matthias Braun's avatar
Matthias Braun committed
397
	arm_emitf(irn, "add %D0, %S0, #0x%X", attr->fp_offset);
398
399
}

Michael Beck's avatar
Michael Beck committed
400
401
402
/**
 * Emit a floating point fpa constant.
 */
403
static void emit_arm_fConst(const ir_node *irn)
404
{
405
406
407
408
409
	ir_tarval *const tv = get_fConst_value(irn);
	ent_or_tv_t key = {
		.u.tv      = tv,
		.is_entity = false
	};
410
	ent_or_tv_t *entry = get_ent_or_tv_entry(&key);
Michael Beck's avatar
Michael Beck committed
411
412

	/* load the tarval indirect */
413
	ir_mode *const mode = get_tarval_mode(tv);
Matthias Braun's avatar
Matthias Braun committed
414
	arm_emitf(irn, "ldf%m %D0, %C", mode, entry);
Michael Beck's avatar
Michael Beck committed
415
416
}

Michael Beck's avatar
Michael Beck committed
417
418
419
/**
 * Returns the next block in a block schedule.
 */
420
421
static ir_node *sched_next_block(const ir_node *block)
{
422
    return (ir_node*)get_irn_link(block);
Michael Beck's avatar
Michael Beck committed
423
424
425
}

/**
Michael Beck's avatar
Michael Beck committed
426
 * Emit a Compare with conditional branch.
Michael Beck's avatar
Michael Beck committed
427
 */
428
429
static void emit_arm_B(const ir_node *irn)
{
Matthias Braun's avatar
Matthias Braun committed
430
431
	const ir_node *proj_true  = NULL;
	const ir_node *proj_false = NULL;
Michael Beck's avatar
Michael Beck committed
432
433
	foreach_out_edge(irn, edge) {
		ir_node *proj = get_edge_src_irn(edge);
434
		unsigned nr   = get_Proj_num(proj);
Michael Beck's avatar
Michael Beck committed
435
		if (nr == pn_Cond_true) {
436
			proj_true = proj;
437
		} else {
438
			proj_false = proj;
439
		}
Michael Beck's avatar
Michael Beck committed
440
	}
441

442
	ir_node *const op1 = get_irn_n(irn, n_arm_B_flags);
443
	assert(is_arm_Cmn(op1) || is_arm_Cmp(op1) || is_arm_Tst(op1));
Christoph Mallon's avatar
Christoph Mallon committed
444
445
446
447
448

	arm_cmp_attr_t const *const cmp_attr = get_arm_cmp_attr_const(op1);

	ir_relation relation = get_arm_CondJmp_relation(irn);
	if (cmp_attr->ins_permuted)
449
		relation = get_inversed_relation(relation);
450
451

	/* for now, the code works for scheduled and non-schedules blocks */
Matthias Braun's avatar
Matthias Braun committed
452
453
	const ir_node *block      = get_nodes_block(irn);
	const ir_node *next_block = sched_next_block(block);
454

455
456
	assert(relation != ir_relation_false);
	assert(relation != ir_relation_true);
457
458
459
460
461
462
463

	if (get_cfop_target_block(proj_true) == next_block) {
		/* exchange both proj's so the second one can be omitted */
		const ir_node *t = proj_true;

		proj_true  = proj_false;
		proj_false = t;
464
		relation   = get_negated_relation(relation);
465
	}
466

Christoph Mallon's avatar
Christoph Mallon committed
467
468
	char const *suffix;
	bool const  is_signed = !cmp_attr->is_unsigned;
469
470
471
472
473
474
475
476
477
	switch (relation & (ir_relation_less_equal_greater)) {
		case ir_relation_equal:         suffix = "eq"; break;
		case ir_relation_less:          suffix = is_signed ? "lt" : "lo"; break;
		case ir_relation_less_equal:    suffix = is_signed ? "le" : "ls"; break;
		case ir_relation_greater:       suffix = is_signed ? "gt" : "hi"; break;
		case ir_relation_greater_equal: suffix = is_signed ? "ge" : "hs"; break;
		case ir_relation_less_greater:  suffix = "ne"; break;
		case ir_relation_less_equal_greater: suffix = "al"; break;
		default: panic("Cmp has unsupported relation");
478
479
480
	}

	/* emit the true proj */
Matthias Braun's avatar
Matthias Braun committed
481
	arm_emitf(irn, "b%s %t", suffix, proj_true);
482
483

	if (get_cfop_target_block(proj_false) == next_block) {
484
		if (be_options.verbose_asm) {
Matthias Braun's avatar
Matthias Braun committed
485
			arm_emitf(irn, "/* fallthrough to %t */", proj_false);
486
		}
487
	} else {
Matthias Braun's avatar
Matthias Braun committed
488
		arm_emitf(irn, "b %t", proj_false);
489
490
491
	}
}

492
493
494
495
496
497
498
static void emit_jumptable_target(ir_entity const *const table,
                                  ir_node const *const proj_x)
{
	(void)table;
	arm_emit_cfop_target(proj_x);
}

499
500
static void emit_arm_SwitchJmp(const ir_node *irn)
{
Matthias Braun's avatar
Matthias Braun committed
501
	const arm_SwitchJmp_attr_t *attr = get_arm_SwitchJmp_attr_const(irn);
Matthias Braun's avatar
Matthias Braun committed
502
	arm_emitf(irn, "ldrls pc, [pc, %S0, asl #2]");
503

504
	be_emit_jump_table(irn, attr->table, NULL, emit_jumptable_target);
505
506
}

Michael Beck's avatar
Michael Beck committed
507
/** Emit an IncSP node */
508
509
static void emit_be_IncSP(const ir_node *irn)
{
510
	int offs = -be_get_IncSP_offset(irn);
Matthias Braun's avatar
Matthias Braun committed
511
	if (offs == 0)
512
		return;
Matthias Braun's avatar
Matthias Braun committed
513
514
515
516
517

	const char *op = "add";
	if (offs < 0) {
		op   = "sub";
		offs = -offs;
518
	}
Matthias Braun's avatar
Matthias Braun committed
519
	arm_emitf(irn, "%s %D0, %S0, #0x%X", op, offs);
520
521
}

522
523
static void emit_be_Copy(const ir_node *irn)
{
524
525
	arch_register_t const *const out = arch_get_irn_register_out(irn, 0);
	if (arch_get_irn_register_in(irn, 0) == out) {
526
		/* omitted Copy */
527
528
529
		return;
	}

530
531
	arch_register_class_t const *const cls = out->cls;
	if (cls == &arm_reg_classes[CLASS_arm_gp]) {
Matthias Braun's avatar
Matthias Braun committed
532
		arm_emitf(irn, "mov %D0, %S0");
533
534
	} else if (cls == &arm_reg_classes[CLASS_arm_fpa]) {
		arm_emitf(irn, "mvf %D0, %S0");
535
	} else {
536
		panic("move not supported for this register class");
537
538
539
	}
}

540
541
static void emit_be_Perm(const ir_node *irn)
{
Matthias Braun's avatar
Matthias Braun committed
542
	arm_emitf(irn,
543
544
545
		"eor %D0, %D0, %D1\n"
		"eor %D1, %D0, %D1\n"
		"eor %D0, %D0, %D1");
Michael Beck's avatar
Michael Beck committed
546
547
}

548
549
550
551
552
static void emit_be_MemPerm(const ir_node *node)
{
	/* TODO: this implementation is slower than necessary.
	   The longterm goal is however to avoid the memperm node completely */

Matthias Braun's avatar
Matthias Braun committed
553
	int memperm_arity = be_get_MemPerm_entity_arity(node);
554
555
556
	if (memperm_arity > 12)
		panic("memperm with more than 12 inputs not supported yet");

Matthias Braun's avatar
Matthias Braun committed
557
558
	int sp_change = 0;
	for (int i = 0; i < memperm_arity; ++i) {
559
		/* spill register */
Matthias Braun's avatar
Matthias Braun committed
560
		arm_emitf(node, "str r%d, [sp, #-4]!", i);
561
562
		sp_change += 4;
		/* load from entity */
Matthias Braun's avatar
Matthias Braun committed
563
564
565
		ir_entity *entity = be_get_MemPerm_in_entity(node, i);
		int        offset = get_entity_offset(entity) + sp_change;
		arm_emitf(node, "ldr r%d, [sp, #%d]", i, offset);
566
567
	}

Matthias Braun's avatar
Matthias Braun committed
568
	for (int i = memperm_arity; i-- > 0; ) {
569
		/* store to new entity */
Matthias Braun's avatar
Matthias Braun committed
570
571
572
		ir_entity *entity = be_get_MemPerm_out_entity(node, i);
		int        offset = get_entity_offset(entity) + sp_change;
		arm_emitf(node, "str r%d, [sp, #%d]", i, offset);
573
		/* restore register */
Matthias Braun's avatar
Matthias Braun committed
574
		arm_emitf(node, "ldr r%d, [sp], #4", i);
575
576
577
578
579
580
581
		sp_change -= 4;
	}
	assert(sp_change == 0);
}

static void emit_arm_Jmp(const ir_node *node)
{
582
	/* for now, the code works for scheduled and non-schedules blocks */
Matthias Braun's avatar
Matthias Braun committed
583
584
	const ir_node *block      = get_nodes_block(node);
	const ir_node *next_block = sched_next_block(block);
585
	if (get_cfop_target_block(node) != next_block) {
Matthias Braun's avatar
Matthias Braun committed
586
		arm_emitf(node, "b %t", node);
587
	} else {
588
		if (be_options.verbose_asm) {
Matthias Braun's avatar
Matthias Braun committed
589
			arm_emitf(node, "/* fallthrough to %t */", node);
590
		}
Michael Beck's avatar
Michael Beck committed
591
	}
592
593
594
595
596
597
}

/**
 * Enters the emitter functions for handled nodes into the generic
 * pointer of an opcode.
 */
598
599
static void arm_register_emitters(void)
{
600
	be_init_emitters();
601
602
603
604

	/* register all emitter functions defined in spec */
	arm_register_spec_emitters();

605
	/* custom emitter */
606
	be_set_emitter(op_arm_Address,   emit_arm_Address);
607
	be_set_emitter(op_arm_B,         emit_arm_B);
608
	be_set_emitter(op_arm_fConst,    emit_arm_fConst);
609
610
611
612
613
614
615
616
	be_set_emitter(op_arm_FrameAddr, emit_arm_FrameAddr);
	be_set_emitter(op_arm_Jmp,       emit_arm_Jmp);
	be_set_emitter(op_arm_SwitchJmp, emit_arm_SwitchJmp);
	be_set_emitter(op_be_Copy,       emit_be_Copy);
	be_set_emitter(op_be_CopyKeep,   emit_be_Copy);
	be_set_emitter(op_be_IncSP,      emit_be_IncSP);
	be_set_emitter(op_be_MemPerm,    emit_be_MemPerm);
	be_set_emitter(op_be_Perm,       emit_be_Perm);
617
618
}

619
620
621
/**
 * emit the block label if needed.
 */
622
static void arm_emit_block_header(ir_node *block, ir_node *prev)
623
{
Matthias Braun's avatar
Matthias Braun committed
624
625
	int  n_cfgpreds = get_Block_n_cfgpreds(block);
	bool need_label;
626
	if (n_cfgpreds == 1) {
Matthias Braun's avatar
Matthias Braun committed
627
628
		const ir_node *pred       = get_Block_cfgpred(block, 0);
		const ir_node *pred_block = get_nodes_block(pred);
629
630
631

		/* we don't need labels for fallthrough blocks, however switch-jmps
		 * are no fallthroughs */
632
633
634
		need_label =
			pred_block != prev ||
			(is_Proj(pred) && is_arm_SwitchJmp(get_Proj_pred(pred)));
635
	} else {
636
		need_label = true;
637
638
	}

639
	be_gas_begin_block(block, need_label);
640
641
}

642
643
644
645
/**
 * Walks over the nodes in a block connected by scheduling edges
 * and emits code for each node.
 */
646
647
static void arm_gen_block(ir_node *block, ir_node *prev_block)
{
648
	arm_emit_block_header(block, prev_block);
649
	be_dwarf_location(get_irn_dbg_info(block));
650
	sched_foreach(block, irn) {
651
		be_emit_node(irn);
652
653
654
655
	}
}

/**
656
 * Block-walker:
657
658
 * Sets labels for control flow nodes (jump target)
 */
659
660
static void arm_gen_labels(ir_node *block, void *env)
{
661
	(void)env;
Matthias Braun's avatar
Matthias Braun committed
662
663
	for (int n = get_Block_n_cfgpreds(block); n-- > 0; ) {
		ir_node *pred = get_Block_cfgpred(block, n);
664
665
666
667
		set_irn_link(pred, block);
	}
}

668
669
670
671
672
static parameter_dbg_info_t *construct_parameter_infos(ir_graph *irg)
{
	ir_entity            *entity   = get_irg_entity(irg);
	ir_type              *type     = get_entity_type(entity);
	calling_convention_t *cconv    = arm_decide_calling_convention(NULL, type);
673
	size_t                n_params = cconv->n_parameters;
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
	parameter_dbg_info_t *infos    = XMALLOCNZ(parameter_dbg_info_t, n_params);

	for (size_t i = 0; i < n_params; ++i) {
		const reg_or_stackslot_t *slot = &cconv->parameters[i];

		assert(infos[i].entity == NULL && infos[i].reg == NULL);
		if (slot->reg0 != NULL) {
			infos[i].reg = slot->reg0;
		} else {
			infos[i].entity = slot->entity;
		}
	}
	arm_free_calling_convention(cconv);

	return infos;
}

691
void arm_emit_function(ir_graph *irg)
692
{
693
694
	ent_or_tv = pmap_create();
	obstack_init(&obst);
695
696
	ent_or_tv_first  = NULL;
	ent_or_tv_anchor = &ent_or_tv_first;
697
698
699

	arm_register_emitters();

700
	/* create the block schedule */
Matthias Braun's avatar
Matthias Braun committed
701
	ir_node **blk_sched = be_create_block_schedule(irg);
Michael Beck's avatar
Michael Beck committed
702

Christoph Mallon's avatar
Christoph Mallon committed
703
704
	ir_entity            *const entity = get_irg_entity(irg);
	parameter_dbg_info_t *const infos  = construct_parameter_infos(irg);
705
	be_gas_emit_function_prolog(entity, 4, infos);
706

707
	ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
708
	irg_block_walk_graph(irg, arm_gen_labels, NULL, NULL);
Michael Beck's avatar
Michael Beck committed
709

Christoph Mallon's avatar
Christoph Mallon committed
710
711
	ir_node *last_block = NULL;
	for (size_t i = 0, n = ARR_LEN(blk_sched); i < n;) {
Matthias Braun's avatar
Matthias Braun committed
712
713
		ir_node *block   = blk_sched[i++];
		ir_node *next_bl = i < n ? blk_sched[i] : NULL;
Michael Beck's avatar
Michael Beck committed
714
715
716

		/* set here the link. the emitter expects to find the next block here */
		set_irn_link(block, next_bl);
717
		arm_gen_block(block, last_block);
718
		last_block = block;
Michael Beck's avatar
Michael Beck committed
719
	}
720
	ir_free_resources(irg, IR_RESOURCE_IRN_LINK);
Michael Beck's avatar
Michael Beck committed
721

722
	/* emit entity and tarval values */
723
	if (ent_or_tv_first != NULL) {
724
		be_emit_cstring("\t.align 2\n");
Michael Beck's avatar
Michael Beck committed
725

Christoph Mallon's avatar
Christoph Mallon committed
726
		for (ent_or_tv_t *entry = ent_or_tv_first; entry; entry = entry->next) {
727
728
729
			emit_constant_name(entry);
			be_emit_cstring(":\n");
			be_emit_write_line();
Michael Beck's avatar
Michael Beck committed
730

731
			if (entry->is_entity) {
732
				be_emit_cstring("\t.word\t");
733
				be_gas_emit_entity(entry->u.entity);
734
735
				be_emit_char('\n');
				be_emit_write_line();
Michael Beck's avatar
Michael Beck committed
736
			} else {
Matthias Braun's avatar
Matthias Braun committed
737
738
				ir_tarval *tv   = entry->u.tv;
				unsigned   size = get_mode_size_bytes(get_tarval_mode(tv));
Michael Beck's avatar
Michael Beck committed
739

740
				/* beware: ARM fpa uses big endian format */
Christoph Mallon's avatar
Christoph Mallon committed
741
				for (unsigned vi = round_up2(size, 4); vi != 0;) {
Michael Beck's avatar
Michael Beck committed
742
					/* get 32 bits */
Christoph Mallon's avatar
Christoph Mallon committed
743
744
745
746
747
					uint32_t v;
					v  = get_tarval_sub_bits(tv, --vi) << 24;
					v |= get_tarval_sub_bits(tv, --vi) << 16;
					v |= get_tarval_sub_bits(tv, --vi) <<  8;
					v |= get_tarval_sub_bits(tv, --vi) <<  0;
Matthias Braun's avatar
Matthias Braun committed
748
					be_emit_irprintf("\t.word\t%" PRIu32 "\n", v);
749
					be_emit_write_line();
Michael Beck's avatar
Michael Beck committed
750
751
				}
			}
Michael Beck's avatar
Michael Beck committed
752
		}
753
754
		be_emit_char('\n');
		be_emit_write_line();
Michael Beck's avatar
Michael Beck committed
755
	}
756
757
	pmap_destroy(ent_or_tv);
	obstack_free(&obst, NULL);
758
759

	be_gas_emit_function_epilog(entity);
760
761
}

762
static const char *get_variant_string(arm_variant_t variant)
763
{
764
	switch (variant) {
765
766
767
768
769
	case ARM_VARIANT_4:   return "armv4";
	case ARM_VARIANT_5T:  return "armv5t";
	case ARM_VARIANT_6:   return "armv6";
	case ARM_VARIANT_6T2: return "armv6t2";
	case ARM_VARIANT_7:   return "armv7";
770
	}
771
772
773
774
775
776
	panic("invalid arm variant");
}

void arm_emit_file_prologue(void)
{
	be_emit_irprintf("\t.arch %s\n", get_variant_string(arm_cg_config.variant));
777
778
779
780
781
	be_emit_write_line();
	be_emit_cstring("\t.fpu softvfp\n");
	be_emit_write_line();
}

782
783
784
void arm_init_emitter(void)
{
	FIRM_DBG_REGISTER(dbg, "firm.be.arm.emit");
785
}