0a8f0108cdb737199f1a28f18d34e1fd5f763c0a
[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 void TEMPLATE_emit_immediate(const ir_node *node)
50 {
51         const TEMPLATE_attr_t *attr = get_TEMPLATE_attr_const(node);
52         be_emit_irprintf("%T", attr->value);
53 }
54
55 static void emit_register(const arch_register_t *reg)
56 {
57         be_emit_string(arch_register_get_name(reg));
58 }
59
60 void TEMPLATE_emit_source_register(const ir_node *node, int pos)
61 {
62         const arch_register_t *reg = arch_get_irn_register_in(node, pos);
63         emit_register(reg);
64 }
65
66 void TEMPLATE_emit_dest_register(const ir_node *node, int pos)
67 {
68         const arch_register_t *reg = arch_get_irn_register_out(node, pos);
69         emit_register(reg);
70 }
71
72 /**
73  * Returns the target label for a control flow node.
74  */
75 static void TEMPLATE_emit_cfop_target(const ir_node *node)
76 {
77         ir_node *block = (ir_node*)get_irn_link(node);
78         be_gas_emit_block_name(block);
79 }
80
81
82
83 /**
84  * Emits code for a unconditional jump.
85  */
86 static void emit_TEMPLATE_Jmp(const ir_node *node)
87 {
88         be_emit_cstring("\tjmp ");
89         TEMPLATE_emit_cfop_target(node);
90         be_emit_finish_line_gas(node);
91 }
92
93 static void emit_be_IncSP(const ir_node *node)
94 {
95         int offset = be_get_IncSP_offset(node);
96
97         if (offset == 0)
98                 return;
99
100         /* downwards growing stack */
101         if (offset > 0) {
102                 be_emit_cstring("\tsub ");
103         } else {
104                 be_emit_cstring("\tadd ");
105                 offset = -offset;
106         }
107
108         TEMPLATE_emit_source_register(node, 0);
109         be_emit_irprintf(", %d, ", offset);
110         TEMPLATE_emit_dest_register(node, 0);
111         be_emit_finish_line_gas(node);
112 }
113
114 static void emit_be_Start(const ir_node *node)
115 {
116         ir_graph *irg        = get_irn_irg(node);
117         ir_type  *frame_type = get_irg_frame_type(irg);
118         unsigned  size       = get_type_size_bytes(frame_type);
119
120         /* emit function prolog */
121
122         /* allocate stackframe */
123         if (size > 0) {
124                 be_emit_cstring("\tsub ");
125                 emit_register(&TEMPLATE_registers[REG_SP]);
126                 be_emit_irprintf(", %u, ", size);
127                 emit_register(&TEMPLATE_registers[REG_SP]);
128                 be_emit_finish_line_gas(node);
129         }
130 }
131
132 static void emit_be_Return(const ir_node *node)
133 {
134         ir_graph *irg        = get_irn_irg(node);
135         ir_type  *frame_type = get_irg_frame_type(irg);
136         unsigned  size       = get_type_size_bytes(frame_type);
137
138         /* emit function epilog here */
139
140         /* deallocate stackframe */
141         if (size > 0) {
142                 be_emit_cstring("\tadd ");
143                 emit_register(&TEMPLATE_registers[REG_SP]);
144                 be_emit_irprintf(", %u, ", size);
145                 emit_register(&TEMPLATE_registers[REG_SP]);
146                 be_emit_finish_line_gas(node);
147         }
148
149         /* return */
150         be_emit_cstring("\tret");
151         be_emit_finish_line_gas(node);
152 }
153
154 static void emit_nothing(const ir_node *node)
155 {
156         (void) node;
157 }
158
159 /**
160  * The type of a emitter function.
161  */
162 typedef void (emit_func)(const ir_node *node);
163
164 static inline void set_emitter(ir_op *op, emit_func func)
165 {
166         op->ops.generic = (op_func)func;
167 }
168
169 /**
170  * Enters the emitter functions for handled nodes into the generic
171  * pointer of an opcode.
172  */
173 static void TEMPLATE_register_emitters(void)
174 {
175         /* first clear the generic function pointer for all ops */
176         ir_clear_opcodes_generic_func();
177
178         /* register all emitter functions defined in spec */
179         TEMPLATE_register_spec_emitters();
180
181         /* custom emitters not provided by the spec */
182         set_emitter(op_TEMPLATE_Jmp,   emit_TEMPLATE_Jmp);
183         set_emitter(op_be_IncSP,       emit_be_IncSP);
184         set_emitter(op_be_Return,      emit_be_Return);
185         set_emitter(op_be_Start,       emit_be_Start);
186
187         /* no need to emit anything for the following nodes */
188         set_emitter(op_Phi,            emit_nothing);
189         set_emitter(op_be_Keep,        emit_nothing);
190 }
191
192 typedef void (*emit_func_ptr) (const ir_node *);
193
194 /**
195  * Emits code for a node.
196  */
197 static void TEMPLATE_emit_node(const ir_node *node)
198 {
199         ir_op               *op       = get_irn_op(node);
200
201         if (op->ops.generic) {
202                 emit_func_ptr func = (emit_func_ptr) op->ops.generic;
203                 (*func) (node);
204         } else {
205                 ir_fprintf(stderr, "No emitter for node %+F\n", node);
206         }
207 }
208
209 /**
210  * Walks over the nodes in a block connected by scheduling edges
211  * and emits code for each node.
212  */
213 static void TEMPLATE_emit_block(ir_node *block)
214 {
215         ir_node *node;
216
217         be_gas_emit_block_name(block);
218         be_emit_cstring(":\n");
219         be_emit_write_line();
220
221         sched_foreach(block, node) {
222                 TEMPLATE_emit_node(node);
223         }
224 }
225
226 /**
227  * Sets labels for control flow nodes (jump target)
228  */
229 static void TEMPLATE_gen_labels(ir_node *block, void *env)
230 {
231         ir_node *pred;
232         int n = get_Block_n_cfgpreds(block);
233         (void) env;
234
235         for (n--; n >= 0; n--) {
236                 pred = get_Block_cfgpred(block, n);
237                 set_irn_link(pred, block);
238         }
239 }
240
241 /**
242  * Main driver
243  */
244 void TEMPLATE_emit_routine(ir_graph *irg)
245 {
246         ir_node   **block_schedule;
247         ir_entity  *entity = get_irg_entity(irg);
248         size_t      i;
249         size_t      n;
250
251         /* register all emitter functions */
252         TEMPLATE_register_emitters();
253
254         /* create the block schedule */
255         block_schedule = be_create_block_schedule(irg);
256
257         /* emit assembler prolog */
258         be_gas_emit_function_prolog(entity, 4, NULL);
259
260         /* populate jump link fields with their destinations */
261         irg_block_walk_graph(irg, TEMPLATE_gen_labels, NULL, NULL);
262
263         n = ARR_LEN(block_schedule);
264         for (i = 0; i < n; ++i) {
265                 ir_node *block = block_schedule[i];
266                 TEMPLATE_emit_block(block);
267         }
268         be_gas_emit_function_epilog(entity);
269 }