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