finished TEMPLATE backend
[libfirm] / ir / be / TEMPLATE / TEMPLATE_emitter.c
1 /* TEMPLATE emitter */
2 /* $Id$ */
3
4 #ifdef HAVE_CONFIG_H
5 #include "config.h"
6 #endif
7
8 #include <limits.h>
9
10 #include "xmalloc.h"
11 #include "tv.h"
12 #include "iredges.h"
13 #include "debug.h"
14 #include "irgwalk.h"
15 #include "irprintf.h"
16 #include "irop_t.h"
17 #include "irargs_t.h"
18
19 #include "../besched.h"
20
21 #include "TEMPLATE_emitter.h"
22 #include "gen_TEMPLATE_emitter.h"
23 #include "TEMPLATE_nodes_attr.h"
24 #include "TEMPLATE_new_nodes.h"
25 #include "TEMPLATE_map_regs.h"
26
27 #define SNPRINTF_BUF_LEN 128
28
29 static const arch_env_t *arch_env = NULL;
30
31
32 /*************************************************************
33  *             _       _    __   _          _
34  *            (_)     | |  / _| | |        | |
35  *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
36  * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
37  * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
38  * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
39  * | |                                       | |
40  * |_|                                       |_|
41  *************************************************************/
42
43 /**
44  * Return a const or symconst as string.
45  */
46 static const char *node_const_to_str(ir_node *n) {
47         /* TODO */
48 }
49
50 /**
51  * Returns node's offset as string.
52  */
53 static char *node_offset_to_str(ir_node *n) {
54         /* TODO */
55 }
56
57 /* We always pass the ir_node which is a pointer. */
58 static int TEMPLATE_get_arg_type(const lc_arg_occ_t *occ) {
59         return lc_arg_type_ptr;
60 }
61
62
63 /**
64  * Returns the register at in position pos.
65  */
66 static const arch_register_t *get_in_reg(ir_node *irn, int pos) {
67         ir_node                *op;
68         const arch_register_t  *reg = NULL;
69
70         assert(get_irn_arity(irn) > pos && "Invalid IN position");
71
72         /* The out register of the operator at position pos is the
73            in register we need. */
74         op = get_irn_n(irn, pos);
75
76         reg = arch_get_irn_register(arch_env, op);
77
78         assert(reg && "no in register found");
79         return reg;
80 }
81
82 /**
83  * Returns the register at out position pos.
84  */
85 static const arch_register_t *get_out_reg(ir_node *irn, int pos) {
86         ir_node                *proj;
87         const arch_register_t  *reg = NULL;
88
89         assert(get_irn_n_edges(irn) > pos && "Invalid OUT position");
90
91         /* 1st case: irn is not of mode_T, so it has only                 */
92         /*           one OUT register -> good                             */
93         /* 2nd case: irn is of mode_T -> collect all Projs and ask the    */
94         /*           Proj with the corresponding projnum for the register */
95
96         if (get_irn_mode(irn) != mode_T) {
97                 reg = arch_get_irn_register(arch_env, irn);
98         }
99         else if (is_TEMPLATE_irn(irn)) {
100                 reg = get_TEMPLATE_out_reg(irn, pos);
101         }
102         else {
103                 const ir_edge_t *edge;
104
105                 foreach_out_edge(irn, edge) {
106                         proj = get_edge_src_irn(edge);
107                         assert(is_Proj(proj) && "non-Proj from mode_T node");
108                         if (get_Proj_proj(proj) == pos) {
109                                 reg = arch_get_irn_register(arch_env, proj);
110                                 break;
111                         }
112                 }
113         }
114
115         assert(reg && "no out register found");
116         return reg;
117 }
118
119 /**
120  * Returns the number of the in register at position pos.
121  */
122 int get_TEMPLATE_reg_nr(ir_node *irn, int pos, int in_out) {
123         const arch_register_t *reg;
124
125         if (in_out == 1) {
126                 reg = get_in_reg(irn, pos);
127         }
128         else {
129                 reg = get_out_reg(irn, pos);
130         }
131
132         return arch_register_get_index(reg);
133 }
134
135 /**
136  * Returns the name of the in register at position pos.
137  */
138 const char *get_TEMPLATE_reg_name(ir_node *irn, int pos, int in_out) {
139         const arch_register_t *reg;
140
141         if (in_out == 1) {
142                 reg = get_in_reg(irn, pos);
143         }
144         else {
145                 reg = get_out_reg(irn, pos);
146         }
147
148         return arch_register_get_name(reg);
149 }
150
151 /**
152  * Get the register name for a node.
153  */
154 static int TEMPLATE_get_reg_name(lc_appendable_t *app,
155     const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
156 {
157         const char *buf;
158         ir_node    *X  = arg->v_ptr;
159         int         nr = occ->width - 1;
160
161         if (!X)
162                 return lc_arg_append(app, occ, "(null)", 6);
163
164         if (occ->conversion == 'S') {
165                 buf = get_TEMPLATE_reg_name(X, nr, 1);
166         }
167         else { /* 'D' */
168                 buf = get_TEMPLATE_reg_name(X, nr, 0);
169         }
170
171         lc_appendable_chadd(app, '%');
172         return lc_arg_append(app, occ, buf, strlen(buf));
173 }
174
175 /**
176  * Returns the tarval or offset of an TEMPLATE node as a string.
177  */
178 static int TEMPLATE_const_to_str(lc_appendable_t *app,
179     const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
180 {
181         const char *buf;
182         ir_node    *X = arg->v_ptr;
183
184         if (!X)
185                 return lc_arg_append(app, occ, "(null)", 6);
186
187         if (occ->conversion == 'C') {
188                 buf = node_const_to_str(X);
189         }
190         else { /* 'O' */
191                 buf = node_offset_to_str(X);
192         }
193
194         return lc_arg_append(app, occ, buf, strlen(buf));
195 }
196
197 /**
198  * Determines the SSE suffix depending on the mode.
199  */
200 static int TEMPLATE_get_mode_suffix(lc_appendable_t *app,
201     const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
202 {
203         ir_node *X = arg->v_ptr;
204
205         if (!X)
206                 return lc_arg_append(app, occ, "(null)", 6);
207
208         if (get_mode_size_bits(get_irn_mode(X)) == 32)
209                 return lc_appendable_chadd(app, 's');
210         else
211                 return lc_appendable_chadd(app, 'd');
212 }
213
214 /**
215  * Return the TEMPLATE printf arg environment.
216  * We use the firm environment with some additional handlers.
217  */
218 const lc_arg_env_t *TEMPLATE_get_arg_env(void) {
219         static lc_arg_env_t *env = NULL;
220
221         static const lc_arg_handler_t TEMPLATE_reg_handler   = { TEMPLATE_get_arg_type, TEMPLATE_get_reg_name };
222         static const lc_arg_handler_t TEMPLATE_const_handler = { TEMPLATE_get_arg_type, TEMPLATE_const_to_str };
223         static const lc_arg_handler_t TEMPLATE_mode_handler  = { TEMPLATE_get_arg_type, TEMPLATE_get_mode_suffix };
224
225         if(env == NULL) {
226                 /* extend the firm printer */
227                 env = firm_get_arg_env();
228                         //lc_arg_new_env();
229
230                 lc_arg_register(env, "TEMPLATE:sreg", 'S', &TEMPLATE_reg_handler);
231                 lc_arg_register(env, "TEMPLATE:dreg", 'D', &TEMPLATE_reg_handler);
232                 lc_arg_register(env, "TEMPLATE:cnst", 'C', &TEMPLATE_const_handler);
233                 lc_arg_register(env, "TEMPLATE:offs", 'O', &TEMPLATE_const_handler);
234                 lc_arg_register(env, "TEMPLATE:mode", 'M', &TEMPLATE_mode_handler);
235         }
236
237         return env;
238 }
239
240 /*
241  * Add a number to a prefix. This number will not be used a second time.
242  */
243 static char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
244         static unsigned long id = 0;
245         snprintf(buf, buflen, "%s%lu", prefix, ++id);
246         return buf;
247 }
248
249
250 /**
251  * Returns the target label for a control flow node.
252  */
253 static char *get_cfop_target(const ir_node *irn, char *buf) {
254         ir_node *bl = get_irn_link(irn);
255
256         snprintf(buf, SNPRINTF_BUF_LEN, "BLOCK_%ld", get_irn_node_nr(bl));
257         return buf;
258 }
259
260
261
262 /***********************************************************************************
263  *                  _          __                                             _
264  *                 (_)        / _|                                           | |
265  *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
266  * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
267  * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
268  * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
269  *
270  ***********************************************************************************/
271
272 /**
273  * Emits code for a node.
274  */
275 void TEMPLATE_emit_node(ir_node *irn, void *env) {
276         emit_env_t *emit_env   = env;
277         firm_dbg_module_t *mod = emit_env->mod;
278         FILE              *F   = emit_env->out;
279
280         DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));
281
282 #define BE_EMIT(a) if (is_TEMPLATE_##a(irn)) { emit_TEMPLATE_##a(irn, emit_env); return; }
283
284         BE_EMIT(Const);
285
286         BE_EMIT(Add);
287         BE_EMIT(Add_i);
288         BE_EMIT(Sub);
289         BE_EMIT(Sub_i);
290         BE_EMIT(Minus);
291         BE_EMIT(Inc);
292         BE_EMIT(Dec);
293
294         BE_EMIT(And);
295         BE_EMIT(And_i);
296         BE_EMIT(Or);
297         BE_EMIT(Or_i);
298         BE_EMIT(Eor);
299         BE_EMIT(Eor_i);
300         BE_EMIT(Not);
301
302         BE_EMIT(Shl);
303         BE_EMIT(Shl_i);
304         BE_EMIT(Shr);
305         BE_EMIT(Shr_i);
306         BE_EMIT(RotL);
307         BE_EMIT(RotL_i);
308         BE_EMIT(RotR);
309
310         BE_EMIT(Mul);
311         BE_EMIT(Mul_i);
312
313         BE_EMIT(Store);
314         BE_EMIT(Load);
315
316         /* generated floating point emitter */
317         BE_EMIT(fConst);
318
319         BE_EMIT(fAdd);
320         BE_EMIT(fSub);
321         BE_EMIT(fMinus);
322
323         BE_EMIT(fMul);
324         BE_EMIT(fDiv);
325
326         BE_EMIT(fMin);
327         BE_EMIT(fMax);
328
329         BE_EMIT(fLoad);
330         BE_EMIT(fStore);
331
332         ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn);
333 }
334
335 /**
336  * Walks over the nodes in a block connected by scheduling edges
337  * and emits code for each node.
338  */
339 void TEMPLATE_gen_block(ir_node *block, void *env) {
340         ir_node *irn;
341
342         if (! is_Block(block))
343                 return;
344
345         fprintf(((emit_env_t *)env)->out, "BLOCK_%ld:\n", get_irn_node_nr(block));
346         sched_foreach(block, irn) {
347                 TEMPLATE_emit_node(irn, env);
348         }
349 }
350
351
352 /**
353  * Emits code for function start.
354  */
355 void TEMPLATE_emit_start(FILE *F, ir_graph *irg) {
356         const char *irg_name = get_entity_name(get_irg_entity(irg));
357
358         /* TODO: emit function header */
359 }
360
361 /**
362  * Emits code for function end
363  */
364 void TEMPLATE_emit_end(FILE *F, ir_graph *irg) {
365         const char *irg_name = get_entity_name(get_irg_entity(irg));
366
367         /* TODO: emit function end */
368 }
369
370 /**
371  * Sets labels for control flow nodes (jump target)
372  * TODO: Jump optimization
373  */
374 void TEMPLATE_gen_labels(ir_node *block, void *env) {
375         ir_node *pred;
376         int n = get_Block_n_cfgpreds(block);
377
378         for (n--; n >= 0; n--) {
379                 pred = get_Block_cfgpred(block, n);
380                 set_irn_link(pred, block);
381         }
382 }
383
384 /**
385  * Main driver
386  */
387 void TEMPLATE_gen_routine(FILE *F, ir_graph *irg, const TEMPLATE_code_gen_t *cg) {
388         emit_env_t emit_env;
389
390         emit_env.mod      = firm_dbg_register("firm.be.TEMPLATE.emit");
391         emit_env.out      = F;
392         emit_env.arch_env = cg->arch_env;
393         emit_env.cg       = cg;
394
395         /* set the global arch_env (needed by print hooks) */
396         arch_env = cg->arch_env;
397
398         TEMPLATE_emit_start(F, irg);
399         irg_block_walk_graph(irg, TEMPLATE_gen_labels, NULL, &emit_env);
400         irg_walk_blkwise_graph(irg, NULL, TEMPLATE_gen_block, &emit_env);
401         TEMPLATE_emit_end(F, irg);
402 }