arm_emitter.c 29.8 KB
Newer Older
1
#define SILENCER
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/* arm emitter */
/* $Id$ */

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

#include <limits.h>

#include "xmalloc.h"
#include "tv.h"
#include "iredges.h"
#include "debug.h"
#include "irgwalk.h"
#include "irprintf.h"
#include "irop_t.h"
#include "irprog_t.h"
#include "irargs_t.h"

#include "../besched.h"

#include "arm_emitter.h"
#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"

#include "../benode_t.h"

#define SNPRINTF_BUF_LEN 128

static const arch_env_t *arch_env = NULL;

Michael Beck's avatar
Michael Beck committed
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
/**
 * Switch to a new section
 */
void arm_switch_section(FILE *f, sections sec) {
	static sections curr_sec = NO_SECTION;

	if (curr_sec == sec)
		return;

	curr_sec = sec;
	switch (sec) {

	case NO_SECTION:
		break;

	case SECTION_TEXT:
		fprintf(f, "\t.text\n");
		break;

	case SECTION_DATA:
		fprintf(f, "\t.data\n");
		break;
	}
}
60
61
62
63
64
65
66
67
68
69
70
71

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

Michael Beck's avatar
Michael Beck committed
72
73
74
/**
 * Returns non-zero if a mode has a Immediate attribute.
 */
75
int is_immediate_node(ir_node *irn) {
Michael Beck's avatar
Michael Beck committed
76
77
	arm_attr_t *attr = get_arm_attr(irn);
	return ARM_GET_SHF_MOD(attr) == ARM_SHF_IMM;
78
79
80
}

/**
Michael Beck's avatar
Michael Beck committed
81
 * Return a const or SymConst as string.
82
 */
Michael Beck's avatar
Michael Beck committed
83
84
85
86
static const char *node_const_to_str(ir_node *n, char *buf, int buflen) {
	if (is_immediate_node(n)) {
		snprintf(buf, buflen, "#0x%X", arm_decode_imm_w_shift(get_arm_value(n)));
		return buf;
87
	}
Michael Beck's avatar
Michael Beck committed
88
89
	else if (is_arm_SymConst(n))
		return get_arm_symconst_label(n);
90

Michael Beck's avatar
Michael Beck committed
91
92
	assert( 0 && "das ist gar keine Konstante");
	return NULL;
93
94
95
96
97
}

/**
 * Returns node's offset as string.
 */
Michael Beck's avatar
Michael Beck committed
98
static const char *node_offset_to_str(ir_node *n, char *buf, int buflen) {
99
100
	int offset = 0;
	ir_op *irn_op = get_irn_op(n);
Michael Beck's avatar
Michael Beck committed
101

102
103
104
	if (irn_op == op_be_StackParam) {
		entity *ent = be_get_frame_entity(n);
		offset = get_entity_offset_bytes(ent);
Michael Beck's avatar
Michael Beck committed
105
	} else if (irn_op == op_be_Reload || irn_op == op_be_Spill) {
106
		entity *ent = be_get_frame_entity(n);
107
		offset = get_entity_offset_bytes(ent);
Michael Beck's avatar
Michael Beck committed
108
	} else if (irn_op == op_be_IncSP) {
109
		offset = - be_get_IncSP_offset(n);
110
111
112
	} else {
		return "node_offset_to_str will fuer diesen Knotentyp noch implementiert werden";
	}
Michael Beck's avatar
Michael Beck committed
113
114
	snprintf(buf, buflen, "%d", offset);
	return buf;
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
}

/* We always pass the ir_node which is a pointer. */
static int arm_get_arg_type(const lc_arg_occ_t *occ) {
	return lc_arg_type_ptr;
}


/**
 * Returns the register at in position pos.
 */
static const arch_register_t *get_in_reg(const ir_node *irn, int pos) {
	ir_node                *op;
	const arch_register_t  *reg = NULL;

	assert(get_irn_arity(irn) > pos && "Invalid IN position");

	/* The out register of the operator at position pos is the
	   in register we need. */
	op = get_irn_n(irn, pos);

	reg = arch_get_irn_register(arch_env, op);

	assert(reg && "no in register found");
	return reg;
}

/**
 * Returns the register at out position pos.
 */
static const arch_register_t *get_out_reg(const ir_node *irn, int pos) {
	ir_node                *proj;
	const arch_register_t  *reg = NULL;

	assert(get_irn_n_edges(irn) > pos && "Invalid OUT position");

	/* 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(irn) != mode_T) {
		reg = arch_get_irn_register(arch_env, irn);
	}
	else if (is_arm_irn(irn)) {
		reg = get_arm_out_reg(irn, pos);
	}
	else {
		const ir_edge_t *edge;

		foreach_out_edge(irn, edge) {
			proj = get_edge_src_irn(edge);
			assert(is_Proj(proj) && "non-Proj from mode_T node");
			if (get_Proj_proj(proj) == pos) {
				reg = arch_get_irn_register(arch_env, proj);
				break;
			}
		}
	}

	assert(reg && "no out register found");
	return reg;
}

/**
 * Returns the number of the in register at position pos.
 */
int get_arm_reg_nr(ir_node *irn, int pos, int in_out) {
	const arch_register_t *reg;

	if (in_out == 1) {
		reg = get_in_reg(irn, pos);
	}
	else {
		reg = get_out_reg(irn, pos);
	}

	return arch_register_get_index(reg);
}

/**
 * Returns the name of the in register at position pos.
 */
const char *get_arm_reg_name(ir_node *irn, int pos, int in_out) {
	const arch_register_t *reg;

	if (in_out == 1) {
		reg = get_in_reg(irn, pos);
	}
	else {
		reg = get_out_reg(irn, pos);
	}

	return arch_register_get_name(reg);
}

/**
 * Get the register name for a node.
 */
static int arm_get_reg_name(lc_appendable_t *app,
    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
{
	const char *buf;
	ir_node    *X  = arg->v_ptr;
	int         nr = occ->width - 1;

	if (!X)
		return lc_appendable_snadd(app, "(null)", 6);

	if (occ->conversion == 'S') {
		buf = get_arm_reg_name(X, nr, 1);
	}
	else { /* 'D' */
		buf = get_arm_reg_name(X, nr, 0);
	}

	lc_appendable_chadd(app, '%');
	return lc_appendable_snadd(app, buf, strlen(buf));
}

/**
 * Returns the tarval or offset of an arm node as a string.
 */
static int arm_const_to_str(lc_appendable_t *app,
    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
{
Michael Beck's avatar
Michael Beck committed
241
	char buffer[SNPRINTF_BUF_LEN];
242
243
244
245
246
247
248
	const char *buf;
	ir_node    *X = arg->v_ptr;

	if (!X)
		return lc_appendable_snadd(app, "(null)", 6);

	if (occ->conversion == 'C') {
Michael Beck's avatar
Michael Beck committed
249
		buf = node_const_to_str(X, buffer, sizeof(buffer));
250
251
	}
	else { /* 'O' */
Michael Beck's avatar
Michael Beck committed
252
		buf = node_offset_to_str(X, buffer, sizeof(buffer));
253
254
255
256
257
258
	}

	return lc_appendable_snadd(app, buf, strlen(buf));
}

/**
Michael Beck's avatar
Michael Beck committed
259
260
261
262
263
264
 * Returns the tarval or offset of an arm node as a string.
 */
static int arm_shift_str(lc_appendable_t *app,
    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
{
	char buffer[SNPRINTF_BUF_LEN];
Michael Beck's avatar
Michael Beck committed
265
	ir_node            *irn = arg->v_ptr;
Michael Beck's avatar
Michael Beck committed
266
267
	arm_shift_modifier mod;

Michael Beck's avatar
Michael Beck committed
268
	if (!irn)
Michael Beck's avatar
Michael Beck committed
269
270
		return lc_appendable_snadd(app, "(null)", 6);

Michael Beck's avatar
Michael Beck committed
271
	mod = get_arm_shift_modifier(irn);
Michael Beck's avatar
Michael Beck committed
272
	if (ARM_HAS_SHIFT(mod)) {
Michael Beck's avatar
Michael Beck committed
273
		long v = get_tarval_long(get_arm_value(irn));
Michael Beck's avatar
Michael Beck committed
274

275
		snprintf(buffer, sizeof(buffer), ", %s #%ld", arm_shf_mod_name(mod), v);
Michael Beck's avatar
Michael Beck committed
276
277
278
279
280
281
282
		return lc_appendable_snadd(app, buffer, strlen(buffer));
	}
	return 0;
}

/**
 * Determines the instruction suffix depending on the mode.
283
284
285
286
 */
static int arm_get_mode_suffix(lc_appendable_t *app,
    const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
{
Michael Beck's avatar
Michael Beck committed
287
288
289
290
	ir_node *irn = arg->v_ptr;
	arm_attr_t *attr;
	ir_mode *mode;
	int bits;
291

Michael Beck's avatar
Michael Beck committed
292
	if (! irn)
293
294
		return lc_appendable_snadd(app, "(null)", 6);

Michael Beck's avatar
Michael Beck committed
295
296
297
298
299
	attr = get_arm_attr(irn);
	mode = attr->op_mode ? attr->op_mode : get_irn_mode(irn);
	bits = get_mode_size_bits(mode);

	if (bits == 32)
300
		return lc_appendable_chadd(app, 's');
Michael Beck's avatar
Michael Beck committed
301
	else if (bits == 64)
302
		return lc_appendable_chadd(app, 'd');
Michael Beck's avatar
Michael Beck committed
303
304
	else
		return lc_appendable_chadd(app, 'e');
305
306
307
308
309
310
311
312
313
314
315
316
}

/**
 * Return the arm printf arg environment.
 * We use the firm environment with some additional handlers.
 */
const lc_arg_env_t *arm_get_arg_env(void) {
	static lc_arg_env_t *env = NULL;

	static const lc_arg_handler_t arm_reg_handler   = { arm_get_arg_type, arm_get_reg_name };
	static const lc_arg_handler_t arm_const_handler = { arm_get_arg_type, arm_const_to_str };
	static const lc_arg_handler_t arm_mode_handler  = { arm_get_arg_type, arm_get_mode_suffix };
Michael Beck's avatar
Michael Beck committed
317
	static const lc_arg_handler_t arm_shf_handler   = { arm_get_arg_type, arm_shift_str };
318

Michael Beck's avatar
Michael Beck committed
319
	if (env == NULL) {
320
321
322
323
324
325
326
327
328
		/* extend the firm printer */
		env = firm_get_arg_env();
			//lc_arg_new_env();

		lc_arg_register(env, "arm:sreg", 'S', &arm_reg_handler);
		lc_arg_register(env, "arm:dreg", 'D', &arm_reg_handler);
		lc_arg_register(env, "arm:cnst", 'C', &arm_const_handler);
		lc_arg_register(env, "arm:offs", 'O', &arm_const_handler);
		lc_arg_register(env, "arm:mode", 'M', &arm_mode_handler);
Michael Beck's avatar
Michael Beck committed
329
		lc_arg_register(env, "arm:shf",  'X', &arm_shf_handler);
330
331
332
333
334
335
336
337
	}

	return env;
}

/**
 * Formated print of commands and comments.
 */
338
static void arm_fprintf_format(FILE *F, const char *cmd_buf, const char *cmnt_buf, const ir_node *irn) {
Michael Beck's avatar
Michael Beck committed
339
	lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F (%G) */\n", cmd_buf, cmnt_buf, irn, irn);
340
341
}

Michael Beck's avatar
Michael Beck committed
342
343
/**
 * Returns a unique label. This number will not be used a second time.
344
 */
Michael Beck's avatar
Michael Beck committed
345
346
347
static unsigned get_unique_label(void) {
	static unsigned id = 0;
	return ++id;
348
349
350
351
352
353
354
355
356
}


/**
 * Returns the target label for a control flow node.
 */
static char *get_cfop_target(const ir_node *irn, char *buf) {
	ir_node *bl = get_irn_link(irn);

Christoph Mallon's avatar
Christoph Mallon committed
357
	snprintf(buf, SNPRINTF_BUF_LEN, "BLOCK_%ld", get_irn_node_nr(bl));
358
359
360
	return buf;
}

Michael Beck's avatar
Michael Beck committed
361
362
363
/**
 * Emit a SymConst
 */
364
365
static void emit_arm_SymConst(ir_node *irn, void *env) {
	arm_emit_env_t *emit_env = env;
366
	FILE *F = emit_env->out;
Michael Beck's avatar
Michael Beck committed
367
	SymConstEntry *entry = obstack_alloc(&emit_env->obst, sizeof(*entry));
368
369
	const lc_arg_env_t *arg_env = arm_get_arg_env();
	char cmd_buf[256];
Michael Beck's avatar
Michael Beck committed
370
371
372
373
374
375

	entry->label      = get_unique_label();
	entry->symconst   = irn;
	entry->next       = emit_env->symbols;
	emit_env->symbols = entry;

376
377
	lc_esnprintf(arg_env, cmd_buf, 256, "ldr %1D, .L%u", irn, entry->label);
	arm_fprintf_format(F, cmd_buf, "/* indirect SymConst */", irn);
378
379
}

Michael Beck's avatar
Michael Beck committed
380
381
382
383
384
385
386
387
388
389
/**
 * Returns the next block in a block schedule.
 */
static ir_node *sched_next_block(ir_node *block) {
    return get_irn_link(block);
}

/**
 * Emit a conditional jump.
 */
390
391
392
393
394
395
396
397
398
399
400
401
402
static void emit_arm_CondJmp(ir_node *irn, void *env) {
	arm_emit_env_t *emit_env = env;
	FILE *out = emit_env->out;
	const ir_edge_t *edge;
	ir_node *true_block = NULL;
	ir_node *false_block = NULL;
	ir_node *op1 = get_irn_n(irn, 0);
	ir_mode *opmode = get_irn_mode(op1);
	char *suffix;
	int proj_num = get_arm_proj_num(irn);
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];


Michael Beck's avatar
Michael Beck committed
403
404
405
	foreach_out_edge(irn, edge) {
		ir_node *proj = get_edge_src_irn(edge);
		long nr = get_Proj_proj(proj);
406
407
408
409
410
411
412
413
		ir_node *block = get_irn_link(proj);
		if ( nr == pn_Cond_true) {
			true_block = block;
		} else if (nr == pn_Cond_false) {
			false_block = block;
		} else {
			assert(0 && "tertium non datur! (CondJmp)");
		}
Michael Beck's avatar
Michael Beck committed
414
	}
415
416

	if (proj_num == pn_Cmp_False) {
Michael Beck's avatar
Michael Beck committed
417
		/* always false: should not happen */
Christoph Mallon's avatar
Christoph Mallon committed
418
		fprintf(out, "\tb BLOCK_%ld\t\t\t/* false case */\n", get_irn_node_nr(false_block));
419
	} else if (proj_num == pn_Cmp_True) {
Michael Beck's avatar
Michael Beck committed
420
		/* always true: should not happen */
Christoph Mallon's avatar
Christoph Mallon committed
421
		fprintf(out, "\tb BLOCK_%ld\t\t\t/* true case */\n", get_irn_node_nr(true_block));
422
	} else {
Michael Beck's avatar
Michael Beck committed
423
424
		ir_node *block = get_nodes_block(irn);

425
426
427
		if (mode_is_float(opmode)) {
			suffix = "ICHWILLIMPLEMENTIERTWERDEN";

Michael Beck's avatar
Michael Beck committed
428
			lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "fcmp %1S, %2S", irn, irn);
429
430
431
			lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Compare(%1S, %2S) -> FCPSR */", irn, irn );
			arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);

Michael Beck's avatar
Michael Beck committed
432
			lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "fmstat", irn, irn);
433
434
435
			lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* FCSPR -> CPSR */");
			arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
		} else {
Michael Beck's avatar
Michael Beck committed
436
437
438
439
			if (true_block == sched_next_block(block)) {
				/* negate it */
				proj_num = get_negated_pnc(proj_num, opmode);
			}
440
			switch(proj_num) {
Michael Beck's avatar
Michael Beck committed
441
442
443
444
445
446
447
448
				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(0 && "komische Dinge geschehen"); suffix = "al";
449
450
			}

Michael Beck's avatar
Michael Beck committed
451
			lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "cmp %1S, %2S", irn, irn);
452
453
			lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Compare(%1S, %2S) -> CPSR */", irn, irn );
			arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
Michael Beck's avatar
Michael Beck committed
454
		}
455

Michael Beck's avatar
Michael Beck committed
456
		if (true_block == sched_next_block(block)) {
Michael Beck's avatar
Michael Beck committed
457
			lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "b%s BLOCK_%d", suffix, get_irn_node_nr(true_block));
458
459
			lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* false case */");
			arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
Michael Beck's avatar
Michael Beck committed
460
461
462

			lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrough BLOCK_%d */", get_irn_node_nr(false_block));
			arm_fprintf_format(out, "", cmnt_buf, irn);
463
		}
Michael Beck's avatar
Michael Beck committed
464
		else {
Michael Beck's avatar
Michael Beck committed
465
			lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "b%s BLOCK_%d", suffix, get_irn_node_nr(true_block));
Michael Beck's avatar
Michael Beck committed
466
467
468
469
470
471
472
473
			lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* true case */");
			arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);

            if (false_block == sched_next_block(block)) {
                lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrough BLOCK_%d */", get_irn_node_nr(false_block));
                arm_fprintf_format(out, "", cmnt_buf, irn);
            }
            else {
Michael Beck's avatar
Michael Beck committed
474
			    lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "b BLOCK_%d", get_irn_node_nr(false_block));
Michael Beck's avatar
Michael Beck committed
475
476
477
478
			    lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* false case */");
			    arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
            }
        }
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
	}
}

static void emit_arm_CopyB(ir_node *irn, void *env) {
	arm_emit_env_t *emit_env = env;
	FILE *out = emit_env->out;
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
	unsigned int size = get_tarval_long(get_arm_value(irn));
	const lc_arg_env_t *arg_env = arm_get_arg_env();

	lc_esnprintf(arg_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* MemCopy (%2S)->(%1S) [%d bytes], Use %3S, %4S, %5S and %%r12 */", irn, irn, size, irn, irn, irn);

	assert ( size > 0 && "CopyB needs size > 0" );
	if (size & 3)
		size += 4;
	size >>= 2;
	switch(size & 3) {
	case 0:
		break;
	case 1:
Michael Beck's avatar
Michael Beck committed
499
		lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ldr %%r12, [%2S, #0]!", irn);
500
		arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
Michael Beck's avatar
Michael Beck committed
501
		lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "str  %%r12, [%1S, #0]!", irn);
502
503
504
		arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
		break;
	case 2:
Michael Beck's avatar
Michael Beck committed
505
		lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ldmia %2S!, {%%r12, %3S}", irn, irn);
506
		arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
Michael Beck's avatar
Michael Beck committed
507
		lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "stmia %1S!, {%%r12, %3S}", irn, irn);
508
509
510
		arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
		break;
	case 3:
Michael Beck's avatar
Michael Beck committed
511
		lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ldmia %2S!, {%%r12, %3S, %4S}", irn, irn, irn);
512
		arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
Michael Beck's avatar
Michael Beck committed
513
		lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "stmia %1S!, {%%r12, %3S, %4S}", irn, irn, irn);
514
515
516
517
518
		arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
		break;
	}
	size >>= 2;
	while (size) {
Michael Beck's avatar
Michael Beck committed
519
		lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ldmia %2S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn);
520
		arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
Michael Beck's avatar
Michael Beck committed
521
		lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "stmia %1S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn);
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
		arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
		--size;
	}
}

static void emit_arm_SwitchJmp(ir_node *irn, void *env) {
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
	const ir_edge_t    *edge;
	ir_node            *proj;
	arm_emit_env_t *emit_env = env;
	FILE *out = emit_env->out;
	int i;
	ir_node **projs;
	int n_projs;
	int block_nr;
	int default_block_num;

	block_nr = get_irn_node_nr(irn);
	n_projs = get_arm_n_projs(irn);

	projs = xcalloc(n_projs , sizeof(ir_node*));

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

		if (get_Proj_proj(proj) == get_arm_default_proj_num(irn))
			default_block_num = get_irn_node_nr(get_irn_link(proj));

		projs[get_Proj_proj(proj)] = proj;
	}

	// CMP %1S, n_projs - 1
	// BHI default



Michael Beck's avatar
Michael Beck committed
559
	lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "cmp %1S, #%u", irn, n_projs - 1);
560
	lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
561
	arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
562

Michael Beck's avatar
Michael Beck committed
563
	lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "bhi BLOCK_%d", default_block_num);
564
	lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
565
	arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
566
567


Michael Beck's avatar
Michael Beck committed
568
	lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ldr %%r12, TABLE_%d_START", block_nr);
569
	lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
570
	arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
571

Michael Beck's avatar
Michael Beck committed
572
	lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "add %%r12, %%r12, %1S, LSL #2", irn);
573
	lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
574
	arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
575

Michael Beck's avatar
Michael Beck committed
576
	lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ldr %%r15, [%%r12, #0]");
577
	lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
578
	arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596

	// LDR %r12, .TABLE_X_START
	// ADD %r12, %r12, [%1S, LSL #2]
	// LDR %r15, %r12

	fprintf(out, "TABLE_%d_START:\n\t.word\tTABLE_%d\n", block_nr, block_nr);
	fprintf(out, "\t.align 2\n");
	fprintf(out, "TABLE_%d:\n", block_nr);


	for ( i=0; i<n_projs; i++) {
		ir_node *block;
		proj = projs[i];
		if ( proj ) {
			block = get_irn_link(proj);
		} else {
			block = get_irn_link(projs[get_arm_default_proj_num(irn)]);
		}
Christian Würdig's avatar
Christian Würdig committed
597
		fprintf(out, "\t.word\tBLOCK_%ld\n",get_irn_node_nr(block));
598
599
600
601
602
603
604
605
606
607
608
609
	}
	fprintf(out, "\t.align 2\n");

	xfree(projs);
}

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

static void emit_be_Call(ir_node *irn, void *env) {
	arm_emit_env_t *emit_env = env;
Michael Beck's avatar
Michael Beck committed
610
611
612
613
614
	FILE *F = emit_env->out;
	entity *ent = be_Call_get_entity(irn);
    char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];

    if (ent)
Michael Beck's avatar
Michael Beck committed
615
	    lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "bl %s", get_entity_ld_name(ent));
Michael Beck's avatar
Michael Beck committed
616
617
618
    else
        lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "%1D", get_irn_n(irn, be_pos_Call_ptr));
    lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F (be_Call) */", irn);
619
    arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
620
621
}

Michael Beck's avatar
Michael Beck committed
622
/** Emit an IncSP node */
623
624
static void emit_be_IncSP(const ir_node *irn, arm_emit_env_t *emit_env) {
	FILE *F = emit_env->out;
625
626
627
	int offs = be_get_IncSP_offset(irn);

	if (offs != 0) {
628
		char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
Michael Beck's avatar
Michael Beck committed
629
		lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "add %1D, %1S, #%O", irn, irn, irn );
630
		lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* IncSP(%O) */", irn);
631
		arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
632
	} else {
Michael Beck's avatar
Michael Beck committed
633
		char cmnt_buf[SNPRINTF_BUF_LEN];
634
		lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* omitted IncSP(%O) */", irn);
635
		arm_fprintf_format(F, "", cmnt_buf, irn);
636
637
638
639
640
641
642
643
644
645
646
647
648
649
	}
}

// void emit_be_AddSP(const ir_node *irn, arm_emit_env_t *emit_env) {
// 	FILE *F = emit_env->out;
// 	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
// 	lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ADD %1D, %1S, %2S", irn, irn, irn );
// 	lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* AddSP(%2S) */", irn);
// 	lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
// }

static void emit_be_Copy(const ir_node *irn, arm_emit_env_t *emit_env) {
	FILE *F    = emit_env->out;
	ir_mode *mode = get_irn_mode(irn);
650
651
	const lc_arg_env_t *arm_env = arm_get_arg_env();
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
652
653

	if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) {
654
655
		lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* omitted Copy: %1S -> %1D */", irn, irn);
		lc_efprintf(arm_env, F, "\t%-35s %-60s /* %+F */\n", "", cmnt_buf, irn);
656
657
658
		return;
	}

659
660
661
662
663
664
665
666
667
	if (mode_is_float(mode)) {
		if (USE_FPA(emit_env->cg->isa)) {
			lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "mvf%M %1D, %1S", irn, irn, irn);
			lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Copy: %1S -> %1D */", irn, irn);
			arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
		}
		else {
			assert(0 && "move not supported for this mode");
		}
668
	} else if (mode_is_numP(mode)) {
669
670
671
		lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "mov %1D, %1S", irn, irn);
		lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Copy: %1S -> %1D */", irn, irn);
		arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
672
673
674
675
676
677
	} else {
		assert(0 && "move not supported for this mode");
	}
//	emit_arm_Copy(irn, emit_env);
}

678
679
680
/**
 * Emit code for a Spill.
 */
681
682
683
static void emit_be_Spill(const ir_node *irn, arm_emit_env_t *emit_env) {
	FILE *F = emit_env->out;
	ir_mode *mode = get_irn_mode(irn);
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
	const lc_arg_env_t *arm_env = arm_get_arg_env();
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];

	if (mode_is_float(mode)) {
		if (USE_FPA(emit_env->cg->isa)) {
			lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "stf %2S, [%1S, #%O]", irn, irn, irn );
			lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Spill(%2S) -> (%1S) */", irn, irn);
			arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
		}
		else {
			assert(0 && "move not supported for this mode");
		}
	} else if (mode_is_dataM(mode)) {
		lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "str %2S, [%1S, #%O]", irn, irn, irn );
		lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Spill(%2S) -> (%1S) */", irn, irn);
		arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
700
701
702
703
704
	} else {
		assert(0 && "spill not supported for this mode");
	}
}

705
706
707
/**
 * Emit code for a Reload.
 */
708
709
710
static void emit_be_Reload(const ir_node* irn, arm_emit_env_t *emit_env) {
	FILE *F = emit_env->out;
	ir_mode *mode = get_irn_mode(irn);
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
	const lc_arg_env_t *arm_env = arm_get_arg_env();
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];

	if (mode_is_float(mode)) {
		if (USE_FPA(emit_env->cg->isa)) {
			lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "ldf %1D, [%1S, #%O]", irn, irn, irn );
			lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Reload(%1S) -> (%1D) */", irn, irn);
			arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
		}
		else {
			assert(0 && "move not supported for this mode");
		}
	} else if (mode_is_dataM(mode)) {
		lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "ldr %1D, [%1S, #%O]", irn, irn, irn );
		lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Reload(%1S) -> (%1D) */", irn, irn);
		arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
727
728
729
730
731
732
733
	} else {
		assert(0 && "reload not supported for this mode");
	}
}

static void emit_be_Perm(const ir_node* irn, arm_emit_env_t *emit_env) {
	FILE *F = emit_env->out;
734
735
736
	const lc_arg_env_t *arm_env = arm_get_arg_env();
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];

Christian Würdig's avatar
Christian Würdig committed
737
738
739
740
741
742
743
744
745
746
747
	lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "eor %1S, %1S, %2S", irn, irn, irn);
	lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* begin Perm(%1S, %2S) */", irn, irn);
	arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);

	lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "eor %2S, %1S, %2S", irn, irn, irn);
	lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, " ");
	arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);

	lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "eor %1S, %1S, %2S", irn, irn, irn);
	lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* end Perm(%1S, %2S) */", irn, irn);
	arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
748
749
750
751
752
}

static void emit_be_StackParam(const ir_node *irn, arm_emit_env_t *emit_env) {
	FILE *F = emit_env->out;
	ir_mode *mode = get_irn_mode(irn);
753
754
	const lc_arg_env_t *arm_env = arm_get_arg_env();
	char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
755

756
757
758
759
760
761
762
763
764
765
766
767
768
769
	if (mode_is_float(mode)) {
		if (USE_FPA(emit_env->cg->isa)) {
			lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "ldf %1D, [%1S, #%O]", irn, irn, irn );
			lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* StackParam: (%1S + %O) -> %1D */",irn , irn, irn, get_irn_n(irn, 0));
			arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
		}
		else {
			assert(0 && "move not supported for this mode");
		}
	} else {
		lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "ldr %1D, [%1S, #%O]", irn, irn, irn );
		lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* StackParam: (%1S + %O) -> %1D */",irn , irn, irn, get_irn_n(irn, 0));
		arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
	}
770
771
772
773
774
775
776
}

/************************************************************************/
/* emit                                                                 */
/************************************************************************/

static void emit_Jmp(ir_node *irn, void *env) {
777
	char cmd_buf[SNPRINTF_BUF_LEN];
778
	arm_emit_env_t *emit_env = env;
779
	FILE *F = emit_env->out;
780
	const ir_edge_t *edge = get_irn_out_edge_first(irn);
781
	const lc_arg_env_t *arm_env = arm_get_arg_env();
782
	ir_node *target_block = get_edge_src_irn(edge);
783
784
785

	lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "b BLOCK_%d", get_irn_node_nr(target_block));
	arm_fprintf_format(F, cmd_buf, "/* unconditional Jump */", irn);
786
787
}

Michael Beck's avatar
Michael Beck committed
788
789
790
791
792
793
static void emit_arm_fpaDbl2GP(const ir_node *n, arm_emit_env_t *env) {
  FILE *F = env->out;
  char cmd_buf[256];
  const lc_arg_env_t *arg_env = arm_get_arg_env();

  lc_esnprintf(arg_env, cmd_buf, 256, "stfd %1S, [sp, #-8]! ", n);
794
  arm_fprintf_format(F, cmd_buf, "/* Push fp to stack */", n);
795

Michael Beck's avatar
Michael Beck committed
796
  lc_esnprintf(arg_env, cmd_buf, 256, "ldmfd sp!, {%2D, %1D} ", n, n);
797
  arm_fprintf_format(F, cmd_buf, "/* Pop destination */", n);
798
799
}

Michael Beck's avatar
Michael Beck committed
800
801
802
static void emit_silence(ir_node *irn, void *env) {

}
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820


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

/**
 * 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
821
#define ARM_EMIT(a)  op_arm_##a->ops.generic = (op_func)emit_arm_##a
822
823
#define EMIT(a)      op_##a->ops.generic = (op_func)emit_##a
#define BE_EMIT(a)   op_be_##a->ops.generic = (op_func)emit_be_##a
824
#define SILENCE(a)   op_##a->ops.generic = (op_func)emit_silence
825
826
827
828
829
830
831
832

	/* 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
833
834
	ARM_EMIT(CondJmp);
	ARM_EMIT(CopyB);
835
836
837
838
// 	ARM_EMIT(CopyB_i);
//	ARM_EMIT(Const);
	ARM_EMIT(SymConst);
	ARM_EMIT(SwitchJmp);
Michael Beck's avatar
Michael Beck committed
839
	ARM_EMIT(fpaDbl2GP);
840
841
842
843
844
845
846
847
848
849
850
851

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

	/* firm emitter */
Michael Beck's avatar
Michael Beck committed
852
	EMIT(Jmp);
853
854
855

	/* noisy stuff */
#ifdef SILENCER
Michael Beck's avatar
Michael Beck committed
856
857
858
859
	SILENCE(Proj);
	SILENCE(Phi);
	SILENCE(be_Keep);
	SILENCE(be_CopyKeep);
860
861
862
863
864
#endif

#undef ARM_EMIT
#undef BE_EMIT
#undef EMIT
865
#undef SILENCE
866
867
}

Michael Beck's avatar
Michael Beck committed
868
869
typedef void (node_emitter)(const ir_node *, void *);

870
871
872
873
/**
 * Emits code for a node.
 */
static void arm_emit_node(const ir_node *irn, void *env) {
Michael Beck's avatar
Michael Beck committed
874
875
876
877
	arm_emit_env_t *emit_env = env;
	FILE           *F        = emit_env->out;
	ir_op          *op       = get_irn_op(irn);
	DEBUG_ONLY(firm_dbg_module_t *mod = emit_env->mod;)
878
879
880
881

	DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));

	if (op->ops.generic) {
Michael Beck's avatar
Michael Beck committed
882
883
		node_emitter *emit = (node_emitter *)op->ops.generic;
		emit(irn, env);
884
885
	}
	else {
Michael Beck's avatar
Michael Beck committed
886
		ir_fprintf(F, "\t%-35s /* %+F %G */\n", "", irn, irn);
887
888
889
890
891
892
893
894
895
896
	}
}

/**
 * Walks over the nodes in a block connected by scheduling edges
 * and emits code for each node.
 */
void arm_gen_block(ir_node *block, void *env) {
	ir_node *irn;

Christoph Mallon's avatar
Christoph Mallon committed
897
	fprintf(((arm_emit_env_t *)env)->out, "BLOCK_%ld:\n", get_irn_node_nr(block));
898
899
900
901
902
903
904
905
906
907
	sched_foreach(block, irn) {
		arm_emit_node(irn, env);
	}
}


/**
 * Emits code for function start.
 */
void arm_emit_start(FILE *F, ir_graph *irg) {
Michael Beck's avatar
Michael Beck committed
908
909
910
	entity *ent = get_irg_entity(irg);
	const char *irg_name = get_entity_ld_name(ent);
	arm_switch_section(F, SECTION_TEXT);
911
	fprintf(F, "\t.align  2\n");
Michael Beck's avatar
Michael Beck committed
912
913
914

	if (get_entity_visibility(ent) == visibility_external_visible)
		fprintf(F, "\t.global %s\n", irg_name);
915
916
917
918
919
920
921
	fprintf(F, "%s:\n", irg_name);
}

/**
 * Emits code for function end
 */
void arm_emit_end(FILE *F, ir_graph *irg) {
Michael Beck's avatar
Michael Beck committed
922
	fprintf(F, "\t.ident \"firmcc\"\n");
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
}

/**
 * Sets labels for control flow nodes (jump target)
 * TODO: Jump optimization
 */
void arm_gen_labels(ir_node *block, void *env) {
	ir_node *pred;
	int n = get_Block_n_cfgpreds(block);

	for (n--; n >= 0; n--) {
		pred = get_Block_cfgpred(block, n);
		set_irn_link(pred, block);
	}
}


/**
Michael Beck's avatar
Michael Beck committed
941
 * Main driver. Emits the code for one routine.
942
943
 */
void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg) {
Michael Beck's avatar
Michael Beck committed
944
	SymConstEntry *entry;
945
	arm_emit_env_t emit_env;
Michael Beck's avatar
Michael Beck committed
946
947
    ir_node **blk_sched;
    int i, n;
948
949
950
951

	emit_env.out      = F;
	emit_env.arch_env = cg->arch_env;
	emit_env.cg       = cg;
Michael Beck's avatar
Michael Beck committed
952
953
	emit_env.symbols  = NULL;
	obstack_init(&emit_env.obst);
954
	FIRM_DBG_REGISTER(emit_env.mod, "firm.be.arm.emit");
955
956
957
958
959
960

	/* set the global arch_env (needed by print hooks) */
	arch_env = cg->arch_env;

	arm_register_emitters();

Michael Beck's avatar
Michael Beck committed
961
	/* create the block schedule. For now, we don't need it earlier. */
962
	blk_sched = sched_create_block_schedule(cg->irg, cg->birg->exec_freq);
Michael Beck's avatar
Michael Beck committed
963

964
965
	arm_emit_start(F, irg);
	irg_block_walk_graph(irg, arm_gen_labels, NULL, &emit_env);
Michael Beck's avatar
Michael Beck committed
966
967
968
969
970
971
972
973
974
975
976
977
978
979

	n = ARR_LEN(blk_sched);
	for (i = 0; i < n;) {
		ir_node *block, *next_bl;

		block   = blk_sched[i];
		++i;
		next_bl = i < n ? blk_sched[i] : NULL;

		/* set here the link. the emitter expects to find the next block here */
		set_irn_link(block, next_bl);
		arm_gen_block(block, &emit_env);
	}

Michael Beck's avatar
Michael Beck committed
980
981
982
983
984
985
986
987
988
989
	/* emit SymConst values */
	if (emit_env.symbols)
		fprintf(F, "\t.align 2\n");

	for (entry = emit_env.symbols; entry; entry = entry->next) {
		fprintf(F, ".L%u:\n", entry->label);
		lc_efprintf(arm_get_arg_env(), F, "\t.word\t%C\n", entry->symconst);
	}

	obstack_free(&emit_env.obst, NULL);
990
}