mips_emitter.c 19.7 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
23
24
25
/**
 * @file
 * @brief   implementation of mips assembly emitter
 * @author  Matthias Braun, Mehdi
 * @version $Id$
 */
26
#include "config.h"
27
28
29
30
31
32
33
34
35
36
37
38

#include <limits.h>

#include "xmalloc.h"
#include "iredges.h"
#include "debug.h"
#include "irgwalk.h"
#include "irprintf.h"
#include "irop_t.h"
#include "irargs_t.h"
#include "irprog_t.h"
#include "irouts.h"
39
#include "tv.h"
40
#include "error.h"
41
42

#include "../besched.h"
43
#include "../benode.h"
44
#include "../beutil.h"
45
#include "../begnuas.h"
46
47
48
49
50
51
52

#include "mips_emitter.h"
#include "gen_mips_emitter.h"
#include "mips_nodes_attr.h"
#include "mips_new_nodes.h"
#include "mips_map_regs.h"

53
54
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

55
56
#define SNPRINTF_BUF_LEN 128

57
58
59
/**
 * Returns the register at in position pos.
 */
60
static const arch_register_t *get_in_reg(const ir_node *node, int pos)
61
{
62
63
	ir_node                *op;
	const arch_register_t  *reg = NULL;
64

65
	assert(get_irn_arity(node) > pos && "Invalid IN position");
66

67
68
69
	/* The out register of the operator at position pos is the
	   in register we need. */
	op = get_irn_n(node, pos);
70

71
	reg = arch_get_irn_register(op);
72

73
74
	assert(reg && "no in register found");
	return reg;
75
76
77
78
79
}

/**
 * Returns the register at out position pos.
 */
80
static const arch_register_t *get_out_reg(const ir_node *node, int pos)
81
{
82
83
84
85
86
87
88
89
90
	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) {
91
		reg = arch_get_irn_register(node);
92
	} else if (is_mips_irn(node)) {
93
		reg = arch_irn_get_register(node, pos);
94
95
96
97
98
99
100
	} 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) {
101
				reg = arch_get_irn_register(proj);
102
103
104
105
106
107
108
				break;
			}
		}
	}

	assert(reg && "no out register found");
	return reg;
109
}
110
111
112
113
114
115
116
117
118
119
120
121

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

122
123
124
/**
 * Emit the name of the source register at given input position.
 */
125
void mips_emit_source_register(const ir_node *node, int pos)
126
{
127
128
129
	const arch_register_t *reg = get_in_reg(node, pos);
	be_emit_char('$');
	be_emit_string(arch_register_get_name(reg));
130
131
}

132
133
134
/**
 * Emit the name of the destination register at given output position.
 */
135
void mips_emit_dest_register(const ir_node *node, int pos)
136
{
137
138
139
	const arch_register_t *reg = get_out_reg(node, pos);
	be_emit_char('$');
	be_emit_string(arch_register_get_name(reg));
140
141
142
}

#if 0
143
144
145
146
147
148
149
150
151
152
153
154
static const char *get_symconst_str(ir_node *node)
{
	ident *id;

	switch(get_SymConst_kind(node)) {
	case symconst_addr_name:
		id = get_SymConst_name(node);
		return get_id_str(id);
	case symconst_addr_ent:
		id = get_entity_ident(get_SymConst_entity(node));
		return get_id_str(id);
	default:
155
		panic("Unsupported SymConst kind");
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
	}

	return NULL;
}

/**
 * Return a const or symconst as string.
 */
static const char *node_const_to_str(ir_node *n)
{
	static char buf[64];
	const mips_attr_t *attr = get_mips_attr(n);
	long val;

	if(is_mips_load_r(n) || is_mips_store_r(n)) {
		mips_attr_t *attr = get_mips_attr(n);
		ir_node *symconst;

		if(attr->tv != NULL) {
			val = get_tarval_long(attr->tv);
			snprintf(buf, sizeof(buf), "%ld", val);

			return buf;
		}
		if(attr->stack_entity != NULL) {
			snprintf(buf, sizeof(buf), "%d", attr->stack_entity_offset);
			return buf;
		}

		symconst = get_irn_n(n, 1);
		assert(get_irn_opcode(symconst) == iro_SymConst);

		return get_symconst_str(symconst);
	} else if(is_mips_la(n)) {
		snprintf(buf, sizeof(buf), "%s", get_id_str(attr->symconst_id));
		return buf;
	} else if(is_mips_lli(n)) {
		assert(attr->tv != NULL);
		if(get_mode_sign(get_tarval_mode(attr->tv))) {
			long val = get_tarval_long(attr->tv);
Christian Würdig's avatar
Christian Würdig committed
196
			snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
197
198
		} else {
			unsigned long val = get_tarval_long(attr->tv);
Christian Würdig's avatar
Christian Würdig committed
199
			snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
200
201
202
203
204
205
206
207
		}

		return buf;
	} else if(is_mips_lui(n)) {
		assert(attr->tv != NULL);
		if(get_mode_sign(get_tarval_mode(attr->tv))) {
			long val = get_tarval_long(attr->tv);
			val = (val & 0xffff0000) >> 16;
Christian Würdig's avatar
Christian Würdig committed
208
			snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
209
210
211
		} else {
			unsigned long val = get_tarval_long(attr->tv);
			val = (val & 0xffff0000) >> 16;
Christian Würdig's avatar
Christian Würdig committed
212
			snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
213
214
215
216
217
218
219
220
221
222
223
		}

		return buf;
	}

	assert(attr->tv != NULL);
	val = get_tarval_long(attr->tv);
	snprintf(buf, sizeof(buf), "%ld", val);

	return buf;
}
224
#endif
225

226
void mips_emit_load_store_address(const ir_node *node, int pos)
227
228
229
{
	const mips_load_store_attr_t *attr = get_mips_load_store_attr_const(node);

230
231
232
	be_emit_irprintf("%d(", attr->offset);
	mips_emit_source_register(node, pos);
	be_emit_char(')');
233
234
}

235
void mips_emit_immediate_suffix(const ir_node *node, int pos)
236
237
238
{
	ir_node *op = get_irn_n(node, pos);
	if(is_mips_Immediate(op))
239
		be_emit_char('i');
240
241
}

242
void mips_emit_immediate(const ir_node *node)
243
{
244
245
246
247
	const mips_immediate_attr_t *attr = get_mips_immediate_attr_const(node);

	switch(attr->imm_type) {
	case MIPS_IMM_CONST:
248
		be_emit_irprintf("%d", attr->val);
249
250
		break;
	case MIPS_IMM_SYMCONST_LO:
251
252
		be_emit_cstring("%lo($");
		be_emit_ident(get_entity_ld_ident(attr->entity));
253
		if(attr->val != 0) {
254
			be_emit_irprintf("%+d", attr->val);
255
		}
256
		be_emit_char(')');
257
258
		break;
	case MIPS_IMM_SYMCONST_HI:
259
260
		be_emit_cstring("%hi($");
		be_emit_ident(get_entity_ld_ident(attr->entity));
261
		if(attr->val != 0) {
262
			be_emit_irprintf("%+d", attr->val);
263
		}
264
		be_emit_char(')');
265
266
267
268
269
		break;
	default:
		panic("invalid immediate type found");
	}
}
270

271
272
273
/**
 * Emit the name of the destination register at given output position.
 */
274
void mips_emit_source_register_or_immediate(const ir_node *node, int pos)
275
276
277
{
	const ir_node *op = get_irn_n(node, pos);
	if(is_mips_Immediate(op)) {
278
		mips_emit_immediate(op);
Matthias Braun's avatar
Matthias Braun committed
279
	} else {
280
		mips_emit_source_register(node, pos);
Matthias Braun's avatar
Matthias Braun committed
281
	}
282
283
}

284
#if 0
285
286
287
/*
 * Add a number to a prefix. This number will not be used a second time.
 */
288
static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
289
290
291
292
293
{
	static unsigned long id = 0;
	snprintf(buf, buflen, "%s%lu", prefix, ++id);
	return buf;
}
294
#endif
295
296

/************************************************************************/
Christian Würdig's avatar
Christian Würdig committed
297
/* ABI Handling                                                         */
298
299
/************************************************************************/

300
static
301
void mips_emit_IncSP(const ir_node *node)
302
{
Christian Würdig's avatar
Christian Würdig committed
303
304
	int   offset = be_get_IncSP_offset(node);

305
	if(offset == 0) {
306
		return;
307
	}
308

309
	if(offset > 0xffff || offset < -0xffff) {
310
		panic("stackframe > 2^16 bytes not supported yet");
311
312
313
	}

	if(offset > 0) {
314
		be_emit_irprintf("\tsubu $sp, $sp, %d", offset);
315
	} else {
316
		be_emit_irprintf("\taddu $sp, $sp, %d", -offset);
317
	}
318
	be_emit_finish_line_gas(node);
319
320
}

321
static void mips_emit_Copy(const ir_node *node)
322
{
323
324
325
326
327
	be_emit_cstring("\tmove ");
	mips_emit_dest_register(node, 0);
	be_emit_cstring(", ");
	mips_emit_source_register(node, 0);
	be_emit_finish_line_gas(node);
328
329
}

330
static void mips_emit_Return(const ir_node* node)
331
{
332
333
	be_emit_cstring("\tj $ra");
	be_emit_finish_line_gas(node);
334
335
}

336
static __attribute__((unused))
337
void mips_emit_nops(int n)
338
339
340
341
{
	int i;

	for(i = 0; i < n; ++i) {
342
343
		be_emit_cstring("\tnop\n");
		be_emit_write_line();
344
345
346
	}
}

347
static void mips_emit_Perm(const ir_node *node)
348
{
Matthias Braun's avatar
Matthias Braun committed
349
	assert(get_irn_arity(node) == 2);
350

351
352
353
354
355
356
357
	be_emit_cstring("\txor ");
	mips_emit_source_register(node, 0);
	be_emit_cstring(", ");
	mips_emit_source_register(node, 0);
	be_emit_cstring(", ");
	mips_emit_source_register(node, 1);
	be_emit_finish_line_gas(node);
358

359
	/* mips_emit_nops(3); */
360

361
362
363
364
365
366
367
	be_emit_cstring("\txor ");
	mips_emit_source_register(node, 1);
	be_emit_cstring(", ");
	mips_emit_source_register(node, 1);
	be_emit_cstring(", ");
	mips_emit_source_register(node, 0);
	be_emit_finish_line_gas(node);
368

369
	/* mips_emit_nops(3); */
370

371
372
373
374
375
376
377
	be_emit_cstring("\txor ");
	mips_emit_source_register(node, 0);
	be_emit_cstring(", ");
	mips_emit_source_register(node, 0);
	be_emit_cstring(", ");
	mips_emit_source_register(node, 1);
	be_emit_finish_line_gas(node);
378

379
	/* mips_emit_nops(3); */
380
381
382
}

/************************************************************************/
Christian Würdig's avatar
Christian Würdig committed
383
/* Calls                                                                */
384
385
/************************************************************************/

386
static void mips_emit_Call(const ir_node *node)
387
{
Michael Beck's avatar
Michael Beck committed
388
389
	ir_entity *callee;

390
	be_emit_cstring("\tjal ");
391

Michael Beck's avatar
Michael Beck committed
392
393
	/* call of immediate value (label) */
	callee = be_Call_get_entity(node);
394
	if(callee != NULL) {
395
		be_emit_ident(get_entity_ld_ident(callee));
396
	} else {
397
		mips_emit_source_register(node, be_pos_Call_ptr);
398
	}
399
	be_emit_finish_line_gas(node);
400
401
402
403
404
405
406
407
408
409
410
}

/************************************************************************
 *      _
 *     | |_   _ _ __ ___  _ __  ___
 *  _  | | | | | '_ ` _ \| '_ \/ __|
 * | |_| | |_| | | | | | | |_) \__ \
 *  \___/ \__,_|_| |_| |_| .__/|___/
 *                       |_|
 ************************************************************************/

411
static void mips_emit_Jump(const ir_node *node)
412
413
{
	const ir_node *block = get_irn_link(node);
414
415
	assert(is_Block(block));

416
	be_emit_cstring("\tb ");
417
	be_gas_emit_block_name(block);
418
	be_emit_finish_line_gas(node);
419
420
}

Matthias Braun's avatar
Matthias Braun committed
421
ir_node *mips_get_jump_block(const ir_node* node, long projn)
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
{
	const ir_edge_t *oute;
	for(oute = get_irn_out_edge_first(node); oute != NULL;
	    oute = get_irn_out_edge_next(node, oute)) {
		ir_node *proj = get_edge_src_irn(oute);
		long n;
		assert(is_Proj(proj));

		n = get_Proj_proj(proj);
		if(n == projn)
			return get_irn_link(proj);
	}

	return NULL;
}

438
void mips_emit_jump_target_proj(const ir_node *node, long projn)
439
440
441
442
{
	ir_node *jumpblock = mips_get_jump_block(node, projn);
	assert(jumpblock != NULL);

443
	be_gas_emit_block_name(jumpblock);
444
445
}

446
void mips_emit_jump_target(const ir_node *node)
447
448
449
450
{
	ir_node *jumpblock = get_irn_link(node);
	assert(jumpblock != NULL);

451
	be_gas_emit_block_name(jumpblock);
452
453
}

454
void mips_emit_jump_or_fallthrough(const ir_node *node, long pn)
Matthias Braun's avatar
Matthias Braun committed
455
456
457
458
459
{
	ir_node *jumpblock = mips_get_jump_block(node, pn);
	assert(jumpblock != NULL);

	/* TODO: use fallthrough when possible */
460
	be_emit_cstring("b ");
461
	be_gas_emit_block_name(jumpblock);
Matthias Braun's avatar
Matthias Braun committed
462
463
}

464
/************************************************************************
465
466
467
468
469
470
 *  ____          _ _       _         _                                 *
 * / ___|_      _(_) |_ ___| |__     | |_   _ _ __ ___  _ __            *
 * \___ \ \ /\ / / | __/ __| '_ \ _  | | | | | '_ ` _ \| '_ \           *
 *  ___) \ V  V /| | || (__| | | | |_| | |_| | | | | | | |_) |          *
 * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/           *
 *                                                     |_|              *
471
472
473
 *                                                                      *
 ************************************************************************/

474
#if 0
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
/* jump table entry (target and corresponding number) */
typedef struct _branch_t {
	ir_node *target;
	int      value;
} branch_t;

/* jump table for switch generation */
typedef struct _jmp_tbl_t {
	ir_node  *defBlock;        /**< default target */
	int       min_value;       /**< smallest switch case */
	int       max_value;       /**< largest switch case */
	int       num_branches;    /**< number of jumps */
	char     *label;           /**< label of the jump table */
	branch_t *branches;        /**< jump array */
} jmp_tbl_t;

/**
 * Compare two variables of type branch_t. Used to sort all switch cases
 */
494
495
static int mips_cmp_branch_t(const void *a, const void *b)
{
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
	branch_t *b1 = (branch_t *)a;
	branch_t *b2 = (branch_t *)b;

	if (b1->value <= b2->value)
		return -1;
	else
		return 1;
}

const char* mips_get_jumptbl_label(const ir_node* switchjmp)
{
	static char buf[64];
	snprintf(buf, sizeof(buf), "__JUMPTBL%ld", get_irn_node_nr(switchjmp));

	return buf;
}

/**
 * Emits code for a SwitchJmp (creates a jump table if
 * possible otherwise a cmp-jmp cascade). Stolen from ia32
 */
517
518
void emit_mips_jump_table(const ir_node *irn)
{
519
520
521
522
523
	int                lastval, i, i2, pn;
	jmp_tbl_t          tbl;
	ir_node           *proj;
	const ir_edge_t   *edge;
	const mips_attr_t *attr = get_mips_attr_const(irn);
524
525

	/* fill the table structure */
526
	tbl.label        = XMALLOCN(char, SNPRINTF_BUF_LEN);
527
528
529
	tbl.label        = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
	tbl.defBlock     = NULL;
	tbl.num_branches = get_irn_n_edges(irn);
530
	tbl.branches     = XMALLOCNZ(branch_t, tbl.num_branches);
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
	tbl.min_value    = INT_MAX;
	tbl.max_value    = INT_MIN;

	i = 0;
	/* go over all proj's and collect them */
	foreach_out_edge(irn, edge) {
		proj = get_edge_src_irn(edge);
		assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");

		pn = get_Proj_proj(proj);

		/* create branch entry */
		tbl.branches[i].target = get_irn_link(proj);
		tbl.branches[i].value  = pn;

		tbl.min_value = pn < tbl.min_value ? pn : tbl.min_value;
		tbl.max_value = pn > tbl.max_value ? pn : tbl.max_value;

		i++;
	}

	/* sort the branches by their number */
	qsort(tbl.branches, tbl.num_branches, sizeof(tbl.branches[0]), mips_cmp_branch_t);

555
556
557
	be_emit_string(mips_get_jumptbl_label(irn));
	be_emit_cstring(":\n");
	be_emit_write_line();
558
559
560
561
562
563
	lastval = tbl.min_value;
	for(i = 0; i < tbl.num_branches; ++i) {
		const branch_t *branch = &tbl.branches[i];
		int value = branch->value;

		for(i2 = lastval + 1; i2 < value; ++i2) {
564
565
566
567
			be_emit_cstring("\t.word ");
			be_emit_ident(get_entity_ld_ident(attr->symconst));
			be_emit_char('\n');
			be_emit_write_line();
568
569
		}

570
		be_emit_cstring("\t.word ");
571
		be_gas_emit_block_name(branch->target);
572
573
		be_emit_char('\n');
		be_emit_write_line();
574

575
576
577
578
579
580
581
582
583
		lastval = branch->value;
	}

	if (tbl.label)
		free(tbl.label);
	if (tbl.branches)
		free(tbl.branches);
}

584
static void dump_jump_tables(ir_node* node, void *data)
585
{
586
	(void) data;
587
588
589

	// emit jump tables
	if(is_mips_SwitchJump(node)) {
590
591
		be_emit_cstring(".data\n");
		be_emit_write_line();
592

593
		emit_mips_jump_table(node);
594

595
596
		be_emit_cstring(".text\n");
		be_emit_write_line();
597
598
	}
}
599
#endif
600
601
602
603
604
605
606
607
608
609
610

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

611
static void mips_emit_nothing(const ir_node *node)
Matthias Braun's avatar
Matthias Braun committed
612
613
614
615
{
	(void) node;
}

616
static void mips_emit_this_shouldnt_happen(const ir_node *node)
617
{
Matthias Braun's avatar
Matthias Braun committed
618
	panic("Found non-lowered node %+F while emitting", node);
619
620
}

621
622
623
/**
 * The type of a emitter function.
 */
624
typedef void (*emit_func) (const ir_node *);
Matthias Braun's avatar
Matthias Braun committed
625

626
627
628
/**
 * Set a node emitter. Make it a bit more type safe.
 */
629
630
static void register_emitter(ir_op *op, emit_func func)
{
Matthias Braun's avatar
Matthias Braun committed
631
	op->ops.generic = (op_func) func;
632
633
634
635
636
}

/**
 * Register emitter functions for mips backend
 */
637
638
void mips_register_emitters(void)
{
639
640
641
642
643
644
	/* first clear the generic function pointer for all ops */
	clear_irp_opcodes_generic_func();

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

645
	/* benode emitter */
Matthias Braun's avatar
Matthias Braun committed
646
647
648
649
650
651
652
	register_emitter(op_be_IncSP, mips_emit_IncSP);
	register_emitter(op_be_AddSP, mips_emit_this_shouldnt_happen);
	register_emitter(op_be_Call, mips_emit_Call);
	register_emitter(op_be_Copy, mips_emit_Copy);
	register_emitter(op_be_Keep, mips_emit_nothing);
	register_emitter(op_be_Barrier, mips_emit_nothing);
	register_emitter(op_be_Return, mips_emit_Return);
653
	register_emitter(op_be_Start, mips_emit_nothing);
Matthias Braun's avatar
Matthias Braun committed
654
655
656
657
658
659
660
661
662
663
	register_emitter(op_be_Spill, mips_emit_this_shouldnt_happen);
	register_emitter(op_be_Reload, mips_emit_this_shouldnt_happen);
	register_emitter(op_be_Perm, mips_emit_Perm);

	register_emitter(op_Proj, mips_emit_nothing);
	register_emitter(op_SymConst, mips_emit_this_shouldnt_happen);
	register_emitter(op_Const, mips_emit_this_shouldnt_happen);
	register_emitter(op_Jmp, mips_emit_Jump);
	register_emitter(op_Cmp, mips_emit_this_shouldnt_happen);
	register_emitter(op_Cond, mips_emit_this_shouldnt_happen);
Matthias Braun's avatar
Matthias Braun committed
664
	register_emitter(op_Phi, mips_emit_nothing);
665
666
667
668
669
}

/**
 * Emits assembly for a single node
 */
670
static void mips_emit_node(const ir_node *node)
671
{
672
	ir_op *op = get_irn_op(node);
673
674
675

	if (op->ops.generic) {
		emit_func emit = (emit_func) op->ops.generic;
676
		(*emit) (node);
677
	} else {
Matthias Braun's avatar
Matthias Braun committed
678
		panic("No emitter defined for node %+F", node);
679
680
681
682
683
684
685
	}
}

/**
 * Walks over the nodes in a block connected by scheduling edges
 * and emits code for each node.
 */
686
void mips_gen_block(const ir_node *block)
687
{
688
	ir_node *node;
689
690
691
692

	if (! is_Block(block))
		return;

693
	be_gas_emit_block_name(block);
694
695
	be_emit_cstring(":\n");
	be_emit_write_line();
696
697

	sched_foreach(block, node) {
698
		mips_emit_node(node);
699
	}
700

701
702
	be_emit_char('\n');
	be_emit_write_line();
703
704
705
706
707
}

/**
 * Emits code for function start.
 */
708
void mips_emit_func_prolog(ir_graph *irg)
709
{
710
	ident *irg_ident = get_entity_ld_ident(get_irg_entity(irg));
711
712

	// dump jump tables
713
	//irg_walk_graph(irg, NULL, dump_jump_tables, env);
714

715
716
	be_emit_write_line();
	be_gas_emit_switch_section(GAS_SECTION_TEXT);
717

718
	be_emit_cstring("\t.balign\t4\n");
719

720
721
722
	be_emit_cstring("\t.global\t");
	be_emit_ident(irg_ident);
	be_emit_char('\n');
723

724
	be_emit_cstring("\t.set\tnomips16\n");
725

726
727
728
	be_emit_cstring("\t.ent\t");
	be_emit_ident(irg_ident);
	be_emit_char('\n');
729

730
731
	be_emit_ident(irg_ident);
	be_emit_cstring(":\n");
732

733
734
735
	be_emit_cstring("\t.frame\t$fp, 24, $ra\n");
	be_emit_cstring("\t.mask\t0xc0000000, -4\n");
	be_emit_cstring("\t.fmask\t0x00000000, 0\n");
736

737
	be_emit_write_line();
738
739
740
741
742
}

/**
 * Emits code for function end
 */
743
void mips_emit_func_epilog(ir_graph *irg)
744
{
745
746
	ident *irg_ident = get_entity_ident(get_irg_entity(irg));

747
748
749
750
	be_emit_cstring("\t.end\t");
	be_emit_ident(irg_ident);
	be_emit_char('\n');
	be_emit_write_line();
751
752
753
754
755
756
757
758
759
}

/**
 * Sets labels for control flow nodes (jump target)
 */
void mips_gen_labels(ir_node *block, void *env)
{
	ir_node *pred;
	int n = get_Block_n_cfgpreds(block);
Matthias Braun's avatar
Matthias Braun committed
760
	(void) env;
761
762
763
764
765
766
767
768
769
770

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

/**
 * Main driver
 */
771
void mips_gen_routine(mips_code_gen_t *mips_cg, ir_graph *irg)
772
773
774
{
	int i, n;

775
	mips_register_emitters();
776

777
	irg_block_walk_graph(irg, mips_gen_labels, NULL, NULL);
778

779
	mips_emit_func_prolog(irg);
780

781
	n = ARR_LEN(mips_cg->block_schedule);
Matthias Braun's avatar
Matthias Braun committed
782
	for (i = 0; i < n; ++i) {
783
		ir_node *block = mips_cg->block_schedule[i];
784
		mips_gen_block(block);
785
786
	}

787
	mips_emit_func_epilog(irg);
788
789
790
791
792
}

void mips_init_emitter(void)
{
	FIRM_DBG_REGISTER(dbg, "firm.be.mips.emitter");
793
}