752d348b81e40dc2bb07db536854cb9eaee53e23
[libfirm] / ir / be / TEMPLATE / TEMPLATE_emitter.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   emit assembler for a backend graph
23  */
24 #include "config.h"
25
26 #include <limits.h>
27
28 #include "xmalloc.h"
29 #include "tv.h"
30 #include "iredges.h"
31 #include "debug.h"
32 #include "irgwalk.h"
33 #include "irprintf.h"
34 #include "irop_t.h"
35 #include "irargs_t.h"
36 #include "irprog.h"
37
38 #include "besched.h"
39 #include "begnuas.h"
40 #include "beblocksched.h"
41 #include "benode.h"
42
43 #include "TEMPLATE_emitter.h"
44 #include "gen_TEMPLATE_emitter.h"
45 #include "gen_TEMPLATE_regalloc_if.h"
46 #include "TEMPLATE_nodes_attr.h"
47 #include "TEMPLATE_new_nodes.h"
48
49 #define SNPRINTF_BUF_LEN 128
50
51 void TEMPLATE_emit_immediate(const ir_node *node)
52 {
53         const TEMPLATE_attr_t *attr = get_TEMPLATE_attr_const(node);
54         be_emit_tarval(attr->value);
55 }
56
57 static void emit_register(const arch_register_t *reg)
58 {
59         be_emit_string(arch_register_get_name(reg));
60 }
61
62 void TEMPLATE_emit_source_register(const ir_node *node, int pos)
63 {
64         const arch_register_t *reg = arch_get_irn_register_in(node, pos);
65         emit_register(reg);
66 }
67
68 void TEMPLATE_emit_dest_register(const ir_node *node, int pos)
69 {
70         const arch_register_t *reg = arch_get_irn_register_out(node, pos);
71         emit_register(reg);
72 }
73
74 /**
75  * Returns the target label for a control flow node.
76  */
77 static void TEMPLATE_emit_cfop_target(const ir_node *node)
78 {
79         ir_node *block = (ir_node*)get_irn_link(node);
80         be_gas_emit_block_name(block);
81 }
82
83
84
85 /**
86  * Emits code for a unconditional jump.
87  */
88 static void emit_TEMPLATE_Jmp(const ir_node *node)
89 {
90         be_emit_cstring("\tjmp ");
91         TEMPLATE_emit_cfop_target(node);
92         be_emit_finish_line_gas(node);
93 }
94
95 static void emit_be_IncSP(const ir_node *node)
96 {
97         int offset = be_get_IncSP_offset(node);
98
99         if (offset == 0)
100                 return;
101
102         /* downwards growing stack */
103         if (offset > 0) {
104                 be_emit_cstring("\tsub ");
105         } else {
106                 be_emit_cstring("\tadd ");
107                 offset = -offset;
108         }
109
110         TEMPLATE_emit_source_register(node, 0);
111         be_emit_irprintf(", %d, ", offset);
112         TEMPLATE_emit_dest_register(node, 0);
113         be_emit_finish_line_gas(node);
114 }
115
116 static void emit_be_Start(const ir_node *node)
117 {
118         ir_graph *irg        = get_irn_irg(node);
119         ir_type  *frame_type = get_irg_frame_type(irg);
120         unsigned  size       = get_type_size_bytes(frame_type);
121
122         /* emit function prolog */
123
124         /* allocate stackframe */
125         if (size > 0) {
126                 be_emit_cstring("\tsub ");
127                 emit_register(&TEMPLATE_registers[REG_SP]);
128                 be_emit_irprintf(", %u, ", size);
129                 emit_register(&TEMPLATE_registers[REG_SP]);
130                 be_emit_finish_line_gas(node);
131         }
132 }
133
134 static void emit_be_Return(const ir_node *node)
135 {
136         ir_graph *irg        = get_irn_irg(node);
137         ir_type  *frame_type = get_irg_frame_type(irg);
138         unsigned  size       = get_type_size_bytes(frame_type);
139
140         /* emit function epilog here */
141
142         /* deallocate stackframe */
143         if (size > 0) {
144                 be_emit_cstring("\tadd ");
145                 emit_register(&TEMPLATE_registers[REG_SP]);
146                 be_emit_irprintf(", %u, ", size);
147                 emit_register(&TEMPLATE_registers[REG_SP]);
148                 be_emit_finish_line_gas(node);
149         }
150
151         /* return */
152         be_emit_cstring("\tret");
153         be_emit_finish_line_gas(node);
154 }
155
156 static void emit_nothing(const ir_node *node)
157 {
158         (void) node;
159 }
160
161 /**
162  * The type of a emitter function.
163  */
164 typedef void (emit_func)(const ir_node *node);
165
166 static inline void set_emitter(ir_op *op, emit_func func)
167 {
168         op->ops.generic = (op_func)func;
169 }
170
171 /**
172  * Enters the emitter functions for handled nodes into the generic
173  * pointer of an opcode.
174  */
175 static void TEMPLATE_register_emitters(void)
176 {
177         /* first clear the generic function pointer for all ops */
178         ir_clear_opcodes_generic_func();
179
180         /* register all emitter functions defined in spec */
181         TEMPLATE_register_spec_emitters();
182
183         /* custom emitters not provided by the spec */
184         set_emitter(op_TEMPLATE_Jmp,   emit_TEMPLATE_Jmp);
185         set_emitter(op_be_IncSP,       emit_be_IncSP);
186         set_emitter(op_be_Return,      emit_be_Return);
187         set_emitter(op_be_Start,       emit_be_Start);
188
189         /* no need to emit anything for the following nodes */
190         set_emitter(op_Phi,            emit_nothing);
191         set_emitter(op_be_Keep,        emit_nothing);
192 }
193
194 typedef void (*emit_func_ptr) (const ir_node *);
195
196 /**
197  * Emits code for a node.
198  */
199 static void TEMPLATE_emit_node(const ir_node *node)
200 {
201         ir_op               *op       = get_irn_op(node);
202
203         if (op->ops.generic) {
204                 emit_func_ptr func = (emit_func_ptr) op->ops.generic;
205                 (*func) (node);
206         } else {
207                 ir_fprintf(stderr, "No emitter for node %+F\n", node);
208         }
209 }
210
211 /**
212  * Walks over the nodes in a block connected by scheduling edges
213  * and emits code for each node.
214  */
215 static void TEMPLATE_emit_block(ir_node *block)
216 {
217         ir_node *node;
218
219         be_gas_emit_block_name(block);
220         be_emit_cstring(":\n");
221         be_emit_write_line();
222
223         sched_foreach(block, node) {
224                 TEMPLATE_emit_node(node);
225         }
226 }
227
228 /**
229  * Sets labels for control flow nodes (jump target)
230  */
231 static void TEMPLATE_gen_labels(ir_node *block, void *env)
232 {
233         ir_node *pred;
234         int n = get_Block_n_cfgpreds(block);
235         (void) env;
236
237         for (n--; n >= 0; n--) {
238                 pred = get_Block_cfgpred(block, n);
239                 set_irn_link(pred, block);
240         }
241 }
242
243 /**
244  * Main driver
245  */
246 void TEMPLATE_emit_routine(ir_graph *irg)
247 {
248         ir_node   **block_schedule;
249         ir_entity  *entity = get_irg_entity(irg);
250         size_t      i;
251         size_t      n;
252
253         /* register all emitter functions */
254         TEMPLATE_register_emitters();
255
256         /* create the block schedule */
257         block_schedule = be_create_block_schedule(irg);
258
259         /* emit assembler prolog */
260         be_gas_emit_function_prolog(entity, 4);
261
262         /* populate jump link fields with their destinations */
263         irg_block_walk_graph(irg, TEMPLATE_gen_labels, NULL, NULL);
264
265         n = ARR_LEN(block_schedule);
266         for (i = 0; i < n; ++i) {
267                 ir_node *block = block_schedule[i];
268                 TEMPLATE_emit_block(block);
269         }
270         be_gas_emit_function_epilog(entity);
271 }