TEMPLATE_emitter.c 7.36 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.
 */

Matthias Braun's avatar
Matthias Braun committed
20
21
22
23
24
/**
 * @file
 * @brief   emit assembler for a backend graph
 * @version $Id$
 */
25
#include "config.h"
26
27
28
29
30
31
32
33
34
35
36

#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 "irargs_t.h"
37
#include "irprog.h"
38
39
40
41
42
43
44
45
46
47
48
49
50

#include "../besched.h"

#include "TEMPLATE_emitter.h"
#include "gen_TEMPLATE_emitter.h"
#include "TEMPLATE_nodes_attr.h"
#include "TEMPLATE_new_nodes.h"

#define SNPRINTF_BUF_LEN 128

/**
 * Returns the register at in position pos.
 */
51
static const arch_register_t *get_in_reg(const ir_node *node, int pos)
Matthias Braun's avatar
Matthias Braun committed
52
{
53
54
55
	ir_node                *op;
	const arch_register_t  *reg = NULL;

Matthias Braun's avatar
Matthias Braun committed
56
	assert(get_irn_arity(node) > pos && "Invalid IN position");
57
58
59

	/* The out register of the operator at position pos is the
	   in register we need. */
Matthias Braun's avatar
Matthias Braun committed
60
	op = get_irn_n(node, pos);
61

62
	reg = arch_get_irn_register(op);
63
64
65
66
67
68
69
70

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

/**
 * Returns the register at out position pos.
 */
71
static const arch_register_t *get_out_reg(const ir_node *node, int pos)
Matthias Braun's avatar
Matthias Braun committed
72
{
73
74
75
76
77
78
79
80
	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 */

Matthias Braun's avatar
Matthias Braun committed
81
	if (get_irn_mode(node) != mode_T) {
82
		reg = arch_get_irn_register(node);
Matthias Braun's avatar
Matthias Braun committed
83
	} else if (is_TEMPLATE_irn(node)) {
84
		reg = arch_irn_get_register(node, pos);
Matthias Braun's avatar
Matthias Braun committed
85
	} else {
86
87
		const ir_edge_t *edge;

Matthias Braun's avatar
Matthias Braun committed
88
		foreach_out_edge(node, edge) {
89
90
91
			proj = get_edge_src_irn(edge);
			assert(is_Proj(proj) && "non-Proj from mode_T node");
			if (get_Proj_proj(proj) == pos) {
92
				reg = arch_get_irn_register(proj);
93
94
95
96
97
98
99
100
101
				break;
			}
		}
	}

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

Matthias Braun's avatar
Matthias Braun committed
102
103
104
105
106
107
108
109
110
111
/*************************************************************
 *             _       _    __   _          _
 *            (_)     | |  / _| | |        | |
 *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
 * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
 * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
 * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
 * | |                                       | |
 * |_|                                       |_|
 *************************************************************/
112

113
void TEMPLATE_emit_immediate(const ir_node *node)
114
{
Matthias Braun's avatar
Matthias Braun committed
115
	(void) node;
Matthias Braun's avatar
Matthias Braun committed
116
	/* TODO */
117
118
}

119
void TEMPLATE_emit_source_register(const ir_node *node, int pos)
120
{
121
122
	const arch_register_t *reg = get_in_reg(node, pos);
	be_emit_string(arch_register_get_name(reg));
123
124
}

125
void TEMPLATE_emit_dest_register(const ir_node *node, int pos)
126
{
127
128
	const arch_register_t *reg = get_out_reg(node, pos);
	be_emit_string(arch_register_get_name(reg));
129
130
131
132
133
}

/**
 * Returns the target label for a control flow node.
 */
Matthias Braun's avatar
Matthias Braun committed
134
135
static void TEMPLATE_emit_cfop_target(const ir_node *node)
{
Matthias Braun's avatar
Matthias Braun committed
136
	ir_node *block = get_irn_link(node);
137
	be_gas_emit_block_name(block);
138
139
140
141
142
143
144
145
146
147
148
149
}

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

Matthias Braun's avatar
Matthias Braun committed
150
151
152
/**
 * Emits code for a unconditional jump.
 */
Matthias Braun's avatar
Matthias Braun committed
153
154
static void emit_Jmp(const ir_node *node)
{
Matthias Braun's avatar
Matthias Braun committed
155
156
157
158
159
	ir_node *block;

	/* for now, the code works for scheduled and non-schedules blocks */
	block = get_nodes_block(node);

160
161
162
	be_emit_cstring("\tjmp ");
	TEMPLATE_emit_cfop_target(node);
	be_emit_finish_line_gas(node);
Matthias Braun's avatar
Matthias Braun committed
163
164
}

165
/**
166
167
 * Enters the emitter functions for handled nodes into the generic
 * pointer of an opcode.
168
 */
Matthias Braun's avatar
Matthias Braun committed
169
170
static void TEMPLATE_register_emitters(void)
{
171

172
173
174
175
176
/* some convienience macros to register additional emitter functions
   (other than the generated ones) */
#define TEMPLATE_EMIT(a) op_TEMPLATE_##a->ops.generic = (op_func)emit_TEMPLATE_##a
#define EMIT(a)          op_##a->ops.generic = (op_func)emit_##a
#define BE_EMIT(a)       op_be_##a->ops.generic = (op_func)emit_be_##a
177

178
179
	/* first clear the generic function pointer for all ops */
	clear_irp_opcodes_generic_func();
180

181
182
	/* register all emitter functions defined in spec */
	TEMPLATE_register_spec_emitters();
183

184
	/* register addtional emitter functions if needed */
Matthias Braun's avatar
Matthias Braun committed
185
	EMIT(Jmp);
186

187
188
189
190
#undef TEMPLATE_EMIT
#undef BE_EMIT
#undef EMIT
}
191

192
typedef void (*emit_func_ptr) (const ir_node *);
193

194
195
196
/**
 * Emits code for a node.
 */
Matthias Braun's avatar
Matthias Braun committed
197
198
void TEMPLATE_emit_node(const ir_node *node)
{
Matthias Braun's avatar
Matthias Braun committed
199
	ir_op               *op       = get_irn_op(node);
200

201
	if (op->ops.generic) {
Matthias Braun's avatar
Matthias Braun committed
202
		emit_func_ptr func = (emit_func_ptr) op->ops.generic;
203
		(*func) (node);
Matthias Braun's avatar
Matthias Braun committed
204
205
	} else {
		ir_fprintf(stderr, "No emitter for node %+F\n", node);
206
	}
207
208
209
210
211
212
}

/**
 * Walks over the nodes in a block connected by scheduling edges
 * and emits code for each node.
 */
Matthias Braun's avatar
Matthias Braun committed
213
214
void TEMPLATE_gen_block(ir_node *block, void *data)
{
Matthias Braun's avatar
Matthias Braun committed
215
	ir_node *node;
216
	(void) data;
217
218
219
220

	if (! is_Block(block))
		return;

221
222
	be_gas_emit_block_name(block);
	be_emit_cstring(":\n");
223
	be_emit_write_line();
Matthias Braun's avatar
Matthias Braun committed
224
225

	sched_foreach(block, node) {
226
		TEMPLATE_emit_node(node);
227
228
229
230
231
232
233
	}
}


/**
 * Emits code for function start.
 */
Matthias Braun's avatar
Matthias Braun committed
234
235
void TEMPLATE_emit_func_prolog(ir_graph *irg)
{
236
237
238
	const char *irg_name = get_entity_name(get_irg_entity(irg));

	/* TODO: emit function header */
239
240
241
242
	be_emit_cstring("/* start of ");
	be_emit_string(irg_name);
	be_emit_cstring(" */\n");
	be_emit_write_line();
243
244
245
246
247
}

/**
 * Emits code for function end
 */
Matthias Braun's avatar
Matthias Braun committed
248
249
void TEMPLATE_emit_func_epilog(ir_graph *irg)
{
250
251
252
	const char *irg_name = get_entity_name(get_irg_entity(irg));

	/* TODO: emit function end */
253
254
255
256
	be_emit_cstring("/* end of ");
	be_emit_string(irg_name);
	be_emit_cstring(" */\n");
	be_emit_write_line();
257
258
259
260
261
262
}

/**
 * Sets labels for control flow nodes (jump target)
 * TODO: Jump optimization
 */
Matthias Braun's avatar
Matthias Braun committed
263
264
void TEMPLATE_gen_labels(ir_node *block, void *env)
{
265
266
	ir_node *pred;
	int n = get_Block_n_cfgpreds(block);
Matthias Braun's avatar
Matthias Braun committed
267
	(void) env;
268
269
270
271
272
273
274
275
276
277

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

/**
 * Main driver
 */
278
279
280
void TEMPLATE_gen_routine(const TEMPLATE_code_gen_t *cg, ir_graph *irg)
{
	(void)cg;
281

282
283
284
	/* register all emitter functions */
	TEMPLATE_register_emitters();

285
286
287
288
	TEMPLATE_emit_func_prolog(irg);
	irg_block_walk_graph(irg, TEMPLATE_gen_labels, NULL, NULL);
	irg_walk_blkwise_graph(irg, NULL, TEMPLATE_gen_block, NULL);
	TEMPLATE_emit_func_epilog(irg);
289
}