arm_emitter.c 29.4 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
27
28
29
30
31
32
33
34
#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
35
#include "irtools.h"
36
37
38
39
#include "irprintf.h"
#include "irop_t.h"
#include "irprog_t.h"
#include "irargs_t.h"
Michael Beck's avatar
Michael Beck committed
40
#include "error.h"
Michael Beck's avatar
Michael Beck committed
41
#include "raw_bitset.h"
42
#include "dbginfo.h"
43
44

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

#include "arm_emitter.h"
51
#include "arm_optimize.h"
52
53
54
55
56
57
#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"

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

#define SNPRINTF_BUF_LEN 128

62
63
64
65
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

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

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

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

Michael Beck's avatar
Michael Beck committed
77
78
79
	/* 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
80

81
	reg = arch_get_irn_register(op);
Michael Beck's avatar
Michael Beck committed
82

Michael Beck's avatar
Michael Beck committed
83
	assert(reg && "no in register found");
Michael Beck's avatar
Michael Beck committed
84
85
86

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

		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
98
99
	return reg;
}
Michael Beck's avatar
Michael Beck committed
100

Matthias Braun's avatar
Matthias Braun committed
101

Michael Beck's avatar
Michael Beck committed
102
103
104
/**
 * Returns the register at out position pos.
 */
105
static const arch_register_t *get_out_reg(const ir_node *node, int pos)
Michael Beck's avatar
Michael Beck committed
106
107
108
109
110
111
112
113
114
115
{
    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) {
116
        reg = arch_get_irn_register(node);
Michael Beck's avatar
Michael Beck committed
117
    } else if (is_arm_irn(node)) {
118
        reg = arch_irn_get_register(node, pos);
Michael Beck's avatar
Michael Beck committed
119
120
121
122
123
124
125
    } 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) {
126
                reg = arch_get_irn_register(proj);
Michael Beck's avatar
Michael Beck committed
127
128
129
130
131
132
133
                break;
            }
        }
    }

    assert(reg && "no out register found");
    return reg;
Michael Beck's avatar
Michael Beck committed
134
}
135
136

/**
Michael Beck's avatar
Michael Beck committed
137
 * Emit the name of the source register at given input position.
138
 */
139
140
void arm_emit_source_register(const ir_node *node, int pos)
{
141
142
	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
143
}
144

Michael Beck's avatar
Michael Beck committed
145
146
147
/**
 * Emit the name of the destination register at given output position.
 */
148
149
void arm_emit_dest_register(const ir_node *node, int pos)
{
150
151
	const arch_register_t *reg = get_out_reg(node, pos);
	be_emit_string(arch_register_get_name(reg));
152
153
154
}

/**
Michael Beck's avatar
Michael Beck committed
155
 * Emit a node's offset.
156
 */
157
158
159
160
void arm_emit_offset(const ir_node *node)
{
	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
161

162
	be_emit_irprintf("0x%X", attr->offset);
163
164
165
}

/**
Michael Beck's avatar
Michael Beck committed
166
 * Emit the arm fpa instruction suffix depending on the mode.
167
 */
168
169
static void arm_emit_fpa_postfix(const ir_mode *mode)
{
Michael Beck's avatar
Michael Beck committed
170
	int bits = get_mode_size_bits(mode);
Michael Beck's avatar
Michael Beck committed
171
172
	char c = 'e';

Michael Beck's avatar
Michael Beck committed
173
	if (bits == 32)
Michael Beck's avatar
Michael Beck committed
174
		c = 's';
Michael Beck's avatar
Michael Beck committed
175
	else if (bits == 64)
Michael Beck's avatar
Michael Beck committed
176
177
		c = 'd';
	be_emit_char(c);
178
179
}

Michael Beck's avatar
Michael Beck committed
180
181
182
/**
 * Emit the instruction suffix depending on the mode.
 */
183
184
void arm_emit_mode(const ir_node *node)
{
Michael Beck's avatar
Michael Beck committed
185
186
187
188
189
190
191
192
	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);
	}
193
	arm_emit_fpa_postfix(mode);
Michael Beck's avatar
Michael Beck committed
194
195
}

196
/**
Michael Beck's avatar
Michael Beck committed
197
 * Emit a const or SymConst value.
198
 */
199
200
void arm_emit_immediate(const ir_node *node)
{
201
202
	const arm_attr_t *attr = get_arm_attr_const(node);

203
204
205
206
	if (ARM_GET_FPA_IMM(attr)) {
		/* TODO */
		//be_emit_irprintf("#%s", arm_get_fpa_imm_name(get_arm_imm_value(node)));
	} else {
Michael Beck's avatar
Michael Beck committed
207
		assert(!"not a Constant");
208
209
210
	}
}

211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
void arm_emit_load_mode(const ir_node *node)
{
	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);
	}
}

void arm_emit_store_mode(const ir_node *node)
{
	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);
	}
}


static void emit_shf_mod_name(arm_shift_modifier mod)
{
	switch (mod) {
	case ARM_SHF_ASR_REG:
	case ARM_SHF_ASR_IMM:
		be_emit_cstring("asr");
		return;
	case ARM_SHF_LSL_REG:
	case ARM_SHF_LSL_IMM:
		be_emit_cstring("lsl");
		return;
	case ARM_SHF_LSR_REG:
	case ARM_SHF_LSR_IMM:
		be_emit_cstring("lsr");
		return;
	case ARM_SHF_ROR_REG:
	case ARM_SHF_ROR_IMM:
		be_emit_cstring("ror");
		return;
	default:
		break;
	}
	panic("can't emit this shf_mod_name %d", (int) mod);
}

void arm_emit_shifter_operand(const ir_node *node)
{
	const arm_shifter_operand_t *attr = get_irn_generic_attr_const(node);

	switch (attr->shift_modifier) {
	case ARM_SHF_REG:
		arm_emit_source_register(node, get_irn_arity(node) - 1);
		return;
	case ARM_SHF_IMM: {
		unsigned val = attr->immediate_value;
		val = (val >> attr->shift_immediate)
			| (val << (32-attr->shift_immediate));
		val &= 0xFFFFFFFF;
		be_emit_irprintf("#0x%X", val);
		return;
	}
	case ARM_SHF_ASR_IMM:
	case ARM_SHF_LSL_IMM:
	case ARM_SHF_LSR_IMM:
	case ARM_SHF_ROR_IMM:
		arm_emit_source_register(node, get_irn_arity(node) - 1);
		be_emit_cstring(", ");
		emit_shf_mod_name(attr->shift_modifier);
		be_emit_irprintf(" #0x%X", attr->shift_immediate);
		return;

	case ARM_SHF_ASR_REG:
	case ARM_SHF_LSL_REG:
	case ARM_SHF_LSR_REG:
	case ARM_SHF_ROR_REG:
		arm_emit_source_register(node, get_irn_arity(node) - 2);
		be_emit_cstring(", ");
		emit_shf_mod_name(attr->shift_modifier);
		be_emit_cstring(" ");
		arm_emit_source_register(node, get_irn_arity(node) - 1);
		return;
Michael Beck's avatar
Michael Beck committed
302

303
304
305
306
	case ARM_SHF_RRX:
		arm_emit_source_register(node, get_irn_arity(node) - 1);
		panic("RRX shifter emitter TODO");
		return;
307

308
309
	case ARM_SHF_INVALID:
		break;
310
	}
311
	panic("Invalid shift_modifier while emitting %+F", node);
312
313
}

Michael Beck's avatar
Michael Beck committed
314
/** An entry in the sym_or_tv set. */
315
typedef struct sym_or_tv_t {
Michael Beck's avatar
Michael Beck committed
316
317
318
319
320
321
322
	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. */
323
} sym_or_tv_t;
Michael Beck's avatar
Michael Beck committed
324

Michael Beck's avatar
Michael Beck committed
325
326
/**
 * Returns a unique label. This number will not be used a second time.
327
 */
328
329
static unsigned get_unique_label(void)
{
Michael Beck's avatar
Michael Beck committed
330
331
	static unsigned id = 0;
	return ++id;
332
333
}

Michael Beck's avatar
Michael Beck committed
334
/**
Michael Beck's avatar
Michael Beck committed
335
 * Emit a SymConst.
Michael Beck's avatar
Michael Beck committed
336
 */
337
338
339
static void emit_arm_SymConst(const ir_node *irn)
{
	const arm_SymConst_attr_t *attr = get_arm_SymConst_attr_const(irn);
340
	sym_or_tv_t key, *entry;
Michael Beck's avatar
Michael Beck committed
341
342
	unsigned label;

343
	key.u.id     = get_entity_ld_ident(attr->entity);
Michael Beck's avatar
Michael Beck committed
344
345
	key.is_ident = 1;
	key.label    = 0;
346
	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
347
	if (entry->label == 0) {
Michael Beck's avatar
Michael Beck committed
348
		/* allocate a label */
Michael Beck's avatar
Michael Beck committed
349
		entry->label = get_unique_label();
Michael Beck's avatar
Michael Beck committed
350
	}
Michael Beck's avatar
Michael Beck committed
351
	label = entry->label;
Michael Beck's avatar
Michael Beck committed
352

Michael Beck's avatar
Michael Beck committed
353
	/* load the symbol indirect */
354
355
356
357
	be_emit_cstring("\tldr ");
	arm_emit_dest_register(irn, 0);
	be_emit_irprintf(", .L%u", label);
	be_emit_finish_line_gas(irn);
358
359
}

360
361
362
363
364
365
366
367
368
369
370
371
372
static void emit_arm_FrameAddr(const ir_node *irn)
{
	const arm_SymConst_attr_t *attr = get_irn_generic_attr_const(irn);

	be_emit_cstring("\tadd ");
	arm_emit_dest_register(irn, 0);
	be_emit_cstring(", ");
	arm_emit_source_register(irn, 0);
	be_emit_cstring(", ");
	be_emit_irprintf("#0x%X", attr->fp_offset);
	be_emit_finish_line_gas(irn);
}

Michael Beck's avatar
Michael Beck committed
373
374
375
/**
 * Emit a floating point fpa constant.
 */
376
377
static void emit_arm_fpaConst(const ir_node *irn)
{
378
	sym_or_tv_t key, *entry;
Michael Beck's avatar
Michael Beck committed
379
380
381
	unsigned label;
	ir_mode *mode;

Michael Beck's avatar
Michael Beck committed
382
	key.u.tv     = get_fpaConst_value(irn);
Michael Beck's avatar
Michael Beck committed
383
384
	key.is_ident = 0;
	key.label    = 0;
385
	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
386
387
388
389
390
391
392
393
	if (entry->label == 0) {
		/* allocate a label */
		entry->label = get_unique_label();
	}
	label = entry->label;

	/* load the tarval indirect */
	mode = get_irn_mode(irn);
394
395
396
	be_emit_cstring("\tldf");
	arm_emit_fpa_postfix(mode);
	be_emit_char(' ');
Michael Beck's avatar
Michael Beck committed
397

398
399
400
	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
401
402
}

Michael Beck's avatar
Michael Beck committed
403
404
405
/**
 * Returns the next block in a block schedule.
 */
406
407
static ir_node *sched_next_block(const ir_node *block)
{
Michael Beck's avatar
Michael Beck committed
408
409
410
    return get_irn_link(block);
}

411
412
413
/**
 * Returns the target block for a control flow node.
 */
414
415
static ir_node *get_cfop_target_block(const ir_node *irn)
{
416
417
418
419
420
421
	return get_irn_link(irn);
}

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

426
	be_gas_emit_block_name(block);
427
428
}

Michael Beck's avatar
Michael Beck committed
429
/**
Michael Beck's avatar
Michael Beck committed
430
 * Emit a Compare with conditional branch.
Michael Beck's avatar
Michael Beck committed
431
 */
432
433
static void emit_arm_B(const ir_node *irn)
{
434
	const ir_edge_t *edge;
435
436
437
438
	const ir_node *proj_true  = NULL;
	const ir_node *proj_false = NULL;
	const ir_node *block;
	const ir_node *next_block;
439
	ir_node *op1 = get_irn_n(irn, 0);
Michael Beck's avatar
Michael Beck committed
440
	const char *suffix;
Michael Beck's avatar
Michael Beck committed
441
	int proj_num = get_arm_CondJmp_proj_num(irn);
442
443
444
445
	const arm_cmp_attr_t *cmp_attr = get_irn_generic_attr_const(op1);
	bool is_signed = !cmp_attr->is_unsigned;

	assert(is_arm_Cmp(op1) || is_arm_Tst(op1));
446

Michael Beck's avatar
Michael Beck committed
447
448
449
	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
450
		if (nr == pn_Cond_true) {
451
			proj_true = proj;
452
		} else {
453
			proj_false = proj;
454
		}
Michael Beck's avatar
Michael Beck committed
455
	}
456

457
458
	if (cmp_attr->ins_permuted) {
		proj_num = get_mirrored_pnc(proj_num);
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
	}

	/* 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);
	}
478

479
480
	switch (proj_num) {
		case pn_Cmp_Eq:  suffix = "eq"; break;
481
482
483
484
		case pn_Cmp_Lt:  suffix = is_signed ? "lt" : "lo"; break;
		case pn_Cmp_Le:  suffix = is_signed ? "le" : "ls"; break;
		case pn_Cmp_Gt:  suffix = is_signed ? "gt" : "hi"; break;
		case pn_Cmp_Ge:  suffix = is_signed ? "ge" : "hs"; break;
485
486
		case pn_Cmp_Lg:  suffix = "ne"; break;
		case pn_Cmp_Leg: suffix = "al"; break;
487
		default: panic("Cmp has unsupported pnc");
488
489
490
491
492
493
494
495
496
497
498
499
500
	}

	/* 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 {
501
		be_emit_cstring("\tb ");
502
503
504
505
506
		arm_emit_cfop_target(proj_false);
		be_emit_finish_line_gas(proj_false);
	}
}

Michael Beck's avatar
Michael Beck committed
507
/** Sort register in ascending order. */
508
509
static int reg_cmp(const void *a, const void *b)
{
Matthias Braun's avatar
Matthias Braun committed
510
511
	const arch_register_t * const *ra = a;
	const arch_register_t * const *rb = b;
Michael Beck's avatar
Michael Beck committed
512
513
514
515

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

Michael Beck's avatar
Michael Beck committed
516
517
518
/**
 * Create the CopyB instruction sequence.
 */
519
520
521
522
static void emit_arm_CopyB(const ir_node *irn)
{
	const arm_CopyB_attr_t *attr = get_irn_generic_attr_const(irn);
	unsigned size = attr->size;
523

524
525
	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
526
527
528
529
530
	const char *t0, *t1, *t2, *t3;

	const arch_register_t *tmpregs[4];

	/* collect the temporary registers and sort them, we need ascending order */
531
532
533
	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
534
535
536
537
538
539
540
541
542
543
544
	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]);

545
546
547
548
	be_emit_cstring("/* MemCopy (");
	be_emit_string(src);
	be_emit_cstring(")->(");
	arm_emit_source_register(irn, 0);
Michael Beck's avatar
Michael Beck committed
549
	be_emit_irprintf(" [%u bytes], Uses ", size);
550
551
552
553
554
555
556
557
558
	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);
559

Michael Beck's avatar
Michael Beck committed
560
561
562
563
	assert(size > 0 && "CopyB needs size > 0" );

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

567
	size >>= 2;
Michael Beck's avatar
Michael Beck committed
568
	switch (size & 3) {
569
570
571
	case 0:
		break;
	case 1:
572
573
574
575
576
577
578
579
580
581
582
583
584
		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);
585
586
		break;
	case 2:
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
		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);
604
605
		break;
	case 3:
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
		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);
627
628
629
630
		break;
	}
	size >>= 2;
	while (size) {
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
		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);
656
657
658
659
		--size;
	}
}

660
661
static void emit_arm_SwitchJmp(const ir_node *irn)
{
662
663
664
665
666
667
	const ir_edge_t    *edge;
	ir_node            *proj;
	int i;
	ir_node **projs;
	int n_projs;
	int block_nr;
668
	ir_node *default_proj = NULL;
669
670

	block_nr = get_irn_node_nr(irn);
Michael Beck's avatar
Michael Beck committed
671
	n_projs = get_arm_SwitchJmp_n_projs(irn);
672

673
	projs = XMALLOCNZ(ir_node*, n_projs);
674
675
676
677
678

	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
679
		if (get_Proj_proj(proj) == get_arm_SwitchJmp_default_proj_num(irn))
680
			default_proj = proj;
681
682
683

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

Michael Beck's avatar
Michael Beck committed
686
687
688
689
	/*
	   CMP %1S, n_projs - 1
	   BHI default
	*/
690

691
692
693
694
	be_emit_cstring("\tcmp ");
	arm_emit_source_register(irn, 0);
	be_emit_irprintf(", #%u", n_projs - 1);
	be_emit_finish_line_gas(irn);
695

696
697
698
	be_emit_cstring("\tbhi ");
	arm_emit_cfop_target(default_proj);
	be_emit_finish_line_gas(default_proj);
699

Michael Beck's avatar
Michael Beck committed
700
701
702
703
704
	/*
	   LDR %r12, .TABLE_X_START
	   ADD %r12, %r12, [%1S, LSL #2]
	   LDR %r15, %r12
	 */
705

706
707
	be_emit_irprintf("\tldr %%r12, TABLE_%d_START", block_nr);
	be_emit_finish_line_gas(NULL);
708

709
710
711
712
	be_emit_irprintf("\tadd %%r12, %%r12, ");
	arm_emit_source_register(irn, 0);
	be_emit_cstring(", LSL #2");
	be_emit_finish_line_gas(NULL);
713

714
715
	be_emit_cstring("\tldr %r15, [%r12, #0]");
	be_emit_finish_line_gas(NULL);
716

717
718
719
720
721
722
	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);
723

Michael Beck's avatar
Michael Beck committed
724
	for (i = 0; i < n_projs; ++i) {
725
		proj = projs[i];
726
727
		if (proj == NULL) {
			proj = projs[get_arm_SwitchJmp_default_proj_num(irn)];
728
		}
729
730
731
		be_emit_cstring("\t.word\t");
		arm_emit_cfop_target(proj);
		be_emit_finish_line_gas(proj);
732
	}
733
734
	be_emit_irprintf("\t.align 2\n");
	be_emit_finish_line_gas(NULL);
735
736
737
738
739
740
741
	xfree(projs);
}

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

742
743
744
745
746
747
748
749
static void arm_emit_entity(ir_entity *entity)
{
	be_emit_ident(get_entity_ld_ident(entity));
}

static void emit_be_Call(const ir_node *irn)
{
	ir_entity *entity = be_Call_get_entity(irn);
Michael Beck's avatar
Michael Beck committed
750

751
752
753
754
	if (entity != NULL) {
		be_emit_cstring("\tbl ");
		arm_emit_entity(entity);
		be_emit_finish_line_gas(irn);
Michael Beck's avatar
Michael Beck committed
755
	} else {
756
757
758
		be_emit_cstring("\tmov lr, pc");
		be_emit_finish_line_gas(irn);
		be_emit_cstring("\tmov pc, ");
759
		arm_emit_source_register(irn, be_pos_Call_ptr);
760
		be_emit_finish_line_gas(irn);
Michael Beck's avatar
Michael Beck committed
761
	}
762
763
}

Michael Beck's avatar
Michael Beck committed
764
/** Emit an IncSP node */
765
766
static void emit_be_IncSP(const ir_node *irn)
{
767
	int offs = -be_get_IncSP_offset(irn);
768
769

	if (offs != 0) {
770
771
772
773
774
775
		if (offs < 0) {
			be_emit_cstring("\tsub ");
			offs = -offs;
		} else {
			be_emit_cstring("\tadd ");
		}
776
777
778
		arm_emit_dest_register(irn, 0);
		be_emit_cstring(", ");
		arm_emit_source_register(irn, 0);
779
		be_emit_irprintf(", #0x%X", offs);
780
	} else {
781
782
		/* omitted IncSP(0) */
		return;
783
	}
784
	be_emit_finish_line_gas(irn);
785
786
}

787
788
static void emit_be_Copy(const ir_node *irn)
{
789
790
	ir_mode *mode = get_irn_mode(irn);

791
	if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) {
792
		/* omitted Copy */
793
794
795
		return;
	}

796
	if (mode_is_float(mode)) {
797
		if (USE_FPA(cg->isa)) {
798
799
800
801
802
803
804
			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
805
		} else {
806
			assert(0 && "move not supported for this mode");
Michael Beck's avatar
Michael Beck committed
807
			panic("emit_be_Copy: move not supported for this mode");
808
		}
809
	} else if (mode_is_data(mode)) {
810
811
812
813
814
		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);
815
816
	} else {
		assert(0 && "move not supported for this mode");
Michael Beck's avatar
Michael Beck committed
817
		panic("emit_be_Copy: move not supported for this mode");
818
819
820
	}
}

821
822
static void emit_be_Perm(const ir_node *irn)
{
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
	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
846
847
}

848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
static void emit_be_MemPerm(const ir_node *node)
{
	int i;
	int memperm_arity;
	int sp_change = 0;

	/* TODO: this implementation is slower than necessary.
	   The longterm goal is however to avoid the memperm node completely */

	memperm_arity = be_get_MemPerm_entity_arity(node);
	if (memperm_arity > 12)
		panic("memperm with more than 12 inputs not supported yet");

	for (i = 0; i < memperm_arity; ++i) {
		int offset;
		ir_entity *entity = be_get_MemPerm_in_entity(node, i);

		/* spill register */
		be_emit_irprintf("\tstr r%d, [sp, #-4]!", i);
		be_emit_finish_line_gas(node);
		sp_change += 4;
		/* load from entity */
		offset = get_entity_offset(entity) + sp_change;
		be_emit_irprintf("\tldr r%d, [sp, #%d]", i, offset);
		be_emit_finish_line_gas(node);
	}

	for (i = memperm_arity-1; i >= 0; --i) {
		int        offset;
		ir_entity *entity = be_get_MemPerm_out_entity(node, i);

		/* store to new entity */
		offset = get_entity_offset(entity) + sp_change;
		be_emit_irprintf("\tstr r%d, [sp, #%d]", i, offset);
		be_emit_finish_line_gas(node);
		/* restore register */
		be_emit_irprintf("\tldr r%d, [sp], #4", i);
		sp_change -= 4;
		be_emit_finish_line_gas(node);
	}
	assert(sp_change == 0);
}

static void emit_be_Return(const ir_node *node)
{
	be_emit_cstring("\tmov pc, lr");
	be_emit_finish_line_gas(node);
}

897
898
899
900
/************************************************************************/
/* emit                                                                 */
/************************************************************************/

901
902
static void emit_arm_Jmp(const ir_node *node)
{
903
	ir_node *block, *next_block;
904

905
906
907
908
909
910
	/* 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) {
911
912
		be_emit_cstring("\tb ");
		arm_emit_cfop_target(node);
913
	} else {
914
915
916
		be_emit_cstring("\t/* fallthrough to ");
		arm_emit_cfop_target(node);
		be_emit_cstring(" */");
Michael Beck's avatar
Michael Beck committed
917
	}
918
	be_emit_finish_line_gas(node);
919
920
}

921
922
static void emit_arm_fpaDbl2GP(const ir_node *irn)
{
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
	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
938
}
939

940
941
static void emit_arm_LdTls(const ir_node *irn)
{
Matthias Braun's avatar
Matthias Braun committed
942
	(void) irn;
943
	panic("TLS not supported for this target");
944
945
946
	/* Er... our gcc does not support it... Install a newer toolchain. */
}

947
948
static void emit_nothing(const ir_node *irn)
{
Matthias Braun's avatar
Matthias Braun committed
949
	(void) irn;
Michael Beck's avatar
Michael Beck committed
950
951
952
953
954
}

/**
 * The type of a emitter function.
 */
955
typedef void (emit_func)(const ir_node *irn);
Michael Beck's avatar
Michael Beck committed
956
957
958
959

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

965
966
967
968
/**
 * Enters the emitter functions for handled nodes into the generic
 * pointer of an opcode.
 */
969
970
static void arm_register_emitters(void)
{
971
972
973
974
975
976
	/* 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();

977
	/* custom emitter */
978
	set_emitter(op_arm_B,          emit_arm_B);
979
980
981
	set_emitter(op_arm_CopyB,      emit_arm_CopyB);
	set_emitter(op_arm_fpaConst,   emit_arm_fpaConst);
	set_emitter(op_arm_fpaDbl2GP,  emit_arm_fpaDbl2GP);
982
	set_emitter(op_arm_FrameAddr,  emit_arm_FrameAddr);
983
984
985
986
987
988
	set_emitter(op_arm_Jmp,        emit_arm_Jmp);
	set_emitter(op_arm_LdTls,      emit_arm_LdTls);
	set_emitter(op_arm_SwitchJmp,  emit_arm_SwitchJmp);
	set_emitter(op_arm_SymConst,   emit_arm_SymConst);
	set_emitter(op_be_Call,        emit_be_Call);
	set_emitter(op_be_Copy,        emit_be_Copy);
989
	set_emitter(op_be_CopyKeep,    emit_be_Copy);
990
991
992
993
994
995
996
997
998
999
	set_emitter(op_be_IncSP,       emit_be_IncSP);
	set_emitter(op_be_MemPerm,     emit_be_MemPerm);
	set_emitter(op_be_Perm,        emit_be_Perm);
	set_emitter(op_be_Return,      emit_be_Return);

	/* no need to emit anything for the following nodes */
	set_emitter(op_Phi,            emit_nothing);
	set_emitter(op_be_Keep,        emit_nothing);
	set_emitter(op_be_Start,       emit_nothing);
	set_emitter(op_be_Barrier,     emit_nothing);
1000
1001
1002
1003
1004
}

/**
 * Emits code for a node.
 */
1005
1006
static void arm_emit_node(const ir_node *irn)
{
Michael Beck's avatar
Michael Beck committed
1007
	ir_op *op = get_irn_op(irn);
1008
1009

	if (op->ops.generic) {
Michael Beck's avatar
Michael Beck committed
1010
		emit_func *emit = (emit_func *)op->ops.generic;
1011
		be_dbg_set_dbg_info(get_irn_dbg_info(irn));
1012
		(*emit)(irn);
Michael Beck's avatar
Michael Beck committed
1013
	} else {
1014
1015
		panic("Error: No emit handler for node %+F (graph %+F)\n",
		      irn, current_ir_graph);
1016
1017
1018
	}
}

1019
1020
1021
/**
 * emit the block label if needed.
 */
1022
static void arm_emit_block_header(ir_node *block, ir_node *prev)
1023
1024
1025
1026
{
	int           n_cfgpreds;
	int           need_label;
	int           i, arity;
1027
	ir_exec_freq  *exec_freq = cg->birg->exec_freq;
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047

	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) {
1048
		be_gas_emit_block_name(block);
1049
		be_emit_char(':');
1050

1051
1052
		be_emit_pad_comment();
		be_emit_cstring("   /* preds:");
1053
1054
1055
1056
1057

		/* 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);
1058
			be_emit_irprintf(" %d", get_irn_node_nr(predblock));
1059
1060
		}
	} else {
1061
		be_emit_cstring("\t/* ");
1062
		be_gas_emit_block_name(block);
1063
		be_emit_cstring(": ");
1064
1065
	}
	if (exec_freq != NULL) {
1066
		be_emit_irprintf(" freq: %f",
1067
1068
		                 get_block_execfreq(exec_freq, block));
	}
1069
1070
	be_emit_cstring(" */\n");
	be_emit_write_line();
1071
1072
}

1073
1074
1075
1076
/**
 * Walks over the nodes in a block connected by scheduling edges
 * and emits code for each node.
 */
1077
1078
static void arm_gen_block(ir_node *block, ir_node *prev_block)
{
1079
1080
	ir_node *irn;

1081
	arm_emit_block_header(block, prev_block);
1082
	be_dbg_set_dbg_info(get_irn_dbg_info(block));
1083
	sched_foreach(block, irn) {
1084
		arm_emit_node(irn);
1085
1086
1087
1088
	}
}

/**
1089
 * Block-walker:
1090
1091
 * Sets labels for control flow nodes (jump target)
 */
1092
1093
static void arm_gen_labels(ir_node *block, void *env)
{
1094
1095
	ir_node *pred;
	int n = get_Block_n_cfgpreds(block);
1096
	(void)env;
1097
1098
1099
1100
1101
1102
1103

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

Michael Beck's avatar
Michael Beck committed
1104
1105
1106
/**
 * Compare two entries of the symbol or tarval set.
 */
1107
1108
static int cmp_sym_or_tv(const void *elt, const void *key, size_t size)
{
1109
1110
	const sym_or_tv_t *p1 = elt;
	const sym_or_tv_t *p2 = key;
Matthias Braun's avatar
Matthias Braun committed
1111
	(void) size;
Michael Beck's avatar
Michael Beck committed
1112
1113
1114
1115
1116

	/* as an identifier NEVER can point to a tarval, it's enough
	   to compare it this way */
	return p1->u.generic != p2->u.generic;
}
1117
1118

/**
Michael Beck's avatar
Michael Beck committed
1119
 * Main driver. Emits the code for one routine.
1120
 */
1121
1122
void arm_gen_routine(const arm_code_gen_t *arm_cg, ir_graph *irg)
{
Michael Beck's avatar
Michael Beck committed
1123
1124
1125
1126
	ir_node   **blk_sched;
	int       i, n;
	ir_node   *last_block = NULL;
	ir_entity *entity     = get_irg_entity(irg);
1127

1128
1129
	cg        = arm_cg;
	sym_or_tv = new_set(cmp_sym_or_tv, 8);
1130

1131
1132
	be_gas_elf_type_char = '%';

1133
1134
	arm_register_emitters();

Michael Beck's avatar
Michael Beck committed
1135
1136
	be_dbg_method_begin(entity, be_abi_get_stack_layout(cg->birg->abi));

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

1140
1141
	be_gas_emit_function_prolog(entity, 4);

1142
	irg_block_walk_graph(irg, arm_gen_labels, NULL, NULL);
Michael Beck's avatar
Michael Beck committed
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153

	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);
1154
		arm_gen_block(block, last_block);
1155
		last_block = block;
Michael Beck's avatar
Michael Beck committed
1156
1157
	}

1158
	be_gas_emit_function_epilog(entity);
Michael Beck's avatar
Michael Beck committed
1159
1160
	be_dbg_method_end();

Michael Beck's avatar
Michael Beck committed
1161
	/* emit SymConst values */
1162
1163
	if (set_count(sym_or_tv) > 0) {
		sym_or_tv_t *entry;
Michael Beck's avatar
Michael Beck committed
1164

1165
		be_emit_cstring("\t.align 2\n");
Michael Beck's avatar
Michael Beck committed
1166

1167
1168
		foreach_set(sym_or_tv, entry) {
			be_emit_irprintf(".L%u:\n", entry->label);
Michael Beck's avatar
Michael Beck committed
1169

Michael Beck's avatar
Michael Beck committed
1170
			if (entry->is_ident) {
1171
1172
1173
1174
				be_emit_cstring("\t.word\t");
				be_emit_ident(entry->u.id);
				be_emit_char('\n');
				be_emit_write_line();
Michael Beck's avatar
Michael Beck committed
1175
1176
1177
1178
1179
			} else {
				tarval *tv = entry->u.tv;
				int i, size = get_mode_size_bytes(get_tarval_mode(tv));
				unsigned v;

1180
				/* beware: ARM fpa uses big endian format */
Michael Beck's avatar
Michael Beck committed
1181
1182
1183
1184
1185
1186
				for (i = ((size + 3) & ~3) - 4; i >= 0; i -= 4) {
					/* get 32 bits */
					v =            get_tarval_sub_bits(tv, i+3);
					v = (v << 8) | get_tarval_sub_bits(tv, i+2);
					v = (v << 8) | get_tarval_sub_bits(tv, i+1);
					v = (v << 8) | get_tarval_sub_bits(tv, i+0);
1187
1188
					be_emit_irprintf("\t.word\t%u\n", v);
					be_emit_write_line();
Michael Beck's avatar
Michael Beck committed
1189
1190
				}
			}
Michael Beck's avatar
Michael Beck committed
1191
		}
1192
1193
		be_emit_char('\n');
		be_emit_write_line();
Michael Beck's avatar
Michael Beck committed
1194
	}
1195