TEMPLATE_emitter.c 5.75 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 "TEMPLATE_emitter.h"
#include "TEMPLATE_new_nodes.h"
12
#include "bearch.h"
13
#include "beblocksched.h"
14
#include "begnuas.h"
15
#include "benode.h"
16
#include "besched.h"
17
#include "gen_TEMPLATE_emitter.h"
18
19
#include "irgwalk.h"
#include "panic.h"
20
#include "util.h"
21

Matthias Braun's avatar
Matthias Braun committed
22
static void TEMPLATE_emit_immediate(const ir_node *node)
23
{
24
25
26
27
28
29
30
31
32
33
	TEMPLATE_attr_t const *const attr = get_TEMPLATE_attr_const(node);
	ir_entity             *const ent  = attr->entity;
	ir_tarval             *const val  = attr->value;
	if (ent) {
		be_emit_irprintf("&%s", get_entity_ld_name(ent));
		if (val)
			be_emit_char('+');
	}
	if (val)
		be_emit_irprintf("%T", val);
34
35
}

36
37
static void emit_register(const arch_register_t *reg)
{
38
	be_emit_string(reg->name);
39
40
}

Matthias Braun's avatar
Matthias Braun committed
41
static void TEMPLATE_emit_source_register(const ir_node *node, int pos)
42
{
43
	const arch_register_t *reg = arch_get_irn_register_in(node, pos);
44
	emit_register(reg);
45
46
}

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

/**
 * Returns the target label for a control flow node.
 */
Matthias Braun's avatar
Matthias Braun committed
56
57
static void TEMPLATE_emit_cfop_target(const ir_node *node)
{
58
	ir_node *block = (ir_node*)get_irn_link(node);
59
	be_gas_emit_block_name(block);
60
61
}

Matthias Braun's avatar
Matthias Braun committed
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
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': {
82
			if (!is_digit(*format))
Matthias Braun's avatar
Matthias Braun committed
83
84
85
86
87
88
89
				goto unknown;
			unsigned const pos = *format++ - '0';
			TEMPLATE_emit_source_register(node, pos);
			break;
		}

		case 'D': {
90
			if (!is_digit(*format))
Matthias Braun's avatar
Matthias Braun committed
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
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
				goto unknown;
			unsigned const pos = *format++ - '0';
			TEMPLATE_emit_dest_register(node, pos);
			break;
		}

		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:
138
			panic("unknown format conversion");
Matthias Braun's avatar
Matthias Braun committed
139
140
141
142
		}
	}
	va_end(ap);
	be_emit_finish_line_gas(node);
143

Matthias Braun's avatar
Matthias Braun committed
144
}
145

Matthias Braun's avatar
Matthias Braun committed
146
147
148
/**
 * Emits code for a unconditional jump.
 */
149
static void emit_TEMPLATE_Jmp(const ir_node *node)
Matthias Braun's avatar
Matthias Braun committed
150
{
Matthias Braun's avatar
Matthias Braun committed
151
	TEMPLATE_emitf(node, "jmp %L");
Matthias Braun's avatar
Matthias Braun committed
152
153
}

154
155
156
157
158
159
160
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
161
162
163
	const char *op = "add";
	if (offset < 0) {
		op = "sub";
164
165
166
		offset = -offset;
	}

Matthias Braun's avatar
Matthias Braun committed
167
	TEMPLATE_emitf(node, "%s %S0, %d, %D0", op, offset);
168
169
}

170
static void emit_Start(const ir_node *node)
171
172
173
174
175
176
177
178
179
{
	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
180
		TEMPLATE_emitf(node, "sub %%sp, %u, %%sp", size);
181
182
183
	}
}

184
static void emit_Return(const ir_node *node)
185
{
186
187
188
189
190
191
192
193
	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
194
		TEMPLATE_emitf(node, "add %%sp, %u, %%sp", size);
195
196
197
	}

	/* return */
198
199
200
201
202
203
	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);
204
205
}

206
/**
207
208
 * Enters the emitter functions for handled nodes into the generic
 * pointer of an opcode.
209
 */
Matthias Braun's avatar
Matthias Braun committed
210
211
static void TEMPLATE_register_emitters(void)
{
212
	be_init_emitters();
213

214
215
	/* register all emitter functions defined in spec */
	TEMPLATE_register_spec_emitters();
216

217
	/* custom emitters not provided by the spec */
218
219
220
221
	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);
222
}
223
224
225
226
227

/**
 * Walks over the nodes in a block connected by scheduling edges
 * and emits code for each node.
 */
228
static void TEMPLATE_emit_block(ir_node *block)
Matthias Braun's avatar
Matthias Braun committed
229
{
230
	be_gas_begin_block(block, true);
Matthias Braun's avatar
Matthias Braun committed
231
232

	sched_foreach(block, node) {
233
		be_emit_node(node);
234
235
236
237
238
239
	}
}

/**
 * Sets labels for control flow nodes (jump target)
 */
240
static void TEMPLATE_gen_labels(ir_node *block, void *env)
Matthias Braun's avatar
Matthias Braun committed
241
{
Matthias Braun's avatar
Matthias Braun committed
242
243
244
	(void)env;
	for (int n = get_Block_n_cfgpreds(block); n-- > 0; ) {
		ir_node *pred = get_Block_cfgpred(block, n);
245
246
247
248
		set_irn_link(pred, block);
	}
}

249
void TEMPLATE_emit_function(ir_graph *irg)
250
{
251
252
253
	/* register all emitter functions */
	TEMPLATE_register_emitters();

254
	/* create the block schedule */
Matthias Braun's avatar
Matthias Braun committed
255
	ir_node **block_schedule = be_create_block_schedule(irg);
256
257

	/* emit assembler prolog */
Matthias Braun's avatar
Matthias Braun committed
258
	ir_entity *entity = get_irg_entity(irg);
259
	be_gas_emit_function_prolog(entity, 4, NULL);
260
261

	/* populate jump link fields with their destinations */
262
	ir_reserve_resources(irg, IR_RESOURCE_IRN_LINK);
263
	irg_block_walk_graph(irg, TEMPLATE_gen_labels, NULL, NULL);
264

Matthias Braun's avatar
Matthias Braun committed
265
	for (size_t i = 0, n = ARR_LEN(block_schedule); i < n; ++i) {
266
267
268
		ir_node *block = block_schedule[i];
		TEMPLATE_emit_block(block);
	}
269
270
	ir_free_resources(irg, IR_RESOURCE_IRN_LINK);

271
	be_gas_emit_function_epilog(entity);
272
}