TEMPLATE_emitter.c 5.9 KB
Newer Older
Christian Würdig's avatar
Christian Würdig committed
1
2
/*
 * This file is part of libFirm.
3
 * Copyright (C) 2012 University of Karlsruhe.
Christian Würdig's avatar
Christian Würdig committed
4
5
 */

Matthias Braun's avatar
Matthias Braun committed
6
7
8
9
/**
 * @file
 * @brief   emit assembler for a backend graph
 */
10
11
#include <limits.h>

Matthias Braun's avatar
Matthias Braun committed
12
#include "panic.h"
13
14
15
16
17
18
19
#include "xmalloc.h"
#include "tv.h"
#include "iredges.h"
#include "debug.h"
#include "irgwalk.h"
#include "irop_t.h"
#include "irargs_t.h"
20
#include "irprog.h"
21

22
23
24
25
#include "besched.h"
#include "begnuas.h"
#include "beblocksched.h"
#include "benode.h"
26
27
28

#include "TEMPLATE_emitter.h"
#include "gen_TEMPLATE_emitter.h"
29
#include "gen_TEMPLATE_regalloc_if.h"
30
31
32
#include "TEMPLATE_nodes_attr.h"
#include "TEMPLATE_new_nodes.h"

Matthias Braun's avatar
Matthias Braun committed
33
static void TEMPLATE_emit_immediate(const ir_node *node)
34
{
35
	const TEMPLATE_attr_t *attr = get_TEMPLATE_attr_const(node);
36
	be_emit_irprintf("%T", attr->value);
37
38
}

39
40
41
42
43
44
static void TEMPLATE_emit_entity(const ir_node *node)
{
	const TEMPLATE_attr_t *attr = get_TEMPLATE_attr_const(node);
	be_emit_irprintf("%s", get_entity_ld_name(attr->entity));
}

45
46
static void emit_register(const arch_register_t *reg)
{
47
	be_emit_string(reg->name);
48
49
}

Matthias Braun's avatar
Matthias Braun committed
50
static void TEMPLATE_emit_source_register(const ir_node *node, int pos)
51
{
52
	const arch_register_t *reg = arch_get_irn_register_in(node, pos);
53
	emit_register(reg);
54
55
}

Matthias Braun's avatar
Matthias Braun committed
56
static void TEMPLATE_emit_dest_register(const ir_node *node, int pos)
57
{
58
	const arch_register_t *reg = arch_get_irn_register_out(node, pos);
59
	emit_register(reg);
60
61
62
63
64
}

/**
 * Returns the target label for a control flow node.
 */
Matthias Braun's avatar
Matthias Braun committed
65
66
static void TEMPLATE_emit_cfop_target(const ir_node *node)
{
67
	ir_node *block = (ir_node*)get_irn_link(node);
68
	be_gas_emit_block_name(block);
69
70
}

Matthias Braun's avatar
Matthias Braun committed
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
void TEMPLATE_emitf(const ir_node *node, const char *format, ...)
{
	va_list ap;
	va_start(ap, format);
	be_emit_char('\t');
	for (;;) {
		const char *start = format;
		while (*format != '%' && *format != '\0')
			++format;
		be_emit_string_len(start, format-start);
		if (*format == '\0')
			break;
		++format;

		switch (*format++) {
		case '%':
			be_emit_char('%');
			break;

		case 'S': {
			if (*format < '0' || '9' <= *format)
				goto unknown;
			unsigned const pos = *format++ - '0';
			TEMPLATE_emit_source_register(node, pos);
			break;
		}

		case 'D': {
			if (*format < '0' || '9' <= *format)
				goto unknown;
			unsigned const pos = *format++ - '0';
			TEMPLATE_emit_dest_register(node, pos);
			break;
		}

106
107
108
109
		case 'E':
			TEMPLATE_emit_entity(node);
			break;

Matthias Braun's avatar
Matthias Braun committed
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
		case 'I':
			TEMPLATE_emit_immediate(node);
			break;

		case 'X': {
			int num = va_arg(ap, int);
			be_emit_irprintf("%X", num);
			break;
		}

		case 'u': {
			unsigned num = va_arg(ap, unsigned);
			be_emit_irprintf("%u", num);
			break;
		}

		case 'd': {
			int num = va_arg(ap, int);
			be_emit_irprintf("%d", num);
			break;
		}

		case 's': {
			const char *string = va_arg(ap, const char *);
			be_emit_string(string);
			break;
		}

		case 'L': {
			TEMPLATE_emit_cfop_target(node);
			break;
		}

		case '\n':
			be_emit_char('\n');
			be_emit_write_line();
			be_emit_char('\t');
			break;

		default:
unknown:
151
			panic("unknown format conversion");
Matthias Braun's avatar
Matthias Braun committed
152
153
154
155
		}
	}
	va_end(ap);
	be_emit_finish_line_gas(node);
156

Matthias Braun's avatar
Matthias Braun committed
157
}
158

Matthias Braun's avatar
Matthias Braun committed
159
160
161
/**
 * Emits code for a unconditional jump.
 */
162
static void emit_TEMPLATE_Jmp(const ir_node *node)
Matthias Braun's avatar
Matthias Braun committed
163
{
Matthias Braun's avatar
Matthias Braun committed
164
	TEMPLATE_emitf(node, "jmp %L");
Matthias Braun's avatar
Matthias Braun committed
165
166
}

167
168
169
170
171
172
173
static void emit_be_IncSP(const ir_node *node)
{
	int offset = be_get_IncSP_offset(node);
	if (offset == 0)
		return;

	/* downwards growing stack */
Matthias Braun's avatar
Matthias Braun committed
174
175
176
	const char *op = "add";
	if (offset < 0) {
		op = "sub";
177
178
179
		offset = -offset;
	}

Matthias Braun's avatar
Matthias Braun committed
180
	TEMPLATE_emitf(node, "%s %S0, %d, %D0", op, offset);
181
182
}

183
static void emit_Start(const ir_node *node)
184
185
186
187
188
189
190
191
192
{
	ir_graph *irg        = get_irn_irg(node);
	ir_type  *frame_type = get_irg_frame_type(irg);
	unsigned  size       = get_type_size_bytes(frame_type);

	/* emit function prolog */

	/* allocate stackframe */
	if (size > 0) {
Matthias Braun's avatar
Matthias Braun committed
193
		TEMPLATE_emitf(node, "sub %%sp, %u, %%sp", size);
194
195
196
	}
}

197
static void emit_Return(const ir_node *node)
198
{
199
200
201
202
203
204
205
206
	ir_graph *irg        = get_irn_irg(node);
	ir_type  *frame_type = get_irg_frame_type(irg);
	unsigned  size       = get_type_size_bytes(frame_type);

	/* emit function epilog here */

	/* deallocate stackframe */
	if (size > 0) {
Matthias Braun's avatar
Matthias Braun committed
207
		TEMPLATE_emitf(node, "add %%sp, %u, %%sp", size);
208
209
210
	}

	/* return */
211
212
213
214
215
216
	unsigned    const n_res = get_irn_arity(node) - n_TEMPLATE_Return_first_result;
	char const *const fmt   =
		n_res == 0 ? "ret" :
		n_res == 1 ? "ret %S2" :
		"ret %S2, ...";
	TEMPLATE_emitf(node, fmt);
217
218
}

219
/**
220
221
 * Enters the emitter functions for handled nodes into the generic
 * pointer of an opcode.
222
 */
Matthias Braun's avatar
Matthias Braun committed
223
224
static void TEMPLATE_register_emitters(void)
{
225
	be_init_emitters();
226

227
228
	/* register all emitter functions defined in spec */
	TEMPLATE_register_spec_emitters();
229

230
	/* custom emitters not provided by the spec */
231
232
233
234
	be_set_emitter(op_TEMPLATE_Jmp,    emit_TEMPLATE_Jmp);
	be_set_emitter(op_TEMPLATE_Return, emit_Return);
	be_set_emitter(op_TEMPLATE_Start,  emit_Start);
	be_set_emitter(op_be_IncSP,        emit_be_IncSP);
235
}
236
237
238
239
240

/**
 * Walks over the nodes in a block connected by scheduling edges
 * and emits code for each node.
 */
241
static void TEMPLATE_emit_block(ir_node *block)
Matthias Braun's avatar
Matthias Braun committed
242
{
243
	be_gas_begin_block(block, true);
Matthias Braun's avatar
Matthias Braun committed
244
245

	sched_foreach(block, node) {
246
		be_emit_node(node);
247
248
249
250
251
252
	}
}

/**
 * Sets labels for control flow nodes (jump target)
 */
253
static void TEMPLATE_gen_labels(ir_node *block, void *env)
Matthias Braun's avatar
Matthias Braun committed
254
{
Matthias Braun's avatar
Matthias Braun committed
255
256
257
	(void)env;
	for (int n = get_Block_n_cfgpreds(block); n-- > 0; ) {
		ir_node *pred = get_Block_cfgpred(block, n);
258
259
260
261
		set_irn_link(pred, block);
	}
}

262
void TEMPLATE_emit_function(ir_graph *irg)
263
{
264
265
266
	/* register all emitter functions */
	TEMPLATE_register_emitters();

267
	/* create the block schedule */
Matthias Braun's avatar
Matthias Braun committed
268
	ir_node **block_schedule = be_create_block_schedule(irg);
269
270

	/* emit assembler prolog */
Matthias Braun's avatar
Matthias Braun committed
271
	ir_entity *entity = get_irg_entity(irg);
272
	be_gas_emit_function_prolog(entity, 4, NULL);
273
274

	/* populate jump link fields with their destinations */
275
	irg_block_walk_graph(irg, TEMPLATE_gen_labels, NULL, NULL);
276

Matthias Braun's avatar
Matthias Braun committed
277
	for (size_t i = 0, n = ARR_LEN(block_schedule); i < n; ++i) {
278
279
280
281
		ir_node *block = block_schedule[i];
		TEMPLATE_emit_block(block);
	}
	be_gas_emit_function_epilog(entity);
282
}