mips_emitter.c 20.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
#ifdef HAVE_CONFIG_H
27
#include "config.h"
28
29
30
31
32
33
34
35
36
37
38
39
40
#endif

#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"
41
#include "tv.h"
42
#include "error.h"
43
44
45
46

#include "../besched.h"
#include "../benode_t.h"
#include "../beutil.h"
47
#include "../begnuas.h"
48
49
50
51
52
53
54

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

55
56
DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)

Michael Beck's avatar
Michael Beck committed
57
58
#define BLOCK_PREFIX ".L"

59
60
#define SNPRINTF_BUF_LEN 128

61
62
63
64
static const mips_isa_t      *isa;
static const arch_env_t      *arch_env;
static const mips_code_gen_t *cg;

65
66
67
/**
 * Returns the register at in position pos.
 */
68
static const arch_register_t *get_in_reg(const ir_node *node, int pos)
69
{
70
71
	ir_node                *op;
	const arch_register_t  *reg = NULL;
72

73
	assert(get_irn_arity(node) > pos && "Invalid IN position");
74

75
76
77
	/* The out register of the operator at position pos is the
	   in register we need. */
	op = get_irn_n(node, pos);
78

79
	reg = arch_get_irn_register(arch_env, op);
80

81
82
	assert(reg && "no in register found");
	return reg;
83
84
85
86
87
}

/**
 * Returns the register at out position pos.
 */
88
static const arch_register_t *get_out_reg(const ir_node *node, int pos)
89
{
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
	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) {
		reg = arch_get_irn_register(arch_env, node);
	} else if (is_mips_irn(node)) {
		reg = get_mips_out_reg(node, pos);
	} 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) {
				reg = arch_get_irn_register(arch_env, proj);
				break;
			}
		}
	}

	assert(reg && "no out register found");
	return reg;
117
}
118
119
120
121
122
123
124
125
126
127
128
129

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

130
131
132
/**
 * Emit the name of the source register at given input position.
 */
133
void mips_emit_source_register(const ir_node *node, int pos)
134
{
135
136
137
	const arch_register_t *reg = get_in_reg(node, pos);
	be_emit_char('$');
	be_emit_string(arch_register_get_name(reg));
138
139
}

140
141
142
/**
 * Emit the name of the destination register at given output position.
 */
143
void mips_emit_dest_register(const ir_node *node, int pos)
144
{
145
146
147
	const arch_register_t *reg = get_out_reg(node, pos);
	be_emit_char('$');
	be_emit_string(arch_register_get_name(reg));
148
149
150
}

#if 0
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
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:
		assert(0);
	}

	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
204
			snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
205
206
		} else {
			unsigned long val = get_tarval_long(attr->tv);
Christian Würdig's avatar
Christian Würdig committed
207
			snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
208
209
210
211
212
213
214
215
		}

		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
216
			snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
217
218
219
		} else {
			unsigned long val = get_tarval_long(attr->tv);
			val = (val & 0xffff0000) >> 16;
Christian Würdig's avatar
Christian Würdig committed
220
			snprintf(buf, sizeof(buf), "0x%04lX", val & 0xffff);
221
222
223
224
225
226
227
228
229
230
231
		}

		return buf;
	}

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

	return buf;
}
232
#endif
233

234
void mips_emit_load_store_address(const ir_node *node, int pos)
235
236
237
{
	const mips_load_store_attr_t *attr = get_mips_load_store_attr_const(node);

238
239
240
	be_emit_irprintf("%d(", attr->offset);
	mips_emit_source_register(node, pos);
	be_emit_char(')');
241
242
}

243
void mips_emit_immediate_suffix(const ir_node *node, int pos)
244
245
246
{
	ir_node *op = get_irn_n(node, pos);
	if(is_mips_Immediate(op))
247
		be_emit_char('i');
248
249
}

250
void mips_emit_immediate(const ir_node *node)
251
{
252
253
254
255
	const mips_immediate_attr_t *attr = get_mips_immediate_attr_const(node);

	switch(attr->imm_type) {
	case MIPS_IMM_CONST:
256
		be_emit_irprintf("%d", attr->val);
257
258
		break;
	case MIPS_IMM_SYMCONST_LO:
259
260
		be_emit_cstring("%lo($");
		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
		break;
	case MIPS_IMM_SYMCONST_HI:
267
268
		be_emit_cstring("%hi($");
		be_emit_ident(get_entity_ld_ident(attr->entity));
269
		if(attr->val != 0) {
270
			be_emit_irprintf("%+d", attr->val);
271
		}
272
		be_emit_char(')');
273
274
275
276
277
		break;
	default:
		panic("invalid immediate type found");
	}
}
278

279
280
281
/**
 * Emit the name of the destination register at given output position.
 */
282
void mips_emit_source_register_or_immediate(const ir_node *node, int pos)
283
284
285
{
	const ir_node *op = get_irn_n(node, pos);
	if(is_mips_Immediate(op)) {
286
		mips_emit_immediate(op);
Matthias Braun's avatar
Matthias Braun committed
287
	} else {
288
		mips_emit_source_register(node, pos);
Matthias Braun's avatar
Matthias Braun committed
289
	}
290
291
}

292
#if 0
293
294
295
/*
 * Add a number to a prefix. This number will not be used a second time.
 */
296
static char *get_unique_label(char *buf, size_t buflen, const char *prefix)
297
298
299
300
301
{
	static unsigned long id = 0;
	snprintf(buf, buflen, "%s%lu", prefix, ++id);
	return buf;
}
302
#endif
303
304

/************************************************************************/
Christian Würdig's avatar
Christian Würdig committed
305
/* ABI Handling                                                         */
306
307
/************************************************************************/

308
static
309
void mips_emit_IncSP(const ir_node *node)
310
{
Christian Würdig's avatar
Christian Würdig committed
311
312
	int   offset = be_get_IncSP_offset(node);

313
	if(offset == 0) {
314
315
		be_emit_cstring("\t/* omitted IncSP with 0 */");
		be_emit_finish_line_gas(node);
316
		return;
317
	}
318

319
320
321
322
323
	if(offset > 0xffff || offset < -0xffff) {
		panic("stackframe > 2^16 bytes not supported yet\n");
	}

	if(offset > 0) {
324
		be_emit_irprintf("\tsubu $sp, $sp, %d", offset);
325
	} else {
326
		be_emit_irprintf("\taddu $sp, $sp, %d", -offset);
327
	}
328
	be_emit_finish_line_gas(node);
329
330
}

331
static void mips_emit_Copy(const ir_node *node)
332
{
333
334
335
336
337
	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);
338
339
}

340
static void mips_emit_Return(const ir_node* node)
341
{
342
343
	be_emit_cstring("\tj $ra");
	be_emit_finish_line_gas(node);
344
345
}

346
static __attribute__((unused))
347
void mips_emit_nops(int n)
348
349
350
351
{
	int i;

	for(i = 0; i < n; ++i) {
352
353
		be_emit_cstring("\tnop\n");
		be_emit_write_line();
354
355
356
	}
}

357
static void mips_emit_Perm(const ir_node *node)
358
{
Matthias Braun's avatar
Matthias Braun committed
359
	assert(get_irn_arity(node) == 2);
360

361
362
363
364
365
366
367
	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);
368

369
	/* mips_emit_nops(3); */
370

371
372
373
374
375
376
377
	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);
378

379
	/* mips_emit_nops(3); */
380

381
382
383
384
385
386
387
	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);
388

389
	/* mips_emit_nops(3); */
390
391
392
}

/************************************************************************/
Christian Würdig's avatar
Christian Würdig committed
393
/* Calls                                                                */
394
395
/************************************************************************/

396
static void mips_emit_Call(const ir_node *node)
397
{
Michael Beck's avatar
Michael Beck committed
398
399
	ir_entity *callee;

400
	be_emit_cstring("\tjal ");
401

Michael Beck's avatar
Michael Beck committed
402
403
	/* call of immediate value (label) */
	callee = be_Call_get_entity(node);
404
	if(callee != NULL) {
405
		be_emit_ident(get_entity_ld_ident(callee));
406
	} else {
407
		mips_emit_source_register(node, be_pos_Call_ptr);
408
	}
409
	be_emit_finish_line_gas(node);
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
}

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

const char* mips_get_block_label(const ir_node* block)
{
	static char buf[64];
	snprintf(buf, sizeof(buf), "BLOCK_%ld", get_irn_node_nr(block));

	return buf;
}

429
430
431
/**
 * Emits a block label from the given block.
 */
432
static void mips_emit_block_label(const ir_node *block)
433
{
Michael Beck's avatar
Michael Beck committed
434
	if (has_Block_label(block)) {
435
		be_emit_string(be_gas_block_label_prefix());
436
		be_emit_irprintf("%lu", get_Block_label(block));
Michael Beck's avatar
Michael Beck committed
437
	} else {
438
		be_emit_cstring(BLOCK_PREFIX);
439
		be_emit_irprintf("%ld", get_irn_node_nr(block));
Michael Beck's avatar
Michael Beck committed
440
441

	}
442
}
443

444
static void mips_emit_Jump(const ir_node *node)
445
446
{
	const ir_node *block = get_irn_link(node);
447
448
	assert(is_Block(block));

449
450
451
	be_emit_cstring("\tb ");
	mips_emit_block_label(block);
	be_emit_finish_line_gas(node);
452
453
}

Matthias Braun's avatar
Matthias Braun committed
454
ir_node *mips_get_jump_block(const ir_node* node, long projn)
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
{
	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;
}

471
void mips_emit_jump_target_proj(const ir_node *node, long projn)
472
473
474
475
{
	ir_node *jumpblock = mips_get_jump_block(node, projn);
	assert(jumpblock != NULL);

476
	mips_emit_block_label(jumpblock);
477
478
}

479
void mips_emit_jump_target(const ir_node *node)
480
481
482
483
{
	ir_node *jumpblock = get_irn_link(node);
	assert(jumpblock != NULL);

484
	mips_emit_block_label(jumpblock);
485
486
}

487
void mips_emit_jump_or_fallthrough(const ir_node *node, long pn)
Matthias Braun's avatar
Matthias Braun committed
488
489
490
491
492
{
	ir_node *jumpblock = mips_get_jump_block(node, pn);
	assert(jumpblock != NULL);

	/* TODO: use fallthrough when possible */
493
494
	be_emit_cstring("b ");
	mips_emit_block_label(jumpblock);
Matthias Braun's avatar
Matthias Braun committed
495
496
}

497
/************************************************************************
498
499
500
501
502
503
 *  ____          _ _       _         _                                 *
 * / ___|_      _(_) |_ ___| |__     | |_   _ _ __ ___  _ __            *
 * \___ \ \ /\ / / | __/ __| '_ \ _  | | | | | '_ ` _ \| '_ \           *
 *  ___) \ V  V /| | || (__| | | | |_| | |_| | | | | | | |_) |          *
 * |____/ \_/\_/ |_|\__\___|_| |_|\___/ \__,_|_| |_| |_| .__/           *
 *                                                     |_|              *
504
505
506
 *                                                                      *
 ************************************************************************/

507
#if 0
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
/* 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
 */
527
528
static int mips_cmp_branch_t(const void *a, const void *b)
{
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
	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
 */
550
551
void emit_mips_jump_table(const ir_node *irn)
{
552
553
554
555
556
	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);
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587

	/* fill the table structure */
	tbl.label        = xmalloc(SNPRINTF_BUF_LEN);
	tbl.label        = get_unique_label(tbl.label, SNPRINTF_BUF_LEN, "JMPTBL_");
	tbl.defBlock     = NULL;
	tbl.num_branches = get_irn_n_edges(irn);
	tbl.branches     = xcalloc(tbl.num_branches, sizeof(tbl.branches[0]));
	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);

588
589
590
	be_emit_string(mips_get_jumptbl_label(irn));
	be_emit_cstring(":\n");
	be_emit_write_line();
591
592
593
594
595
596
	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) {
597
598
599
600
			be_emit_cstring("\t.word ");
			be_emit_ident(get_entity_ld_ident(attr->symconst));
			be_emit_char('\n');
			be_emit_write_line();
601
602
		}

603
604
605
606
		be_emit_cstring("\t.word ");
		mips_emit_block_label(branch->target);
		be_emit_char('\n');
		be_emit_write_line();
607

608
609
610
611
612
613
614
615
616
		lastval = branch->value;
	}

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

617
static void dump_jump_tables(ir_node* node, void *data)
618
{
619
	(void) data;
620
621
622

	// emit jump tables
	if(is_mips_SwitchJump(node)) {
623
624
		be_emit_cstring(".data\n");
		be_emit_write_line();
625

626
		emit_mips_jump_table(node);
627

628
629
		be_emit_cstring(".text\n");
		be_emit_write_line();
630
631
	}
}
632
#endif
633
634
635
636
637
638
639
640
641
642
643

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

644
static void mips_emit_nothing(const ir_node *node)
Matthias Braun's avatar
Matthias Braun committed
645
646
647
648
{
	(void) node;
}

649
static void mips_emit_this_shouldnt_happen(const ir_node *node)
650
{
Matthias Braun's avatar
Matthias Braun committed
651
	panic("Found non-lowered node %+F while emitting", node);
652
653
}

654
655
656
/**
 * The type of a emitter function.
 */
657
typedef void (*emit_func) (const ir_node *);
Matthias Braun's avatar
Matthias Braun committed
658

659
660
661
/**
 * Set a node emitter. Make it a bit more type safe.
 */
662
663
static void register_emitter(ir_op *op, emit_func func)
{
Matthias Braun's avatar
Matthias Braun committed
664
	op->ops.generic = (op_func) func;
665
666
667
668
669
}

/**
 * Register emitter functions for mips backend
 */
670
671
void mips_register_emitters(void)
{
672
673
674
675
676
677
	/* 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();

678
	/* benode emitter */
Matthias Braun's avatar
Matthias Braun committed
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
	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);
	register_emitter(op_be_RegParams, mips_emit_nothing);
	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_Start, mips_emit_nothing);
	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
698
	register_emitter(op_Phi, mips_emit_nothing);
699
700
701
702
703
}

/**
 * Emits assembly for a single node
 */
704
static void mips_emit_node(const ir_node *node)
705
{
706
	ir_op *op = get_irn_op(node);
707
708
709

	if (op->ops.generic) {
		emit_func emit = (emit_func) op->ops.generic;
710
		(*emit) (node);
711
	} else {
Matthias Braun's avatar
Matthias Braun committed
712
		panic("No emitter defined for node %+F", node);
713
714
715
716
717
718
719
	}
}

/**
 * Walks over the nodes in a block connected by scheduling edges
 * and emits code for each node.
 */
720
void mips_gen_block(const ir_node *block)
721
{
722
	ir_node *node;
723
724
725
726

	if (! is_Block(block))
		return;

727
728
729
	mips_emit_block_label(block);
	be_emit_cstring(":\n");
	be_emit_write_line();
730
731

	sched_foreach(block, node) {
732
		mips_emit_node(node);
733
	}
734

735
736
	be_emit_char('\n');
	be_emit_write_line();
737
738
739
740
741
}

/**
 * Emits code for function start.
 */
742
void mips_emit_func_prolog(ir_graph *irg)
743
{
744
	ident *irg_ident = get_entity_ld_ident(get_irg_entity(irg));
745
746

	// dump jump tables
747
	//irg_walk_graph(irg, NULL, dump_jump_tables, env);
748

749
750
	be_emit_write_line();
	be_gas_emit_switch_section(GAS_SECTION_TEXT);
751

752
	be_emit_cstring("\t.balign\t4\n");
753

754
755
756
	be_emit_cstring("\t.global\t");
	be_emit_ident(irg_ident);
	be_emit_char('\n');
757

758
	be_emit_cstring("\t.set\tnomips16\n");
759

760
761
762
	be_emit_cstring("\t.ent\t");
	be_emit_ident(irg_ident);
	be_emit_char('\n');
763

764
765
	be_emit_ident(irg_ident);
	be_emit_cstring(":\n");
766

767
768
769
	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");
770

771
	be_emit_write_line();
772
773
774
775
776
}

/**
 * Emits code for function end
 */
777
void mips_emit_func_epilog(ir_graph *irg)
778
{
779
780
	ident *irg_ident = get_entity_ident(get_irg_entity(irg));

781
782
783
784
	be_emit_cstring("\t.end\t");
	be_emit_ident(irg_ident);
	be_emit_char('\n');
	be_emit_write_line();
785
786
787
788
789
790
791
792
793
}

/**
 * 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
794
	(void) env;
795
796
797
798
799
800
801
802
803
804

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

/**
 * Main driver
 */
805
void mips_gen_routine(mips_code_gen_t *mips_cg, ir_graph *irg)
806
807
808
{
	int i, n;

809
	cg       = mips_cg;
810
	isa      = (const mips_isa_t*) cg->arch_env;
811
	arch_env = cg->arch_env;
812

813
	mips_register_emitters();
814

815
	irg_block_walk_graph(irg, mips_gen_labels, NULL, NULL);
816

817
	mips_emit_func_prolog(irg);
818
819
820
821
822

	dump_ir_block_graph_sched(irg, "-kaputtelist");

	for (i = 0, n = mips_get_sched_n_blocks(cg); i < n; ++i) {
		ir_node *block = mips_get_sched_block(cg, i);
823
		mips_gen_block(block);
824
825
	}

826
	mips_emit_func_epilog(irg);
827
828
829
830
831
}

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