arm_emitter.c 19.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   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
#include "beemithlp.h"
#include "beemitter.h"
22
23
24
#include "begnuas.h"
#include "benode.h"
#include "besched.h"
25
#include "debug.h"
26
27
#include "gen_arm_emitter.h"
#include "gen_arm_regalloc_if.h"
28
#include "iredges_t.h"
29
#include "irgwalk.h"
Matthias Braun's avatar
Matthias Braun committed
30
#include "panic.h"
31
32
#include "pmap.h"
#include "util.h"
33

34
35
36
37
38
39
40
41
42
43
44
45
46
/** 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. */
};

47
48
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

49
50
51
static struct obstack obst;
static pmap          *ent_or_tv;
static ent_or_tv_t   *ent_or_tv_first;
52
static ent_or_tv_t  **ent_or_tv_anchor;
53

54
55
static void arm_emit_register(const arch_register_t *reg)
{
56
	be_emit_string(reg->name);
57
58
}

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

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

Matthias Braun's avatar
Matthias Braun committed
71
static void arm_emit_offset(const ir_node *node)
72
73
74
{
	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
75

76
	be_emit_irprintf("0x%X", attr->offset);
77
78
79
}

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

Michael Beck's avatar
Michael Beck committed
87
	if (bits == 32)
Michael Beck's avatar
Michael Beck committed
88
		c = 's';
Michael Beck's avatar
Michael Beck committed
89
	else if (bits == 64)
Michael Beck's avatar
Michael Beck committed
90
91
		c = 'd';
	be_emit_char(c);
92
93
}

Matthias Braun's avatar
Matthias Braun committed
94
static void arm_emit_float_load_store_mode(const ir_node *node)
95
{
96
97
98
	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
99

Matthias Braun's avatar
Matthias Braun committed
100
static void arm_emit_float_arithmetic_mode(const ir_node *node)
101
102
103
{
	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
104
105
}

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

	be_gas_emit_entity(entity);

	/* TODO do something with offset */
}

Matthias Braun's avatar
Matthias Braun committed
116
static void arm_emit_load_mode(const ir_node *node)
117
118
119
120
121
122
123
124
125
126
127
128
129
130
{
	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
131
static void arm_emit_store_mode(const ir_node *node)
132
133
134
135
136
137
138
139
140
141
142
143
144
{
	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);
	}
}

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

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

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

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

199
	case ARM_SHF_RRX:
200
		arm_emit_source_register(node, attr->shifter_op_input);
201
		panic("RRX shifter emitter TODO");
202

203
204
	case ARM_SHF_INVALID:
		break;
205
	}
206
	panic("invalid shift_modifier while emitting %+F", node);
207
208
}

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

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

Matthias Braun's avatar
Matthias Braun committed
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
/**
 * 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;
247
		while (*format != '%' && *format != '\n'  && *format != '\0')
Matthias Braun's avatar
Matthias Braun committed
248
			++format;
249
250
		be_emit_string_len(start, format - start);

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

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

Matthias Braun's avatar
Matthias Braun committed
262
263
264
265
266
267
268
269
		++format;

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

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

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

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

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

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

		case 'C': {
298
			const ent_or_tv_t *name = va_arg(ap, const ent_or_tv_t*);
Matthias Braun's avatar
Matthias Braun committed
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
356
357
358
			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:
359
			panic("unknown format conversion");
Matthias Braun's avatar
Matthias Braun committed
360
361
362
363
364
365
		}
	}
	va_end(ap);
	be_emit_finish_line_gas(node);
}

366
367
368
369
370
371
372
373
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;
374
375
		*ent_or_tv_anchor = entry;
		ent_or_tv_anchor  = &entry->next;
376
377
378
379
380
		pmap_insert(ent_or_tv, key->u.generic, entry);
	}
	return entry;
}

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

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

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

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

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

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

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

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

	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)
452
		relation = get_inversed_relation(relation);
453
454

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

458
459
	assert(relation != ir_relation_false);
	assert(relation != ir_relation_true);
460
461
462
463
464
465
466

	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;
467
		relation   = get_negated_relation(relation);
468
	}
469

Christoph Mallon's avatar
Christoph Mallon committed
470
471
	char const *suffix;
	bool const  is_signed = !cmp_attr->is_unsigned;
472
473
474
475
476
477
478
479
480
	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");
481
482
483
	}

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

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

495
496
497
498
499
500
501
static void emit_jumptable_target(ir_entity const *const table,
                                  ir_node const *const proj_x)
{
	(void)table;
	arm_emit_cfop_target(proj_x);
}

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

507
	be_emit_jump_table(irn, attr->table, NULL, mode_P, emit_jumptable_target);
508
509
}

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

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

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

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

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

551
552
553
554
555
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
556
	int memperm_arity = be_get_MemPerm_entity_arity(node);
557
558
559
	if (memperm_arity > 12)
		panic("memperm with more than 12 inputs not supported yet");

Matthias Braun's avatar
Matthias Braun committed
560
561
	int sp_change = 0;
	for (int i = 0; i < memperm_arity; ++i) {
562
		/* spill register */
Matthias Braun's avatar
Matthias Braun committed
563
		arm_emitf(node, "str r%d, [sp, #-4]!", i);
564
565
		sp_change += 4;
		/* load from entity */
Matthias Braun's avatar
Matthias Braun committed
566
567
568
		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);
569
570
	}

Matthias Braun's avatar
Matthias Braun committed
571
	for (int i = memperm_arity; i-- > 0; ) {
572
		/* store to new entity */
Matthias Braun's avatar
Matthias Braun committed
573
574
575
		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);
576
		/* restore register */
Matthias Braun's avatar
Matthias Braun committed
577
		arm_emitf(node, "ldr r%d, [sp], #4", i);
578
579
580
581
582
583
584
		sp_change -= 4;
	}
	assert(sp_change == 0);
}

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

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

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

608
	/* custom emitter */
609
	be_set_emitter(op_arm_Address,   emit_arm_Address);
610
	be_set_emitter(op_arm_B,         emit_arm_B);
611
	be_set_emitter(op_arm_fConst,    emit_arm_fConst);
612
613
614
615
616
617
618
619
	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);
620
621
}

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

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

642
	be_gas_begin_block(block, need_label);
643
644
}

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

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

671
672
673
674
675
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);
676
	size_t                n_params = cconv->n_parameters;
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
	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;
}

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

	arm_register_emitters();

703
	/* create the block schedule */
Matthias Braun's avatar
Matthias Braun committed
704
	ir_node **blk_sched = be_create_block_schedule(irg);
Michael Beck's avatar
Michael Beck committed
705

Christoph Mallon's avatar
Christoph Mallon committed
706
707
	ir_entity            *const entity = get_irg_entity(irg);
	parameter_dbg_info_t *const infos  = construct_parameter_infos(irg);
708
	be_gas_emit_function_prolog(entity, 4, infos);
709

710
	ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
711
	irg_block_walk_graph(irg, arm_gen_labels, NULL, NULL);
Michael Beck's avatar
Michael Beck committed
712

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

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

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

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

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

743
				/* beware: ARM fpa uses big endian format */
Christoph Mallon's avatar
Christoph Mallon committed
744
				for (unsigned vi = round_up2(size, 4); vi != 0;) {
Michael Beck's avatar
Michael Beck committed
745
					/* get 32 bits */
Christoph Mallon's avatar
Christoph Mallon committed
746
747
748
749
750
					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
751
					be_emit_irprintf("\t.word\t%" PRIu32 "\n", v);
752
					be_emit_write_line();
Michael Beck's avatar
Michael Beck committed
753
754
				}
			}
Michael Beck's avatar
Michael Beck committed
755
		}
756
757
		be_emit_char('\n');
		be_emit_write_line();
Michael Beck's avatar
Michael Beck committed
758
	}
759
760
	pmap_destroy(ent_or_tv);
	obstack_free(&obst, NULL);
761
762

	be_gas_emit_function_epilog(entity);
763
764
}

765
static const char *get_variant_string(arm_variant_t variant)
766
{
767
	switch (variant) {
768
769
770
771
772
	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";
773
	}
774
775
776
777
778
779
	panic("invalid arm variant");
}

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

785
786
787
void arm_init_emitter(void)
{
	FIRM_DBG_REGISTER(dbg, "firm.be.arm.emit");
788
}