ppc32_emitter.c 18.2 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   ppc emitter
 * @author  Moritz Kroll, Jens Mueller
 * @version $Id$
 */
26
27
28
29
30
31
32
33
34
35
36
37
38
#include "config.h"

#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 "irnode_t.h"
#include "irargs_t.h"
Michael Beck's avatar
Michael Beck committed
39
#include "error.h"
40

41
#include "../besched.h"
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
#include "../benode_t.h"

#include "ppc32_emitter.h"
#include "gen_ppc32_emitter.h"
#include "gen_ppc32_regalloc_if.h"
#include "ppc32_nodes_attr.h"
#include "ppc32_new_nodes.h"
#include "ppc32_map_regs.h"

#define SNPRINTF_BUF_LEN 128

static char printbuf[SNPRINTF_BUF_LEN];

extern int isleaf;


/*************************************************************
 *             _       _    __   _          _
 *            (_)     | |  / _| | |        | |
 *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
 * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
 * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
 * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
 * | |                                       | |
 * |_|                                       |_|
 *************************************************************/
/**
 * Returns the register at in position pos.
 */
71
static const arch_register_t *get_in_reg(const ir_node *irn, int pos) {
72
73
74
75
76
77
78
79
80
	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);

81
	reg = arch_get_irn_register(op);
82
83
84
85
86
87
88
89

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

/**
 * Returns the register at out position pos.
 */
90
static const arch_register_t *get_out_reg(const ir_node *irn, int pos) {
91
92
93
94
95
96
97
98
99
100
101
	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) {
102
		reg = arch_get_irn_register(irn);
Michael Beck's avatar
Michael Beck committed
103
	} else if (is_ppc32_irn(irn)) {
104
		reg = arch_irn_get_register(irn, pos);
Michael Beck's avatar
Michael Beck committed
105
	} else {
106
107
108
109
110
111
		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) {
112
				reg = arch_get_irn_register(proj);
113
114
115
116
117
118
119
120
121
122
				break;
			}
		}
	}

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

/**
Michael Beck's avatar
Michael Beck committed
123
 * Emit the name of the source register at given input position.
124
 */
125
126
127
void ppc32_emit_source_register(const ir_node *node, int pos) {
	const arch_register_t *reg = get_in_reg(node, pos);
	be_emit_string(arch_register_get_name(reg));
128
129
130
}

/**
Michael Beck's avatar
Michael Beck committed
131
 * Emit the name of the destination register at given output position.
132
 */
133
134
135
void ppc32_emit_dest_register(const ir_node *node, int pos) {
	const arch_register_t *reg = get_out_reg(node, pos);
	be_emit_string(arch_register_get_name(reg));
Michael Beck's avatar
Michael Beck committed
136
}
137

138
void ppc32_emit_rlwimi_helper(const ir_node *n) {
139
	const rlwimi_const_t *rlwimi_const = get_ppc32_rlwimi_const(n);
140

141
	be_emit_irprintf("%i, %i, %i", rlwimi_const->shift,
Michael Beck's avatar
Michael Beck committed
142
		rlwimi_const->maskA, rlwimi_const->maskB);
143
144
145
}

/**
Michael Beck's avatar
Michael Beck committed
146
 * Emit a const or symconst.
147
 */
148
void ppc32_emit_immediate(const ir_node *n) {
149
150
	const char *buf;

Michael Beck's avatar
Michael Beck committed
151
152
153
154
155
156
157
158
159
	switch (get_ppc32_type(n)) {
	case ppc32_ac_Const:
		tarval_snprintf(printbuf, SNPRINTF_BUF_LEN, get_ppc32_constant_tarval(n));
		buf = printbuf;
		break;
	case ppc32_ac_SymConst:
		buf = get_id_str(get_ppc32_symconst_ident(n));
		break;
	case ppc32_ac_Offset:
160
		be_emit_irprintf("%i", get_ppc32_offset(n));
Michael Beck's avatar
Michael Beck committed
161
162
163
164
		return;
	default:
		assert(0 && "node_const_to_str(): Illegal offset type");
		return;
165
	}
Michael Beck's avatar
Michael Beck committed
166
167
	switch (get_ppc32_offset_mode(n)) {
	case ppc32_ao_None:
168
		be_emit_string(buf);
Michael Beck's avatar
Michael Beck committed
169
170
		return;
	case ppc32_ao_Lo16:
171
		be_emit_irprintf("lo16(%s)", buf);
Michael Beck's avatar
Michael Beck committed
172
173
		return;
	case ppc32_ao_Hi16:
174
		be_emit_irprintf("hi16(%s)", buf);
Michael Beck's avatar
Michael Beck committed
175
176
		return;
	case ppc32_ao_Ha16:
177
		be_emit_irprintf("ha16(%s)", buf);
Michael Beck's avatar
Michael Beck committed
178
179
180
181
		return;
	default:
		assert(0 && "node_const_to_str(): Illegal offset mode");
		return;
182
183
184
185
	}
}

/**
Michael Beck's avatar
Michael Beck committed
186
 * Emits a node's offset.
187
 */
188
void ppc32_emit_offset(const ir_node *n) {
189
	const char *buf;
Michael Beck's avatar
Michael Beck committed
190
	if (get_ppc32_type(n) == ppc32_ac_None) {
191
		be_emit_char('0');
Michael Beck's avatar
Michael Beck committed
192
		return;
193
194
	}

Michael Beck's avatar
Michael Beck committed
195
196
197
198
199
200
201
202
203
	switch (get_ppc32_type(n)) {
	case ppc32_ac_Const:
		tarval_snprintf(printbuf, SNPRINTF_BUF_LEN, get_ppc32_constant_tarval(n));
		buf = printbuf;
		break;
	case ppc32_ac_SymConst:
		buf = get_id_str(get_ppc32_symconst_ident(n));
		break;
	case ppc32_ac_Offset:
204
		be_emit_irprintf("%i", get_ppc32_offset(n));
Michael Beck's avatar
Michael Beck committed
205
206
207
208
209
210
211
		return;
	default:
		assert(0 && "node_offset_to_str(): Illegal offset type");
		return;
	}
	switch (get_ppc32_offset_mode(n)) {
	case ppc32_ao_None:
212
		be_emit_string(buf);
Michael Beck's avatar
Michael Beck committed
213
214
		return;
	case ppc32_ao_Lo16:
215
		be_emit_irprintf("lo16(%s)", buf);
Michael Beck's avatar
Michael Beck committed
216
217
		return;
	case ppc32_ao_Hi16:
218
		be_emit_irprintf("hi16(%s)", buf);
Michael Beck's avatar
Michael Beck committed
219
220
		return;
	case ppc32_ao_Ha16:
221
		be_emit_irprintf("ha16(%s)", buf);
Michael Beck's avatar
Michael Beck committed
222
223
224
225
		return;
	default:
		assert(0 && "node_offset_to_str(): Illegal offset mode");
		return;
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
	}
}

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

	snprintf(buf, SNPRINTF_BUF_LEN, "BLOCK_%ld", get_irn_node_nr(bl));
	return buf;
}

/**
 * Emits code for a unconditional jump.
 */
242
static void emit_Jmp(const ir_node *irn) {
Michael Beck's avatar
Michael Beck committed
243
	ir_node *block = get_nodes_block(irn);
244

Michael Beck's avatar
Michael Beck committed
245
	if (get_irn_link(irn) != get_irn_link(block)) {
246
		be_emit_irprintf("\tb %s", get_cfop_target(irn, printbuf));
Michael Beck's avatar
Michael Beck committed
247
	} else {
248
		be_emit_irprintf("/* fallthrough(%+F) */", get_irn_link(irn));
Michael Beck's avatar
Michael Beck committed
249
	}
250
	be_emit_finish_line_gas(irn);
251
252
253
254
255
}

/**
 * Emits code for a call
 */
256
static void emit_be_Call(const ir_node *irn) {
257
	ir_entity *call_ent = be_Call_get_entity(irn);
258

Michael Beck's avatar
Michael Beck committed
259
	if (call_ent) {
Michael Beck's avatar
Michael Beck committed
260
		set_entity_backend_marked(call_ent, 1);
261
		be_emit_irprintf("\tbl %s", get_entity_ld_name(call_ent));
Michael Beck's avatar
Michael Beck committed
262
	} else {
263
264
265
266
267
268
		be_emit_cstring("\tmtlr ");
		ppc32_emit_source_register(irn, be_pos_Call_ptr);
		be_emit_pad_comment();
		be_emit_cstring("/* Move to link register and link */\n");
		be_emit_write_line();
		be_emit_cstring("\tblrl");
Michael Beck's avatar
Michael Beck committed
269
	}
270
	be_emit_finish_line_gas(irn);
271
272
}

273
static void emit_ppc32_Branch(const ir_node *irn) {
Michael Beck's avatar
Michael Beck committed
274
275
	static const char *branchops[8] = { 0, "beq", "blt", "ble", "bgt", "bge", "bne", "b" };
	int projnum = get_ppc32_proj_nr(irn);
276

Michael Beck's avatar
Michael Beck committed
277
	const ir_edge_t *edge = get_irn_out_edge_first(irn);
278
279
280
281
	ir_node *proj = get_edge_src_irn(edge);

	int opind;

Michael Beck's avatar
Michael Beck committed
282
	if (get_Proj_proj(proj) == pn_Cond_true)
283
284
		opind = projnum;
	else
Michael Beck's avatar
Michael Beck committed
285
		opind = 7 - projnum;
286
287
288

	assert(opind>=0 && opind<8);

Michael Beck's avatar
Michael Beck committed
289
	if (opind){
290
		get_cfop_target(proj, printbuf);
291
292
293
294
295
		be_emit_irprintf("\t%8s", branchops[opind]);
		ppc32_emit_source_register(irn, 0);
		be_emit_cstring(", ");
		be_emit_string(printbuf);
		be_emit_finish_line_gas(irn);
296
297
	}

Michael Beck's avatar
Michael Beck committed
298
299
300
	edge = get_irn_out_edge_next(irn, edge);
	if (edge) {
		ir_node *blk = get_edge_src_irn(edge);
301
302
303
		be_emit_cstring("\tb ");
		be_emit_string(get_cfop_target(blk, printbuf));
		be_emit_finish_line_gas(irn);
304
305
306
	}
}

307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
static void emit_ppc32_LoopCopy(const ir_node *irn) {
	be_emit_irprintf("LOOP_%ld:\n", get_irn_node_nr(irn));
	be_emit_write_line();

	be_emit_cstring("\tlwzu ");
	ppc32_emit_dest_register(irn, 4);
	be_emit_cstring(", 4(");
	ppc32_emit_source_register(irn, 1);
	be_emit_char(')');
	be_emit_pad_comment();
	be_emit_cstring("/* Load with update */\n");
	be_emit_write_line();

	be_emit_cstring("\tstwu ");
	ppc32_emit_dest_register(irn, 4);
	be_emit_cstring(", 4(");
	ppc32_emit_source_register(irn, 2);
	be_emit_char(')');
	be_emit_pad_comment();
	be_emit_cstring("/* Store with update */\n");
	be_emit_write_line();

	be_emit_irprintf("\tbdnz LOOP_%i", get_irn_node_nr(irn));
	be_emit_finish_line_gas(irn);
331
332
}

333
static void emit_ppc32_Switch(const ir_node *irn) {
Michael Beck's avatar
Michael Beck committed
334
	ir_node *proj, *defproj = NULL;
335
336
337
	int pn;

	const ir_edge_t* edge;
Michael Beck's avatar
Michael Beck committed
338
	foreach_out_edge(irn, edge) {
339
340
		proj = get_edge_src_irn(edge);
		assert(is_Proj(proj) && "Only proj allowed at Switch");
Michael Beck's avatar
Michael Beck committed
341
		if (get_irn_mode(proj) != mode_X) continue;
342
343
344

		pn = get_Proj_proj(proj);
		/* check for default proj */
Michael Beck's avatar
Michael Beck committed
345
		if (pn == get_ppc32_proj_nr(irn)) {
346
347
			assert(defproj == NULL && "found two defProjs at Switch");
			defproj = proj;
Michael Beck's avatar
Michael Beck committed
348
		} else {
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
			be_emit_cstring("\taddis ");
			ppc32_emit_source_register(irn, 1);
			be_emit_irprintf(", 0, hi16(%i)", pn);
			be_emit_pad_comment();
			be_emit_cstring("/* Load upper immediate */\n");
			be_emit_write_line();

			be_emit_cstring("\tori ");
			ppc32_emit_source_register(irn, 1);
			be_emit_cstring(", ");
			ppc32_emit_source_register(irn, 1);
			be_emit_irprintf(", lo16(%i)", pn);
			be_emit_pad_comment();
			be_emit_cstring("/* Load lower immediate */\n");
			be_emit_write_line();

			be_emit_cstring("\tcmp ");
			ppc32_emit_source_register(irn, 2);
			be_emit_cstring(", ");
			ppc32_emit_source_register(irn, 0);
			be_emit_cstring(", ");
			ppc32_emit_source_register(irn, 1);
			be_emit_pad_comment();
			be_emit_cstring("/* Compare */\n");
			be_emit_write_line();

			be_emit_cstring("\tbeq ");
			ppc32_emit_source_register(irn, 2);
			be_emit_irprintf(", %s", get_cfop_target(proj, printbuf));
			be_emit_cstring("/* Branch if equal */\n");
			be_emit_write_line();
380
381
382
		}
	}
	assert(defproj != NULL && "didn't find defProj at Switch");
383
384
	be_emit_irprintf("\tb %s", get_cfop_target(defproj, printbuf));
	be_emit_finish_line_gas(irn);
385
386
387
388
389
}

/**
 * Emits code for a backend Copy node
 */
390
static void emit_be_Copy(const ir_node *irn) {
391
	const arch_register_class_t *regclass = arch_get_irn_reg_class(irn, 0);
Michael Beck's avatar
Michael Beck committed
392
393

	if (regclass == &ppc32_reg_classes[CLASS_ppc32_gp]) {
394
		be_emit_cstring("\tmr ");
Michael Beck's avatar
Michael Beck committed
395
	} else if (regclass == &ppc32_reg_classes[CLASS_ppc32_fp]) {
396
		be_emit_cstring("\tfmr ");
Michael Beck's avatar
Michael Beck committed
397
	} else if (regclass == &ppc32_reg_classes[CLASS_ppc32_condition]) {
398
		be_emit_cstring("\tmcrf ");
Michael Beck's avatar
Michael Beck committed
399
400
401
402
	} else {
		assert(0 && "Illegal register class for Copy");
		panic("ppc32 Emitter: Illegal register class for Copy");
	}
403
404
405
406
	ppc32_emit_dest_register(irn, 0);
	be_emit_cstring(", ");
	ppc32_emit_source_register(irn, 0);
	be_emit_finish_line_gas(irn);
407
408
409
410
411
}

/**
 * Emits code for a backend Perm node
 */
412
static void emit_be_Perm(const ir_node *irn) {
413
	const arch_register_class_t *regclass = arch_get_irn_reg_class(irn, 0);
Michael Beck's avatar
Michael Beck committed
414
415

	if (regclass == &ppc32_reg_classes[CLASS_ppc32_gp]) {
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
		be_emit_cstring("\txor ");
		ppc32_emit_source_register(irn, 0);
		be_emit_cstring(", ");
		ppc32_emit_source_register(irn, 0);
		be_emit_cstring(", ");
		ppc32_emit_source_register(irn, 1);
		be_emit_pad_comment();
		be_emit_cstring("/* Swap with XOR */\n");
		be_emit_write_line();

		be_emit_cstring("\txor ");
		ppc32_emit_source_register(irn, 1);
		be_emit_cstring(", ");
		ppc32_emit_source_register(irn, 0);
		be_emit_cstring(", ");
		ppc32_emit_source_register(irn, 1);
		be_emit_pad_comment();
		be_emit_cstring("/* (continued) */\n");
		be_emit_write_line();

		be_emit_cstring("\txor ");
		ppc32_emit_source_register(irn, 0);
		be_emit_cstring(", ");
		ppc32_emit_source_register(irn, 0);
		be_emit_cstring(", ");
		ppc32_emit_source_register(irn, 1);
Michael Beck's avatar
Michael Beck committed
442
	} else if (regclass == &ppc32_reg_classes[CLASS_ppc32_fp]) {
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
		be_emit_cstring("\tfmr f0, ");
		ppc32_emit_source_register(irn, 0);
		be_emit_pad_comment();
		be_emit_cstring("/* Swap with moves */\n");
		be_emit_write_line();

		be_emit_cstring("\tfmr ");
		ppc32_emit_source_register(irn, 0);
		be_emit_cstring(", ");
		ppc32_emit_source_register(irn, 1);
		be_emit_pad_comment();
		be_emit_cstring("/* (continued) */\n");
		be_emit_write_line();

		be_emit_cstring("\tfmr ");
		ppc32_emit_source_register(irn, 1);
		be_emit_cstring(", f0");
Michael Beck's avatar
Michael Beck committed
460
	} else if (regclass == &ppc32_reg_classes[CLASS_ppc32_condition]) {
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
		be_emit_cstring("\tmcrf cr7, ");
		ppc32_emit_source_register(irn, 0);
		be_emit_pad_comment();
		be_emit_cstring("/* Swap with moves */\n");
		be_emit_write_line();

		be_emit_cstring("\tmcrf ");
		ppc32_emit_source_register(irn, 0);
		be_emit_cstring(", ");
		ppc32_emit_source_register(irn, 1);
		be_emit_pad_comment();
		be_emit_cstring("/* (continued) */\n");
		be_emit_write_line();

		be_emit_cstring("\tmcrf ");
		ppc32_emit_source_register(irn, 1);
		be_emit_cstring(", cr7");
Michael Beck's avatar
Michael Beck committed
478
479
480
481
	} else {
		assert(0 && "Illegal register class for Perm");
		panic("ppc32 Emitter: Illegal register class for Perm");
	}
482
	be_emit_finish_line_gas(irn);
483
484
485
486
487
488
}


/**
 * Emits code for a proj -> node
 */
489
static void emit_Proj(const ir_node *irn) {
490
491
	ir_node *pred = get_Proj_pred(irn);

492
	if (is_Start(pred)) {
Michael Beck's avatar
Michael Beck committed
493
		if (get_Proj_proj(irn) == pn_Start_X_initial_exec) {
494
			emit_Jmp(irn);
495
496
497
498
		}
	}
}

499
static void emit_be_IncSP(const ir_node *irn) {
500
	int offs = be_get_IncSP_offset(irn);
501

502
503
	be_emit_irprintf("\t/* ignored IncSP with %d */", -offs);
	be_emit_finish_line_gas(irn);
504
505
506

//	if (offs) {
//		assert(offs<=0x7fff);
507
508
//		lc_efprintf(ppc32_get_arg_env(), F, "\taddi    %1S, %1S, %d\t\t\t/* %+F (IncSP) */\n", irn, irn,
//			-offs, irn);
509
510
511
512
513
514
515
516
//	}
//	else {
//		fprintf(F, "\t\t\t\t\t/* omitted IncSP with 0 */\n");
//	}
}

/*static void emit_Spill(const ir_node *irn, ppc32_emit_env_t *emit_env) {
	ir_node *context = be_get_Spill_context(irn);
517
	ir_entity *entity = be_get_spill_entity(irn);
518
519
520
521
522
523
524
525
526
527
528
}*/

/***********************************************************************************
 *                  _          __                                             _
 *                 (_)        / _|                                           | |
 *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
 * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
 * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
 * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
 *
 ***********************************************************************************/
Michael Beck's avatar
Michael Beck committed
529
530
531
/**
 * The type of a emitter function.
 */
532
typedef void (emit_func)(const ir_node *irn);
Michael Beck's avatar
Michael Beck committed
533
534
535
536

/**
 * Set a node emitter. Make it a bit more type safe.
 */
537
static inline void set_emitter(ir_op *op, emit_func ppc32_emit_node) {
Michael Beck's avatar
Michael Beck committed
538
539
	op->ops.generic = (op_func)ppc32_emit_node;
}
540
541
542
543
544
545
546
547

static void ppc32_register_emitters(void) {
	/* first clear generic function pointers */
	clear_irp_opcodes_generic_func();

	/* register generated emitter functions */
	ppc32_register_spec_emitters();

Michael Beck's avatar
Michael Beck committed
548
549
550
551
552
553
554
555
556
557
558
	set_emitter(op_ppc32_Branch, emit_ppc32_Branch);
	set_emitter(op_ppc32_LoopCopy, emit_ppc32_LoopCopy);
	set_emitter(op_ppc32_Switch, emit_ppc32_Switch);
	set_emitter(op_be_Call, emit_be_Call);
	set_emitter(op_Jmp, emit_Jmp);
	set_emitter(op_Proj, emit_Proj);
	set_emitter(op_be_IncSP, emit_be_IncSP);
	set_emitter(op_be_Copy, emit_be_Copy);
	set_emitter(op_be_Perm, emit_be_Perm);
//	set_emitter(op_Spill, emit_Spill);
//	set_emitter(op_Reload, emit_Reload);
559
560
561
562
563
}

/**
 * Emits code for a node.
 */
564
static void ppc32_emit_node(const ir_node *irn) {
Michael Beck's avatar
Michael Beck committed
565
	ir_op *op = get_irn_op(irn);
566
567

	if (op->ops.generic) {
Michael Beck's avatar
Michael Beck committed
568
		emit_func *emit = (emit_func *)op->ops.generic;
569
		(*emit)(irn);
Michael Beck's avatar
Michael Beck committed
570
	} else {
571
572
		be_emit_cstring("\t/* TODO */");
		be_emit_finish_line_gas(irn);
573
574
575
576
577
578
579
580
	}
}


/**
 * Walks over the nodes in a block connected by scheduling edges
 * and emits code for each node.
 */
581
static void ppc32_gen_block(const ir_node *block) {
582
583
584
585
586
	ir_node *irn;

	if (! is_Block(block))
		return;

587
588
	be_emit_irprintf("BLOCK_%ld:\n", get_irn_node_nr(block));
	be_emit_write_line();
589
	sched_foreach(block, irn) {
590
		ppc32_emit_node(irn);
591
592
593
594
595
596
597
	}
}


/**
 * Emits code for function start.
 */
598
static void ppc32_emit_start(ir_graph *irg) {
599
	const char *irg_name  = get_entity_ld_name(get_irg_entity(irg));
600
	int         framesize = get_type_size_bytes(get_irg_frame_type(irg));
601

Michael Beck's avatar
Michael Beck committed
602
603
	if(! strcmp(irg_name, "main")) {					   // XXX: underscore hack
		irg_name = "_main";
604
605
	}

606
	be_emit_irprintf("\t.text\n\t.globl %s\n\t.align 4\n%s:\n", irg_name, irg_name);
607

Michael Beck's avatar
Michael Beck committed
608
	if (framesize > 24) {
609
610
611
		be_emit_cstring("\tmflr    r0\n");
		be_emit_cstring("\tstw     r0, 8(r1)\n");
		be_emit_irprintf("\tstwu    r1, -%i(r1)\n", framesize);
Michael Beck's avatar
Michael Beck committed
612
	} else {
613
		be_emit_irprintf("\t/* set new frame (%d) omitted */\n", framesize);
Michael Beck's avatar
Michael Beck committed
614
	}
615
	be_emit_write_line();
616

Michael Beck's avatar
Michael Beck committed
617
/*	if(!isleaf) {
618
619
		// store link register in linkage area (TODO: if needed)

620
621
622
		be_emit_cstring("\tmflr    r0\n");
		be_emit_cstring("\tstwu    r0, -4(r1)\n");   // stw r0, 8(SP)
		be_emit_write_line();
623
624
625
626
627
628
	}*/
}

/**
 * Emits code for function end
 */
629
static void ppc32_emit_end(ir_graph *irg) {
630
	int framesize = get_type_size_bytes(get_irg_frame_type(irg));
Matthias Braun's avatar
Matthias Braun committed
631
	(void) irg;
632

Michael Beck's avatar
Michael Beck committed
633
/*	if(!isleaf) {
634
635
		// restore link register

636
637
638
639
		be_emit_cstring("\tlwz     r0, 0(r1)\n");
		be_emit_cstring("\taddi    r1, r1, 4\n");
		be_emit_cstring("\tmtlr    r0\n");
		be_emit_write_line();
640
	}*/
Michael Beck's avatar
Michael Beck committed
641
	if(framesize > 24) {
642
643
644
645
		be_emit_cstring("\tlwz    r1, 0(r1)\n");
		be_emit_cstring("\tlwz    r0, 8(r1)\n");
		be_emit_cstring("\tmtlr   r0\n");
		be_emit_write_line();
Michael Beck's avatar
Michael Beck committed
646
	}
647
648
	be_emit_cstring("\tblr\n\n");
	be_emit_write_line();
649
650
651
652
653
654
655
656
657
}

/**
 * Sets labels for control flow nodes (jump target)
 * TODO: Jump optimization
 */
void ppc32_gen_labels(ir_node *block, void *env) {
	ir_node *pred;
	int n;
Matthias Braun's avatar
Matthias Braun committed
658
	(void) env;
659
660
661
662
663
664
665
666
667
668

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

/**
 * Main driver: generates code for one routine
 */
669
void ppc32_gen_routine(const ppc32_code_gen_t *cg, ir_graph *irg)
Michael Beck's avatar
Michael Beck committed
670
{
671
672
673
674
675
	ir_node *block;
	int i, n;

	ppc32_register_emitters();

676
677
	ppc32_emit_start(irg);
	irg_block_walk_graph(irg, ppc32_gen_labels, NULL, NULL);
678
679
680
681
682
683
684
685
686
687
688

	n = ARR_LEN(cg->blk_sched);
	for (i = 0; i < n;) {
		ir_node *next_bl;

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

		/* set here the link. the emitter expects to find the next block here */
		set_irn_link(block, next_bl);
689
		ppc32_gen_block(block);
690
	}
691
	ppc32_emit_end(irg);
692
}