arm_emitter.c 31.9 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
/*
Michael Beck's avatar
Michael Beck committed
2
 * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
Christian Würdig's avatar
Christian Würdig committed
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 *
 * This file is part of libFirm.
 *
 * This file may be distributed and/or modified under the terms of the
 * GNU General Public License version 2 as published by the Free Software
 * Foundation and appearing in the file LICENSE.GPL included in the
 * packaging of this file.
 *
 * Licensees holding valid libFirm Professional Edition licenses may use
 * this file in accordance with the libFirm Commercial License.
 * Agreement provided with the Software.
 *
 * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
 * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE.
 */

20
21
22
/**
 * @file
 * @brief   arm emitter
23
 * @author  Oliver Richter, Tobias Gneist, Michael Beck
24
25
 * @version $Id$
 */
26
#define SILENCER
27
28
29
30
31
32
33
34
35
36

#include "config.h"

#include <limits.h>

#include "xmalloc.h"
#include "tv.h"
#include "iredges.h"
#include "debug.h"
#include "irgwalk.h"
Michael Beck's avatar
Michael Beck committed
37
#include "irtools.h"
38
39
40
41
#include "irprintf.h"
#include "irop_t.h"
#include "irprog_t.h"
#include "irargs_t.h"
Michael Beck's avatar
Michael Beck committed
42
#include "error.h"
Michael Beck's avatar
Michael Beck committed
43
#include "raw_bitset.h"
44
#include "dbginfo.h"
45
46

#include "../besched.h"
47
#include "../beblocksched.h"
48
#include "../beirg.h"
Michael Beck's avatar
Michael Beck committed
49
#include "../begnuas.h"
50
#include "../be_dbgout.h"
51
52

#include "arm_emitter.h"
53
#include "arm_optimize.h"
54
55
56
57
58
59
#include "gen_arm_emitter.h"
#include "arm_nodes_attr.h"
#include "arm_new_nodes.h"
#include "arm_map_regs.h"
#include "gen_arm_regalloc_if.h"

60
#include "../benode.h"
61

62
63
#define BLOCK_PREFIX ".L"

64
65
#define SNPRINTF_BUF_LEN 128

66
67
68
69
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

static const arm_code_gen_t *cg;
static set                  *sym_or_tv;
70

Michael Beck's avatar
Michael Beck committed
71
/**
Michael Beck's avatar
Michael Beck committed
72
 * Returns the register at in position pos.
Michael Beck's avatar
Michael Beck committed
73
 */
74
static const arch_register_t *get_in_reg(const ir_node *irn, int pos) {
Michael Beck's avatar
Michael Beck committed
75
76
	ir_node                *op;
	const arch_register_t  *reg = NULL;
Michael Beck's avatar
Michael Beck committed
77

Michael Beck's avatar
Michael Beck committed
78
	assert(get_irn_arity(irn) > pos && "Invalid IN position");
Michael Beck's avatar
Michael Beck committed
79

Michael Beck's avatar
Michael Beck committed
80
81
82
	/* The out register of the operator at position pos is the
	   in register we need. */
	op = get_irn_n(irn, pos);
Michael Beck's avatar
Michael Beck committed
83

84
	reg = arch_get_irn_register(op);
Michael Beck's avatar
Michael Beck committed
85

Michael Beck's avatar
Michael Beck committed
86
	assert(reg && "no in register found");
Michael Beck's avatar
Michael Beck committed
87
88
89

	/* in case of a joker register: just return a valid register */
	if (arch_register_type_is(reg, joker)) {
90
		const arch_register_req_t *req = arch_get_register_req(irn, pos);
Michael Beck's avatar
Michael Beck committed
91
92
93
94
95
96
97
98
99
100

		if (arch_register_req_is(req, limited)) {
			/* in case of limited requirements: get the first allowed register */
			unsigned idx = rbitset_next(req->limited, 0, 1);
			reg = arch_register_for_index(req->cls, idx);
		} else {
			/* otherwise get first register in class */
			reg = arch_register_for_index(req->cls, 0);
		}
	}
Michael Beck's avatar
Michael Beck committed
101
102
	return reg;
}
Michael Beck's avatar
Michael Beck committed
103

Matthias Braun's avatar
Matthias Braun committed
104

Michael Beck's avatar
Michael Beck committed
105
106
107
/**
 * Returns the register at out position pos.
 */
108
static const arch_register_t *get_out_reg(const ir_node *node, int pos)
Michael Beck's avatar
Michael Beck committed
109
110
111
112
113
114
115
116
117
118
{
    ir_node                *proj;
    const arch_register_t  *reg = NULL;

    /* 1st case: irn is not of mode_T, so it has only                 */
    /*           one OUT register -> good                             */
    /* 2nd case: irn is of mode_T -> collect all Projs and ask the    */
    /*           Proj with the corresponding projnum for the register */

    if (get_irn_mode(node) != mode_T) {
119
        reg = arch_get_irn_register(node);
Michael Beck's avatar
Michael Beck committed
120
    } else if (is_arm_irn(node)) {
121
        reg = arch_irn_get_register(node, pos);
Michael Beck's avatar
Michael Beck committed
122
123
124
125
126
127
128
    } else {
        const ir_edge_t *edge;

        foreach_out_edge(node, edge) {
            proj = get_edge_src_irn(edge);
            assert(is_Proj(proj) && "non-Proj from mode_T node");
            if (get_Proj_proj(proj) == pos) {
129
                reg = arch_get_irn_register(proj);
Michael Beck's avatar
Michael Beck committed
130
131
132
133
134
135
136
                break;
            }
        }
    }

    assert(reg && "no out register found");
    return reg;
Michael Beck's avatar
Michael Beck committed
137
}
138
139
140
141
142
143
144
145
146
147
148
149
150

/*************************************************************
 *             _       _    __   _          _
 *            (_)     | |  / _| | |        | |
 *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
 * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
 * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
 * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
 * | |                                       | |
 * |_|                                       |_|
 *************************************************************/

/**
Michael Beck's avatar
Michael Beck committed
151
 * Emit the name of the source register at given input position.
152
 */
153
154
155
void arm_emit_source_register(const ir_node *node, int pos) {
	const arch_register_t *reg = get_in_reg(node, pos);
	be_emit_string(arch_register_get_name(reg));
Michael Beck's avatar
Michael Beck committed
156
}
157

Michael Beck's avatar
Michael Beck committed
158
159
160
/**
 * Emit the name of the destination register at given output position.
 */
161
162
163
void arm_emit_dest_register(const ir_node *node, int pos) {
	const arch_register_t *reg = get_out_reg(node, pos);
	be_emit_string(arch_register_get_name(reg));
164
165
166
}

/**
Michael Beck's avatar
Michael Beck committed
167
 * Emit a node's offset.
168
 */
169
void arm_emit_offset(const ir_node *node) {
170
	int offset = 0;
Michael Beck's avatar
Michael Beck committed
171
	ir_opcode opc = get_irn_opcode(node);
Michael Beck's avatar
Michael Beck committed
172

Michael Beck's avatar
Michael Beck committed
173
	if (opc == beo_Reload || opc == beo_Spill) {
Michael Beck's avatar
Michael Beck committed
174
		ir_entity *ent = be_get_frame_entity(node);
175
		offset = get_entity_offset(ent);
176
	} else {
Michael Beck's avatar
Michael Beck committed
177
178
		assert(!"unimplemented arm_emit_offset for this node type");
		panic("unimplemented arm_emit_offset for this node type");
179
	}
180
	be_emit_irprintf("%d", offset);
181
182
183
}

/**
Michael Beck's avatar
Michael Beck committed
184
 * Emit the arm fpa instruction suffix depending on the mode.
185
 */
186
static void arm_emit_fpa_postfix(const ir_mode *mode) {
Michael Beck's avatar
Michael Beck committed
187
	int bits = get_mode_size_bits(mode);
Michael Beck's avatar
Michael Beck committed
188
189
	char c = 'e';

Michael Beck's avatar
Michael Beck committed
190
	if (bits == 32)
Michael Beck's avatar
Michael Beck committed
191
		c = 's';
Michael Beck's avatar
Michael Beck committed
192
	else if (bits == 64)
Michael Beck's avatar
Michael Beck committed
193
194
		c = 'd';
	be_emit_char(c);
195
196
}

Michael Beck's avatar
Michael Beck committed
197
198
199
/**
 * Emit the instruction suffix depending on the mode.
 */
200
void arm_emit_mode(const ir_node *node) {
Michael Beck's avatar
Michael Beck committed
201
202
203
204
205
206
207
208
	ir_mode *mode;

	if (is_arm_irn(node)) {
		const arm_attr_t *attr = get_arm_attr_const(node);
		mode = attr->op_mode ? attr->op_mode : get_irn_mode(node);
	} else {
		mode = get_irn_mode(node);
	}
209
	arm_emit_fpa_postfix(mode);
Michael Beck's avatar
Michael Beck committed
210
211
}

212
/**
Michael Beck's avatar
Michael Beck committed
213
 * Emit a const or SymConst value.
214
 */
215
void arm_emit_immediate(const ir_node *node) {
216
217
218
	const arm_attr_t *attr = get_arm_attr_const(node);

	if (ARM_GET_SHF_MOD(attr) == ARM_SHF_IMM) {
Michael Beck's avatar
Michael Beck committed
219
		be_emit_irprintf("#0x%X", arm_decode_imm_w_shift(get_arm_imm_value(node)));
220
	} else if (ARM_GET_FPA_IMM(attr)) {
Michael Beck's avatar
Michael Beck committed
221
		be_emit_irprintf("#%s", arm_get_fpa_imm_name(get_arm_imm_value(node)));
Michael Beck's avatar
Michael Beck committed
222
	} else if (is_arm_SymConst(node))
223
		be_emit_ident(get_arm_symconst_id(node));
224
	else {
Michael Beck's avatar
Michael Beck committed
225
		assert(!"not a Constant");
226
227
228
229
	}
}

/**
Michael Beck's avatar
Michael Beck committed
230
231
 * Returns the tarval or offset of an arm node as a string.
 */
232
void arm_emit_shift(const ir_node *node) {
Michael Beck's avatar
Michael Beck committed
233
234
	arm_shift_modifier mod;

Michael Beck's avatar
Michael Beck committed
235
	mod = get_arm_shift_modifier(node);
Michael Beck's avatar
Michael Beck committed
236
	if (ARM_HAS_SHIFT(mod)) {
237
		int v = get_arm_imm_value(node);
238

239
		be_emit_irprintf(", %s #%d", arm_shf_mod_name(mod), v);
240
241
242
	}
}

Michael Beck's avatar
Michael Beck committed
243
/** An entry in the sym_or_tv set. */
244
typedef struct sym_or_tv_t {
Michael Beck's avatar
Michael Beck committed
245
246
247
248
249
250
251
	union {
		ident  *id;          /**< An ident. */
		tarval *tv;          /**< A tarval. */
		const void *generic; /**< For generic compare. */
	} u;
	unsigned label;      /**< the associated label. */
	char is_ident;       /**< Non-zero if an ident is stored. */
252
} sym_or_tv_t;
Michael Beck's avatar
Michael Beck committed
253

Michael Beck's avatar
Michael Beck committed
254
255
/**
 * Returns a unique label. This number will not be used a second time.
256
 */
Michael Beck's avatar
Michael Beck committed
257
258
259
static unsigned get_unique_label(void) {
	static unsigned id = 0;
	return ++id;
260
261
}

Michael Beck's avatar
Michael Beck committed
262
/**
Michael Beck's avatar
Michael Beck committed
263
 * Emit a SymConst.
Michael Beck's avatar
Michael Beck committed
264
 */
265
266
static void emit_arm_SymConst(const ir_node *irn) {
	sym_or_tv_t key, *entry;
Michael Beck's avatar
Michael Beck committed
267
268
	unsigned label;

Michael Beck's avatar
Michael Beck committed
269
270
271
	key.u.id     = get_arm_symconst_id(irn);
	key.is_ident = 1;
	key.label    = 0;
272
	entry = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
Michael Beck's avatar
Michael Beck committed
273
	if (entry->label == 0) {
Michael Beck's avatar
Michael Beck committed
274
		/* allocate a label */
Michael Beck's avatar
Michael Beck committed
275
		entry->label = get_unique_label();
Michael Beck's avatar
Michael Beck committed
276
	}
Michael Beck's avatar
Michael Beck committed
277
	label = entry->label;
Michael Beck's avatar
Michael Beck committed
278

Michael Beck's avatar
Michael Beck committed
279
	/* load the symbol indirect */
280
281
282
283
	be_emit_cstring("\tldr ");
	arm_emit_dest_register(irn, 0);
	be_emit_irprintf(", .L%u", label);
	be_emit_finish_line_gas(irn);
284
285
}

Michael Beck's avatar
Michael Beck committed
286
287
288
/**
 * Emit a floating point fpa constant.
 */
289
290
static void emit_arm_fpaConst(const ir_node *irn) {
	sym_or_tv_t key, *entry;
Michael Beck's avatar
Michael Beck committed
291
292
293
	unsigned label;
	ir_mode *mode;

Michael Beck's avatar
Michael Beck committed
294
	key.u.tv     = get_fpaConst_value(irn);
Michael Beck's avatar
Michael Beck committed
295
296
	key.is_ident = 0;
	key.label    = 0;
297
	entry = (sym_or_tv_t *)set_insert(sym_or_tv, &key, sizeof(key), HASH_PTR(key.u.generic));
Michael Beck's avatar
Michael Beck committed
298
299
300
301
302
303
304
305
	if (entry->label == 0) {
		/* allocate a label */
		entry->label = get_unique_label();
	}
	label = entry->label;

	/* load the tarval indirect */
	mode = get_irn_mode(irn);
306
307
308
	be_emit_cstring("\tldf");
	arm_emit_fpa_postfix(mode);
	be_emit_char(' ');
Michael Beck's avatar
Michael Beck committed
309

310
311
312
	arm_emit_dest_register(irn, 0);
	be_emit_irprintf(", .L%u", label);
	be_emit_finish_line_gas(irn);
Michael Beck's avatar
Michael Beck committed
313
314
}

Michael Beck's avatar
Michael Beck committed
315
316
317
/**
 * Returns the next block in a block schedule.
 */
318
static ir_node *sched_next_block(const ir_node *block) {
Michael Beck's avatar
Michael Beck committed
319
320
321
    return get_irn_link(block);
}

322
323
324
325
326
327
328
329
330
331
/**
 * Returns the target block for a control flow node.
 */
static ir_node *get_cfop_target_block(const ir_node *irn) {
	return get_irn_link(irn);
}

/**
 * Emits a block label for the given block.
 */
332
static void arm_emit_block_name(const ir_node *block) {
333
334
335
	if (has_Block_entity(block)) {
		ir_entity *entity = get_Block_entity(block);
		be_gas_emit_entity(entity);
Michael Beck's avatar
Michael Beck committed
336
	} else {
337
338
		be_emit_cstring(BLOCK_PREFIX);
		be_emit_irprintf("%d", get_irn_node_nr(block));
Michael Beck's avatar
Michael Beck committed
339
	}
340
341
342
343
344
}

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

348
	arm_emit_block_name(block);
349
350
}

Michael Beck's avatar
Michael Beck committed
351
/**
Michael Beck's avatar
Michael Beck committed
352
 * Emit a Compare with conditional branch.
Michael Beck's avatar
Michael Beck committed
353
 */
354
static void emit_arm_CmpBra(const ir_node *irn) {
355
	const ir_edge_t *edge;
356
357
358
359
	const ir_node *proj_true  = NULL;
	const ir_node *proj_false = NULL;
	const ir_node *block;
	const ir_node *next_block;
360
361
	ir_node *op1 = get_irn_n(irn, 0);
	ir_mode *opmode = get_irn_mode(op1);
Michael Beck's avatar
Michael Beck committed
362
	const char *suffix;
Michael Beck's avatar
Michael Beck committed
363
	int proj_num = get_arm_CondJmp_proj_num(irn);
364

Michael Beck's avatar
Michael Beck committed
365
366
367
	foreach_out_edge(irn, edge) {
		ir_node *proj = get_edge_src_irn(edge);
		long nr = get_Proj_proj(proj);
Michael Beck's avatar
Michael Beck committed
368
		if (nr == pn_Cond_true) {
369
			proj_true = proj;
370
		} else {
371
			proj_false = proj;
372
		}
Michael Beck's avatar
Michael Beck committed
373
	}
374

375
376
377
378
379
380
	/* for now, the code works for scheduled and non-schedules blocks */
	block = get_nodes_block(irn);

	/* we have a block schedule */
	next_block = sched_next_block(block);

381
	if (proj_num == pn_Cmp_False) {
Michael Beck's avatar
Michael Beck committed
382
		/* always false: should not happen */
383
384
385
		be_emit_cstring("\tb ");
		arm_emit_cfop_target(proj_false);
		be_emit_finish_line_gas(proj_false);
386
	} else if (proj_num == pn_Cmp_True) {
Michael Beck's avatar
Michael Beck committed
387
		/* always true: should not happen */
388
389
390
		be_emit_cstring("\tb ");
		arm_emit_cfop_target(proj_true);
		be_emit_finish_line_gas(proj_true);
391
392
393
394
	} else {
		if (mode_is_float(opmode)) {
			suffix = "ICHWILLIMPLEMENTIERTWERDEN";

395
396
397
398
399
			be_emit_cstring("\tfcmp ");
			arm_emit_source_register(irn, 0);
			be_emit_cstring(", ");
			arm_emit_source_register(irn, 1);
			be_emit_finish_line_gas(irn);
400

401
402
403
404
			be_emit_cstring("\tfmstat");
			be_emit_pad_comment();
			be_emit_cstring("/* FCSPR -> CPSR */");
			be_emit_finish_line_gas(NULL);
405
		} else {
406
407
408
409
410
411
412
			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;
				proj_num   = get_negated_pnc(proj_num, mode_Iu);
Michael Beck's avatar
Michael Beck committed
413
			}
Michael Beck's avatar
Michael Beck committed
414
			switch (proj_num) {
Michael Beck's avatar
Michael Beck committed
415
416
417
418
419
420
421
				case pn_Cmp_Eq:  suffix = "eq"; break;
				case pn_Cmp_Lt:  suffix = "lt"; break;
				case pn_Cmp_Le:  suffix = "le"; break;
				case pn_Cmp_Gt:  suffix = "gt"; break;
				case pn_Cmp_Ge:  suffix = "ge"; break;
				case pn_Cmp_Lg:  suffix = "ne"; break;
				case pn_Cmp_Leg: suffix = "al"; break;
Michael Beck's avatar
Michael Beck committed
422
				default: assert(!"Cmp unsupported"); suffix = "al";
423
			}
424
425
426
427
428
			be_emit_cstring("\tcmp ");
			arm_emit_source_register(irn, 0);
			be_emit_cstring(", ");
			arm_emit_source_register(irn, 1);
			be_emit_finish_line_gas(irn);
Michael Beck's avatar
Michael Beck committed
429
		}
430

431
		/* emit the true proj */
432
433
434
		be_emit_irprintf("\tb%s ", suffix);
		arm_emit_cfop_target(proj_true);
		be_emit_finish_line_gas(proj_true);
Michael Beck's avatar
Michael Beck committed
435

436
		if (get_cfop_target_block(proj_false) == next_block) {
437
438
439
440
			be_emit_cstring("\t/* fallthrough to ");
			arm_emit_cfop_target(proj_false);
			be_emit_cstring(" */");
			be_emit_finish_line_gas(proj_false);
Michael Beck's avatar
Michael Beck committed
441
		} else {
442
443
444
			be_emit_cstring("b ");
			arm_emit_cfop_target(proj_false);
			be_emit_finish_line_gas(proj_false);
445
446
447
448
		}
	}
}

449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522

/**
 * Emit a Tst with conditional branch.
 */
static void emit_arm_TstBra(const ir_node *irn)
{
	const ir_edge_t *edge;
	const ir_node *proj_true  = NULL;
	const ir_node *proj_false = NULL;
	const ir_node *block;
	const ir_node *next_block;
	const char *suffix;
	int proj_num = get_arm_CondJmp_proj_num(irn);

	foreach_out_edge(irn, edge) {
		ir_node *proj = get_edge_src_irn(edge);
		long nr = get_Proj_proj(proj);
		if (nr == pn_Cond_true) {
			proj_true = proj;
		} else {
			proj_false = proj;
		}
	}

	/* for now, the code works for scheduled and non-schedules blocks */
	block = get_nodes_block(irn);

	/* we have a block schedule */
	next_block = sched_next_block(block);

	assert(proj_num != pn_Cmp_False);
	assert(proj_num != pn_Cmp_True);

	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;
		proj_num   = get_negated_pnc(proj_num, mode_Iu);
	}
	switch (proj_num) {
		case pn_Cmp_Eq:  suffix = "eq"; break;
		case pn_Cmp_Lt:  suffix = "lt"; break;
		case pn_Cmp_Le:  suffix = "le"; break;
		case pn_Cmp_Gt:  suffix = "gt"; break;
		case pn_Cmp_Ge:  suffix = "ge"; break;
		case pn_Cmp_Lg:  suffix = "ne"; break;
		case pn_Cmp_Leg: suffix = "al"; break;
		default: assert(!"Cmp unsupported"); suffix = "al";
	}
	be_emit_cstring("\ttst ");
	arm_emit_source_register(irn, 0);
	be_emit_cstring(", ");
	arm_emit_source_register(irn, 1);
	be_emit_finish_line_gas(irn);

	/* emit the true proj */
	be_emit_irprintf("\tb%s ", suffix);
	arm_emit_cfop_target(proj_true);
	be_emit_finish_line_gas(proj_true);

	if (get_cfop_target_block(proj_false) == next_block) {
		be_emit_cstring("\t/* fallthrough to ");
		arm_emit_cfop_target(proj_false);
		be_emit_cstring(" */");
		be_emit_finish_line_gas(proj_false);
	} else {
		be_emit_cstring("b ");
		arm_emit_cfop_target(proj_false);
		be_emit_finish_line_gas(proj_false);
	}
}

Michael Beck's avatar
Michael Beck committed
523
524
525
/**
 * Emit a Compare with conditional branch.
 */
526
static void emit_arm_fpaCmfBra(const ir_node *irn) {
Matthias Braun's avatar
Matthias Braun committed
527
	(void) irn;
Michael Beck's avatar
Michael Beck committed
528
529
530
531
532
}

/**
 * Emit a Compare with conditional branch.
 */
533
static void emit_arm_fpaCmfeBra(const ir_node *irn) {
Matthias Braun's avatar
Matthias Braun committed
534
	(void) irn;
Michael Beck's avatar
Michael Beck committed
535
536
537
538
}

/** Sort register in ascending order. */
static int reg_cmp(const void *a, const void *b) {
Matthias Braun's avatar
Matthias Braun committed
539
540
	const arch_register_t * const *ra = a;
	const arch_register_t * const *rb = b;
Michael Beck's avatar
Michael Beck committed
541
542
543
544

	return *ra < *rb ? -1 : (*ra != *rb);
}

Michael Beck's avatar
Michael Beck committed
545
546
547
/**
 * Create the CopyB instruction sequence.
 */
548
static void emit_arm_CopyB(const ir_node *irn) {
Michael Beck's avatar
Michael Beck committed
549
	unsigned size = (unsigned)get_arm_imm_value(irn);
550

551
552
	const char *tgt = arch_register_get_name(get_in_reg(irn, 0));
	const char *src = arch_register_get_name(get_in_reg(irn, 1));
Michael Beck's avatar
Michael Beck committed
553
554
555
556
557
	const char *t0, *t1, *t2, *t3;

	const arch_register_t *tmpregs[4];

	/* collect the temporary registers and sort them, we need ascending order */
558
559
560
	tmpregs[0] = get_in_reg(irn, 2);
	tmpregs[1] = get_in_reg(irn, 3);
	tmpregs[2] = get_in_reg(irn, 4);
Michael Beck's avatar
Michael Beck committed
561
562
563
564
565
566
567
568
569
570
571
	tmpregs[3] = &arm_gp_regs[REG_R12];

	/* Note: R12 is always the last register because the RA did not assign higher ones */
	qsort((void *)tmpregs, 3, sizeof(tmpregs[0]), reg_cmp);

	/* need ascending order */
	t0 = arch_register_get_name(tmpregs[0]);
	t1 = arch_register_get_name(tmpregs[1]);
	t2 = arch_register_get_name(tmpregs[2]);
	t3 = arch_register_get_name(tmpregs[3]);

572
573
574
575
	be_emit_cstring("/* MemCopy (");
	be_emit_string(src);
	be_emit_cstring(")->(");
	arm_emit_source_register(irn, 0);
Michael Beck's avatar
Michael Beck committed
576
	be_emit_irprintf(" [%u bytes], Uses ", size);
577
578
579
580
581
582
583
584
585
	be_emit_string(t0);
	be_emit_cstring(", ");
	be_emit_string(t1);
	be_emit_cstring(", ");
	be_emit_string(t2);
	be_emit_cstring(", and ");
	be_emit_string(t3);
	be_emit_cstring("*/");
	be_emit_finish_line_gas(NULL);
586

Michael Beck's avatar
Michael Beck committed
587
588
589
590
	assert(size > 0 && "CopyB needs size > 0" );

	if (size & 3) {
		assert(!"strange hack enabled: copy more bytes than needed!");
591
		size += 4;
Michael Beck's avatar
Michael Beck committed
592
593
	}

594
	size >>= 2;
Michael Beck's avatar
Michael Beck committed
595
	switch (size & 3) {
596
597
598
	case 0:
		break;
	case 1:
599
600
601
602
603
604
605
606
607
608
609
610
611
		be_emit_cstring("\tldr ");
		be_emit_string(t3);
		be_emit_cstring(", [");
		be_emit_string(src);
		be_emit_cstring(", #0]");
		be_emit_finish_line_gas(NULL);

		be_emit_cstring("\tstr ");
		be_emit_string(t3);
		be_emit_cstring(", [");
		be_emit_string(tgt);
		be_emit_cstring(", #0]");
		be_emit_finish_line_gas(irn);
612
613
		break;
	case 2:
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
		be_emit_cstring("\tldmia ");
		be_emit_string(src);
		be_emit_cstring("!, {");
		be_emit_string(t0);
		be_emit_cstring(", ");
		be_emit_string(t1);
		be_emit_char('}');
		be_emit_finish_line_gas(NULL);

		be_emit_cstring("\tstmia ");
		be_emit_string(tgt);
		be_emit_cstring("!, {");
		be_emit_string(t0);
		be_emit_cstring(", ");
		be_emit_string(t1);
		be_emit_char('}');
		be_emit_finish_line_gas(irn);
631
632
		break;
	case 3:
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
		be_emit_cstring("\tldmia ");
		be_emit_string(src);
		be_emit_cstring("!, {");
		be_emit_string(t0);
		be_emit_cstring(", ");
		be_emit_string(t1);
		be_emit_cstring(", ");
		be_emit_string(t2);
		be_emit_char('}');
		be_emit_finish_line_gas(NULL);

		be_emit_cstring("\tstmia ");
		be_emit_string(tgt);
		be_emit_cstring("!, {");
		be_emit_string(t0);
		be_emit_cstring(", ");
		be_emit_string(t1);
		be_emit_cstring(", ");
		be_emit_string(t2);
		be_emit_char('}');
		be_emit_finish_line_gas(irn);
654
655
656
657
		break;
	}
	size >>= 2;
	while (size) {
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
		be_emit_cstring("\tldmia ");
		be_emit_string(src);
		be_emit_cstring("!, {");
		be_emit_string(t0);
		be_emit_cstring(", ");
		be_emit_string(t1);
		be_emit_cstring(", ");
		be_emit_string(t2);
		be_emit_cstring(", ");
		be_emit_string(t3);
		be_emit_char('}');
		be_emit_finish_line_gas(NULL);

		be_emit_cstring("\tstmia ");
		be_emit_string(tgt);
		be_emit_cstring("!, {");
		be_emit_string(t0);
		be_emit_cstring(", ");
		be_emit_string(t1);
		be_emit_cstring(", ");
		be_emit_string(t2);
		be_emit_cstring(", ");
		be_emit_string(t3);
		be_emit_char('}');
		be_emit_finish_line_gas(irn);
683
684
685
686
		--size;
	}
}

687
static void emit_arm_SwitchJmp(const ir_node *irn) {
688
689
690
691
692
693
	const ir_edge_t    *edge;
	ir_node            *proj;
	int i;
	ir_node **projs;
	int n_projs;
	int block_nr;
694
	ir_node *default_proj = NULL;
695
696

	block_nr = get_irn_node_nr(irn);
Michael Beck's avatar
Michael Beck committed
697
	n_projs = get_arm_SwitchJmp_n_projs(irn);
698

699
	projs = XMALLOCNZ(ir_node*, n_projs);
700
701
702
703
704

	foreach_out_edge(irn, edge) {
		proj = get_edge_src_irn(edge);
		assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");

Michael Beck's avatar
Michael Beck committed
705
		if (get_Proj_proj(proj) == get_arm_SwitchJmp_default_proj_num(irn))
706
			default_proj = proj;
707
708
709

		projs[get_Proj_proj(proj)] = proj;
	}
710
	assert(default_proj != NULL && "SwitchJmp should have a Default Proj");
711

Michael Beck's avatar
Michael Beck committed
712
713
714
715
	/*
	   CMP %1S, n_projs - 1
	   BHI default
	*/
716

717
718
719
720
	be_emit_cstring("\tcmp ");
	arm_emit_source_register(irn, 0);
	be_emit_irprintf(", #%u", n_projs - 1);
	be_emit_finish_line_gas(irn);
721

722
723
724
	be_emit_cstring("\tbhi ");
	arm_emit_cfop_target(default_proj);
	be_emit_finish_line_gas(default_proj);
725

Michael Beck's avatar
Michael Beck committed
726
727
728
729
730
	/*
	   LDR %r12, .TABLE_X_START
	   ADD %r12, %r12, [%1S, LSL #2]
	   LDR %r15, %r12
	 */
731

732
733
	be_emit_irprintf("\tldr %%r12, TABLE_%d_START", block_nr);
	be_emit_finish_line_gas(NULL);
734

735
736
737
738
	be_emit_irprintf("\tadd %%r12, %%r12, ");
	arm_emit_source_register(irn, 0);
	be_emit_cstring(", LSL #2");
	be_emit_finish_line_gas(NULL);
739

740
741
	be_emit_cstring("\tldr %r15, [%r12, #0]");
	be_emit_finish_line_gas(NULL);
742

743
744
745
746
747
748
	be_emit_irprintf("TABLE_%d_START:\n\t.word\tTABLE_%d", block_nr, block_nr);
	be_emit_finish_line_gas(NULL);
	be_emit_irprintf("\t.align 2");
	be_emit_finish_line_gas(NULL);
	be_emit_irprintf("TABLE_%d:", block_nr);
	be_emit_finish_line_gas(NULL);
749

Michael Beck's avatar
Michael Beck committed
750
	for (i = 0; i < n_projs; ++i) {
751
		proj = projs[i];
752
753
		if (proj == NULL) {
			proj = projs[get_arm_SwitchJmp_default_proj_num(irn)];
754
		}
755
756
757
		be_emit_cstring("\t.word\t");
		arm_emit_cfop_target(proj);
		be_emit_finish_line_gas(proj);
758
	}
759
760
	be_emit_irprintf("\t.align 2\n");
	be_emit_finish_line_gas(NULL);
761
762
763
764
765
766
767
	xfree(projs);
}

/************************************************************************/
/* emit_be                                                              */
/************************************************************************/

768
static void emit_be_Call(const ir_node *irn) {
769
	ir_entity *ent = be_Call_get_entity(irn);
Michael Beck's avatar
Michael Beck committed
770

771
	be_emit_cstring("\tbl ");
Michael Beck's avatar
Michael Beck committed
772
	if (ent) {
Michael Beck's avatar
Michael Beck committed
773
		set_entity_backend_marked(ent, 1);
774
		be_emit_ident(get_entity_ld_ident(ent));
Michael Beck's avatar
Michael Beck committed
775
	} else {
776
		arm_emit_source_register(irn, be_pos_Call_ptr);
Michael Beck's avatar
Michael Beck committed
777
	}
778
	be_emit_finish_line_gas(irn);
779
780
}

Michael Beck's avatar
Michael Beck committed
781
/** Emit an IncSP node */
782
static void emit_be_IncSP(const ir_node *irn) {
783
	int offs = -be_get_IncSP_offset(irn);
784
785

	if (offs != 0) {
786
787
788
789
790
791
		if (offs < 0) {
			be_emit_cstring("\tsub ");
			offs = -offs;
		} else {
			be_emit_cstring("\tadd ");
		}
792
793
794
		arm_emit_dest_register(irn, 0);
		be_emit_cstring(", ");
		arm_emit_source_register(irn, 0);
795
		be_emit_irprintf(", #0x%X", offs);
796
	} else {
797
798
		/* omitted IncSP(0) */
		return;
799
	}
800
	be_emit_finish_line_gas(irn);
801
802
}

803
static void emit_be_Copy(const ir_node *irn) {
804
805
	ir_mode *mode = get_irn_mode(irn);

806
	if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) {
807
		/* omitted Copy */
808
809
810
		return;
	}

811
	if (mode_is_float(mode)) {
812
		if (USE_FPA(cg->isa)) {
813
814
815
816
817
818
819
			be_emit_cstring("\tmvf");
			arm_emit_mode(irn);
			be_emit_char(' ');
			arm_emit_dest_register(irn, 0);
			be_emit_cstring(", ");
			arm_emit_source_register(irn, 0);
			be_emit_finish_line_gas(irn);
Michael Beck's avatar
Michael Beck committed
820
		} else {
821
			assert(0 && "move not supported for this mode");
Michael Beck's avatar
Michael Beck committed
822
			panic("emit_be_Copy: move not supported for this mode");
823
		}
824
	} else if (mode_is_data(mode)) {
825
826
827
828
829
		be_emit_cstring("\tmov ");
		arm_emit_dest_register(irn, 0);
		be_emit_cstring(", ");
		arm_emit_source_register(irn, 0);
			be_emit_finish_line_gas(irn);
830
831
	} else {
		assert(0 && "move not supported for this mode");
Michael Beck's avatar
Michael Beck committed
832
		panic("emit_be_Copy: move not supported for this mode");
833
834
835
	}
}

836
837
838
/**
 * Emit code for a Spill.
 */
839
static void emit_be_Spill(const ir_node *irn) {
Michael Beck's avatar
Michael Beck committed
840
	ir_mode *mode = get_irn_mode(be_get_Spill_val(irn));
841
842

	if (mode_is_float(mode)) {
843
844
845
846
		if (USE_FPA(cg->isa)) {
			be_emit_cstring("\tstf");
			arm_emit_fpa_postfix(mode);
			be_emit_char(' ');
Michael Beck's avatar
Michael Beck committed
847
848
849
		} else {
			assert(0 && "spill not supported for this mode");
			panic("emit_be_Spill: spill not supported for this mode");
850
851
		}
	} else if (mode_is_dataM(mode)) {
852
		be_emit_cstring("\tstr ");
853
854
	} else {
		assert(0 && "spill not supported for this mode");
Michael Beck's avatar
Michael Beck committed
855
		panic("emit_be_Spill: spill not supported for this mode");
856
	}
857
858
859
860
861
862
863
	arm_emit_source_register(irn, 1);
	be_emit_cstring(", [");
	arm_emit_source_register(irn, 0);
	be_emit_cstring(", #");
	arm_emit_offset(irn);
	be_emit_char(']');
	be_emit_finish_line_gas(irn);
864
865
}

866
867
868
/**
 * Emit code for a Reload.
 */
869
static void emit_be_Reload(const ir_node *irn) {
870
	ir_mode *mode = get_irn_mode(irn);
871
872

	if (mode_is_float(mode)) {
873
874
875
876
		if (USE_FPA(cg->isa)) {
			be_emit_cstring("\tldf");
			arm_emit_fpa_postfix(mode);
			be_emit_char(' ');
Michael Beck's avatar
Michael Beck committed
877
878
879
		} else {
			assert(0 && "reload not supported for this mode");
			panic("emit_be_Reload: reload not supported for this mode");
880
881
		}
	} else if (mode_is_dataM(mode)) {
882
		be_emit_cstring("\tldr ");
883
884
	} else {
		assert(0 && "reload not supported for this mode");
Michael Beck's avatar
Michael Beck committed
885
886
		panic("emit_be_Reload: reload not supported for this mode");
	}
887
888
889
890
891
892
893
	arm_emit_dest_register(irn, 0);
	be_emit_cstring(", [");
	arm_emit_source_register(irn, 0);
	be_emit_cstring(", #");
	arm_emit_offset(irn);
	be_emit_char(']');
	be_emit_finish_line_gas(irn);
Michael Beck's avatar
Michael Beck committed
894
895
}

896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
static void emit_be_Perm(const ir_node *irn) {
	be_emit_cstring("\teor ");
	arm_emit_source_register(irn, 0);
	be_emit_cstring(", ");
	arm_emit_source_register(irn, 0);
	be_emit_cstring(", ");
	arm_emit_source_register(irn, 1);
	be_emit_finish_line_gas(NULL);

	be_emit_cstring("\teor ");
	arm_emit_source_register(irn, 1);
	be_emit_cstring(", ");
	arm_emit_source_register(irn, 0);
	be_emit_cstring(", ");
	arm_emit_source_register(irn, 1);
	be_emit_finish_line_gas(NULL);

	be_emit_cstring("\teor ");
	arm_emit_source_register(irn, 0);
	be_emit_cstring(", ");
	arm_emit_source_register(irn, 0);
	be_emit_cstring(", ");
	arm_emit_source_register(irn, 1);
	be_emit_finish_line_gas(irn);
Michael Beck's avatar
Michael Beck committed
920
921
}

922
923
924
925
/************************************************************************/
/* emit                                                                 */
/************************************************************************/

926
static void emit_Jmp(const ir_node *node) {
927
	ir_node *block, *next_block;
928

929
930
931
932
933
934
	/* for now, the code works for scheduled and non-schedules blocks */
	block = get_nodes_block(node);

	/* we have a block schedule */
	next_block = sched_next_block(block);
	if (get_cfop_target_block(node) != next_block) {
935
936
		be_emit_cstring("\tb ");
		arm_emit_cfop_target(node);
937
	} else {
938
939
940
		be_emit_cstring("\t/* fallthrough to ");
		arm_emit_cfop_target(node);
		be_emit_cstring(" */");
Michael Beck's avatar
Michael Beck committed
941
	}
942
	be_emit_finish_line_gas(node);
943
944
}

945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
static void emit_arm_fpaDbl2GP(const ir_node *irn) {
	be_emit_cstring("\tstfd ");
	arm_emit_source_register(irn, 0);
	be_emit_cstring(", [sp, #-8]!");
	be_emit_pad_comment();
	be_emit_cstring("/* Push fp to stack */");
	be_emit_finish_line_gas(NULL);

	be_emit_cstring("\tldmfd sp!, {");
	arm_emit_dest_register(irn, 1);
	be_emit_cstring(", ");
	arm_emit_dest_register(irn, 0);
	be_emit_char('}');
	be_emit_pad_comment();
	be_emit_cstring("/* Pop destination */");
	be_emit_finish_line_gas(irn);
Michael Beck's avatar
Michael Beck committed
961
}
962

963
static void emit_arm_LdTls(const ir_node *irn) {
Matthias Braun's avatar
Matthias Braun committed
964
	(void) irn;
965
	panic("TLS not supported for this target");
966
967
968
	/* Er... our gcc does not support it... Install a newer toolchain. */
}

969
970
971
972
973
974
975
976
977
978
/***********************************************************************************
 *                  _          __                                             _
 *                 (_)        / _|                                           | |
 *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
 * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
 * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
 * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
 *
 ***********************************************************************************/

979
static void emit_silence(const ir_node *irn) {
Matthias Braun's avatar
Matthias Braun committed
980
	(void) irn;
Michael Beck's avatar
Michael Beck committed
981
982
983
984
985
986
	/* Do nothing. */
}

/**
 * The type of a emitter function.
 */
987
typedef void (emit_func)(const ir_node *irn);
Michael Beck's avatar
Michael Beck committed
988
989
990
991

/**
 * Set a node emitter. Make it a bit more type safe.
 */
992
static inline void set_emitter(ir_op *op, emit_func arm_emit_node) {
Michael Beck's avatar
Michael Beck committed
993
994
995
	op->ops.generic = (op_func)arm_emit_node;
}

996
997
998
999
1000
1001
/**
 * Enters the emitter functions for handled nodes into the generic
 * pointer of an opcode.
 */
static void arm_register_emitters(void) {

Michael Beck's avatar
Michael Beck committed
1002
1003
1004
1005
#define ARM_EMIT(a)  set_emitter(op_arm_##a, emit_arm_##a)
#define EMIT(a)      set_emitter(op_##a, emit_##a)
#define BE_EMIT(a)   set_emitter(op_be_##a, emit_be_##a)
#define SILENCE(a)   set_emitter(op_##a, emit_silence)
1006
1007
1008
1009
1010
1011
1012
1013

	/* first clear the generic function pointer for all ops */
	clear_irp_opcodes_generic_func();

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

	/* other emitter functions */
Michael Beck's avatar
Michael Beck committed
1014
	ARM_EMIT(CmpBra);
1015
	ARM_EMIT(TstBra);
Michael Beck's avatar
Michael Beck committed
1016
1017
	ARM_EMIT(fpaCmfBra);
	ARM_EMIT(fpaCmfeBra);
Michael Beck's avatar
Michael Beck committed
1018
	ARM_EMIT(CopyB);
1019
1020
1021
1022
// 	ARM_EMIT(CopyB_i);
//	ARM_EMIT(Const);
	ARM_EMIT(SymConst);
	ARM_EMIT(SwitchJmp);
Michael Beck's avatar
Michael Beck committed
1023
	ARM_EMIT(fpaDbl2GP);
Michael Beck's avatar
Michael Beck committed
1024
	ARM_EMIT(fpaConst);
1025
	ARM_EMIT(LdTls);
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035

	/* benode emitter */
 	BE_EMIT(Call);
 	BE_EMIT(IncSP);
	BE_EMIT(Copy);
	BE_EMIT(Spill);
	BE_EMIT(Reload);
	BE_EMIT(Perm);

	/* firm emitter */
Michael Beck's avatar
Michael Beck committed
1036
	EMIT(Jmp);
1037
1038
1039

	/* noisy stuff */
#ifdef SILENCER
Michael Beck's avatar
Michael Beck committed
1040
1041
1042
1043
	SILENCE(Proj);
	SILENCE(Phi);
	SILENCE(be_Keep);
	SILENCE(be_CopyKeep);
1044
	SILENCE(be_Start);
Michael Beck's avatar
Michael Beck committed
1045
1046
	SILENCE(be_Barrier);
	SILENCE(be_Return);
1047
1048
1049
1050
1051
#endif

#undef ARM_EMIT
#undef BE_EMIT
#undef EMIT
1052
#undef SILENCE
1053
1054
1055
1056
1057
}

/**
 * Emits code for a node.
 */
1058
static void arm_emit_node(const ir_node *irn) {
Michael Beck's avatar
Michael Beck committed
1059
	ir_op *op = get_irn_op(irn);
1060
1061

	if (op->ops.generic) {
Michael Beck's avatar
Michael Beck committed
1062
		emit_func *emit = (emit_func *)op->ops.generic;
1063
		be_dbg_set_dbg_info(get_irn_dbg_info(irn));
1064
		(*emit)(irn);
Michael Beck's avatar
Michael Beck committed
1065
	} else {
1066
1067
		be_emit_cstring("\t/* TODO */");
		be_emit_finish_line_gas(irn);
1068
1069
1070
	}
}

1071
1072
1073
/**
 * emit the block label if needed.
 */
1074
static void arm_emit_block_header(ir_node *block, ir_node *prev)
1075
1076
1077
1078
{
	int           n_cfgpreds;
	int           need_label;
	int           i, arity;
1079
	ir_exec_freq  *exec_freq = cg->birg->exec_freq;
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099

	need_label = 0;
	n_cfgpreds = get_Block_n_cfgpreds(block);
	if (n_cfgpreds == 1) {
		ir_node *pred       = get_Block_cfgpred(block, 0);
		ir_node *pred_block = get_nodes_block(pred);

		/* we don't need labels for fallthrough blocks, however switch-jmps
		 * are no fallthroughs */
		if (pred_block == prev &&
				!(is_Proj(pred) && is_arm_SwitchJmp(get_Proj_pred(pred)))) {
			need_label = 0;
		} else {
			need_label = 1;
		}
	} else {
		need_label = 1;
	}

	if (need_label) {
1100
1101
		arm_emit_block_name(block);
		be_emit_char(':');
1102

1103
1104
		be_emit_pad_comment();
		be_emit_cstring("   /* preds:");
1105
1106
1107
1108
1109

		/* emit list of pred blocks in comment */
		arity = get_irn_arity(block);
		for (i = 0; i < arity; ++i) {
			ir_node *predblock = get_Block_cfgpred_block(block, i);
1110
			be_emit_irprintf(" %d", get_irn_node_nr(predblock));
1111
1112
		}
	} else {
1113
1114
1115
		be_emit_cstring("\t/* ");
		arm_emit_block_name(block);
		be_emit_cstring(": ");
1116
1117
	}
	if (exec_freq != NULL) {
1118
		be_emit_irprintf(" freq: %f",
1119
1120
		                 get_block_execfreq(exec_freq, block));
	}
1121
1122
	be_emit_cstring(" */\n");
	be_emit_write_line();
1123
1124
}

1125
1126
1127
1128
/**
 * Walks over the nodes in a block connected by scheduling edges
 * and emits code for each node.
 */
1129
static void arm_gen_block(ir_node *block, ir_node *prev_block) {
1130
1131
	ir_node *irn;

1132
	arm_emit_block_header(block, prev_block);
1133
	be_dbg_set_dbg_info(get_irn_dbg_info(block));
1134
	sched_foreach(block, irn) {
1135
		arm_emit_node(irn);
Michael Beck's avatar