used new be_set_spill_env_dbg_module()
[libfirm] / ir / be / arm / arm_emitter.c
1 /* arm 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 "irprog_t.h"
18 #include "irargs_t.h"
19
20 #include "../besched.h"
21
22 #include "arm_emitter.h"
23 #include "gen_arm_emitter.h"
24 #include "arm_nodes_attr.h"
25 #include "arm_new_nodes.h"
26 #include "arm_map_regs.h"
27 #include "gen_arm_regalloc_if.h"
28
29 #include "../benode_t.h"
30
31 #define SNPRINTF_BUF_LEN 128
32
33 static const arch_env_t *arch_env = NULL;
34
35
36 /*************************************************************
37  *             _       _    __   _          _
38  *            (_)     | |  / _| | |        | |
39  *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
40  * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
41  * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
42  * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
43  * | |                                       | |
44  * |_|                                       |_|
45  *************************************************************/
46
47 int is_immediate_node(ir_node *irn) {
48         if (is_arm_Add_i(irn) || is_arm_Sub_i(irn))
49                 return 1;
50         if (is_arm_Shr_i(irn) || is_arm_Shr_i(irn) || is_arm_Shl_i(irn))
51                 return 1;
52         if (is_arm_And_i(irn) || is_arm_Or_i(irn) || is_arm_Eor_i(irn))
53                 return 1;
54         if (is_arm_Or_Shl_i(irn))
55                 return 1;
56         return 0;
57 }
58
59 /**
60  * Return a const or symconst as string.
61  */
62 static const char *node_const_to_str(ir_node *n) {
63         char buffer[SNPRINTF_BUF_LEN];
64
65         if ( is_immediate_node(n) ) {
66                 long longvalue = get_tarval_long(get_arm_value(n));
67                 char *str;
68                 assert(longvalue < 0x1000 && "constant doesn't fit in shifter_operand");
69                 snprintf(buffer, SNPRINTF_BUF_LEN - 1, "#%ld << %ld", longvalue & 0xff, (longvalue >> 8) << 1 );
70                 str = xmalloc(strlen(buffer) * sizeof(char));
71                 strcpy(str, buffer);
72                 return str;
73         }
74         if ( is_arm_Const(n) || is_arm_Const_Neg(n) ) {
75                 tarval *tv = get_arm_value(n);
76                 if ( mode_is_int(get_tarval_mode(tv)) ) {
77                         long longvalue = get_tarval_long(get_arm_value(n));
78                         char *str;
79                         assert(longvalue < 0x1000 && "constant doesn't fit in shifter_operand");
80                         snprintf(buffer, SNPRINTF_BUF_LEN - 1, "#%ld << %ld", longvalue & 0xff, (longvalue >> 8) << 1 );
81                         str = xmalloc(strlen(buffer) * sizeof(char));
82                         strcpy(str, buffer);
83                         return str;
84                 } else {
85                         return "found something else in arm_const";
86                 }
87         } else if ( is_arm_SymConst(n) ) {
88                 return get_arm_symconst_label(n);
89         } else {
90                 assert( 0 && "das ist gar keine Konstante");
91                 return NULL;
92         }
93
94 }
95
96 /**
97  * Returns node's offset as string.
98  */
99 static char *node_offset_to_str(ir_node *n) {
100         char buffer[SNPRINTF_BUF_LEN];
101         char *result;
102         int offset = 0;
103         ir_op *irn_op = get_irn_op(n);
104         if (irn_op == op_be_StackParam) {
105                 entity *ent = be_get_frame_entity(n);
106                 offset = get_entity_offset_bytes(ent);
107         } else if (irn_op==op_be_Reload || irn_op==op_be_Spill) {
108                 entity * ent = be_get_spill_entity(n);
109                 offset = get_entity_offset_bytes(ent);
110         } else if (irn_op==op_be_IncSP) {
111                 int offs = be_get_IncSP_offset(n);
112                 be_stack_dir_t dir  = be_get_IncSP_direction(n);
113                 offset = (dir == be_stack_dir_expand) ? -offs : offs;
114         } else {
115                 return "node_offset_to_str will fuer diesen Knotentyp noch implementiert werden";
116         }
117         snprintf(buffer, SNPRINTF_BUF_LEN, "%d", offset);
118         result = xmalloc(sizeof(char)*(strlen(buffer) + 1));
119         strcpy(result, buffer);
120         return result;
121 }
122
123 /* We always pass the ir_node which is a pointer. */
124 static int arm_get_arg_type(const lc_arg_occ_t *occ) {
125         return lc_arg_type_ptr;
126 }
127
128
129 /**
130  * Returns the register at in position pos.
131  */
132 static const arch_register_t *get_in_reg(const ir_node *irn, int pos) {
133         ir_node                *op;
134         const arch_register_t  *reg = NULL;
135
136         assert(get_irn_arity(irn) > pos && "Invalid IN position");
137
138         /* The out register of the operator at position pos is the
139            in register we need. */
140         op = get_irn_n(irn, pos);
141
142         reg = arch_get_irn_register(arch_env, op);
143
144         /* ONLY TEMPORARY WORK-AROUND */
145 //      if (!reg) {
146 //              printf("FIXME\n");
147 //              reg = &arm_general_purpose_regs[REG_MURX];
148 //      }
149
150         assert(reg && "no in register found");
151         return reg;
152 }
153
154 /**
155  * Returns the register at out position pos.
156  */
157 static const arch_register_t *get_out_reg(const ir_node *irn, int pos) {
158         ir_node                *proj;
159         const arch_register_t  *reg = NULL;
160
161         assert(get_irn_n_edges(irn) > pos && "Invalid OUT position");
162
163         /* 1st case: irn is not of mode_T, so it has only                 */
164         /*           one OUT register -> good                             */
165         /* 2nd case: irn is of mode_T -> collect all Projs and ask the    */
166         /*           Proj with the corresponding projnum for the register */
167
168         if (get_irn_mode(irn) != mode_T) {
169                 reg = arch_get_irn_register(arch_env, irn);
170         }
171         else if (is_arm_irn(irn)) {
172                 reg = get_arm_out_reg(irn, pos);
173         }
174         else {
175                 const ir_edge_t *edge;
176
177                 foreach_out_edge(irn, edge) {
178                         proj = get_edge_src_irn(edge);
179                         assert(is_Proj(proj) && "non-Proj from mode_T node");
180                         if (get_Proj_proj(proj) == pos) {
181                                 reg = arch_get_irn_register(arch_env, proj);
182                                 break;
183                         }
184                 }
185         }
186
187         assert(reg && "no out register found");
188         return reg;
189 }
190
191 /**
192  * Returns the number of the in register at position pos.
193  */
194 int get_arm_reg_nr(ir_node *irn, int pos, int in_out) {
195         const arch_register_t *reg;
196
197         if (in_out == 1) {
198                 reg = get_in_reg(irn, pos);
199         }
200         else {
201                 reg = get_out_reg(irn, pos);
202         }
203
204         return arch_register_get_index(reg);
205 }
206
207 /**
208  * Returns the name of the in register at position pos.
209  */
210 const char *get_arm_reg_name(ir_node *irn, int pos, int in_out) {
211         const arch_register_t *reg;
212
213         if (in_out == 1) {
214                 reg = get_in_reg(irn, pos);
215         }
216         else {
217                 reg = get_out_reg(irn, pos);
218         }
219
220         return arch_register_get_name(reg);
221 }
222
223 /**
224  * Get the register name for a node.
225  */
226 static int arm_get_reg_name(lc_appendable_t *app,
227     const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
228 {
229         const char *buf;
230         ir_node    *X  = arg->v_ptr;
231         int         nr = occ->width - 1;
232
233         if (!X)
234                 return lc_appendable_snadd(app, "(null)", 6);
235
236         if (occ->conversion == 'S') {
237                 buf = get_arm_reg_name(X, nr, 1);
238         }
239         else { /* 'D' */
240                 buf = get_arm_reg_name(X, nr, 0);
241         }
242
243         lc_appendable_chadd(app, '%');
244         return lc_appendable_snadd(app, buf, strlen(buf));
245 }
246
247 /**
248  * Returns the tarval or offset of an arm node as a string.
249  */
250 static int arm_const_to_str(lc_appendable_t *app,
251     const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
252 {
253         const char *buf;
254         ir_node    *X = arg->v_ptr;
255
256         if (!X)
257                 return lc_appendable_snadd(app, "(null)", 6);
258
259         if (occ->conversion == 'C') {
260                 buf = node_const_to_str(X);
261         }
262         else { /* 'O' */
263                 buf = node_offset_to_str(X);
264         }
265
266         return lc_appendable_snadd(app, buf, strlen(buf));
267 }
268
269 /**
270  * Determines the SSE suffix depending on the mode.
271  */
272 static int arm_get_mode_suffix(lc_appendable_t *app,
273     const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
274 {
275         ir_node *X = arg->v_ptr;
276
277         if (!X)
278                 return lc_appendable_snadd(app, "(null)", 6);
279
280         if (get_mode_size_bits(get_irn_mode(X)) == 32)
281                 return lc_appendable_chadd(app, 's');
282         else
283                 return lc_appendable_chadd(app, 'd');
284 }
285
286 /**
287  * Return the arm printf arg environment.
288  * We use the firm environment with some additional handlers.
289  */
290 const lc_arg_env_t *arm_get_arg_env(void) {
291         static lc_arg_env_t *env = NULL;
292
293         static const lc_arg_handler_t arm_reg_handler   = { arm_get_arg_type, arm_get_reg_name };
294         static const lc_arg_handler_t arm_const_handler = { arm_get_arg_type, arm_const_to_str };
295         static const lc_arg_handler_t arm_mode_handler  = { arm_get_arg_type, arm_get_mode_suffix };
296
297         if(env == NULL) {
298                 /* extend the firm printer */
299                 env = firm_get_arg_env();
300                         //lc_arg_new_env();
301
302                 lc_arg_register(env, "arm:sreg", 'S', &arm_reg_handler);
303                 lc_arg_register(env, "arm:dreg", 'D', &arm_reg_handler);
304                 lc_arg_register(env, "arm:cnst", 'C', &arm_const_handler);
305                 lc_arg_register(env, "arm:offs", 'O', &arm_const_handler);
306                 lc_arg_register(env, "arm:mode", 'M', &arm_mode_handler);
307         }
308
309         return env;
310 }
311
312 /**
313  * Formated print of commands and comments.
314  */
315 static void arm_fprintf_format(FILE *F, char *cmd_buf, char *cmnt_buf, ir_node *irn) {
316         lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
317 }
318
319 /*
320  * Add a number to a prefix. This number will not be used a second time.
321  */
322 static char *get_unique_label(char *buf, size_t buflen, const char *prefix) {
323         static unsigned long id = 0;
324         snprintf(buf, buflen, "%s%lu", prefix, ++id);
325         return buf;
326 }
327
328
329 /**
330  * Returns the target label for a control flow node.
331  */
332 static char *get_cfop_target(const ir_node *irn, char *buf) {
333         ir_node *bl = get_irn_link(irn);
334
335         snprintf(buf, SNPRINTF_BUF_LEN, "BLOCK_%ld", get_irn_node_nr(bl));
336         return buf;
337 }
338
339 /************************************************************************/
340 /* emit_arm                                                             */
341 /************************************************************************/
342
343 static void emit_arm_SymConst(ir_node *irn, void *env) {
344         arm_emit_env_t *emit_env = env;
345         FILE *out = emit_env->out;
346         char buffer1[SNPRINTF_BUF_LEN];
347         char *skip_label = get_unique_label(buffer1, SNPRINTF_BUF_LEN, ".L");
348         char buffer2[SNPRINTF_BUF_LEN];
349         char *indi_label = get_unique_label(buffer2, SNPRINTF_BUF_LEN, ".L");
350         fprintf( out, "\tB %s\t\t\t\t\t/* start of indirect SymConst */\n", skip_label );
351         fprintf( out, "\t.align 2\n" );
352         fprintf( out, "%s:\n", indi_label );
353         lc_efprintf(arm_get_arg_env(), out, "\t.word\t%C\n", irn);
354         fprintf( out, "\t.align 2\n" );
355         fprintf( out, "%s:\n", skip_label );
356         lc_efprintf(arm_get_arg_env(), out, "\tLDR %1D, %s\t\t\t/* end of indirect SymConst */\n", irn, indi_label);
357 }
358
359 static void emit_arm_CondJmp(ir_node *irn, void *env) {
360         arm_emit_env_t *emit_env = env;
361         FILE *out = emit_env->out;
362         const ir_edge_t *edge;
363         ir_node *true_block = NULL;
364         ir_node *false_block = NULL;
365         ir_node *op1 = get_irn_n(irn, 0);
366         ir_mode *opmode = get_irn_mode(op1);
367         char *suffix;
368         int proj_num = get_arm_proj_num(irn);
369         char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
370
371
372         foreach_out_edge(irn, edge) {
373                 ir_node* proj = get_edge_src_irn(edge);
374                 long nr = get_Proj_proj(proj);
375                 ir_node *block = get_irn_link(proj);
376                 if ( nr == pn_Cond_true) {
377                         true_block = block;
378                 } else if (nr == pn_Cond_false) {
379                         false_block = block;
380                 } else {
381                         assert(0 && "tertium non datur! (CondJmp)");
382                 }
383         }
384
385         if (proj_num == pn_Cmp_False) {
386                 fprintf(out, "\tB BLOCK_%ld\t\t\t/* false case */\n", get_irn_node_nr(false_block));
387         } else if (proj_num == pn_Cmp_True) {
388                 fprintf(out, "\tB BLOCK_%ld\t\t\t/* true case */\n", get_irn_node_nr(true_block));
389         } else {
390                 if (mode_is_float(opmode)) {
391                         suffix = "ICHWILLIMPLEMENTIERTWERDEN";
392
393                         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "FCMP %1S, %2S", irn, irn);
394                         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Compare(%1S, %2S) -> FCPSR */", irn, irn );
395                         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
396
397                         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "FMSTAT", irn, irn);
398                         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* FCSPR -> CPSR */");
399                         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
400
401                         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B%s BLOCK_%d", suffix, get_irn_node_nr(true_block));
402                         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* true case */");
403                         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
404
405                         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B BLOCK_%d", get_irn_node_nr(false_block));
406                         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* false case */");
407                         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
408                 } else {
409                         switch(proj_num) {
410                                 case pn_Cmp_Eq:  suffix = "EQ"; break;
411                                 case pn_Cmp_Lt:  suffix = "LT"; break;
412                                 case pn_Cmp_Le:  suffix = "LE"; break;
413                                 case pn_Cmp_Gt:  suffix = "GT"; break;
414                                 case pn_Cmp_Ge:  suffix = "GE"; break;
415                                 case pn_Cmp_Lg:  suffix = "NE"; break;
416                                 case pn_Cmp_Leg: suffix = "AL"; break;
417                         default: assert(0 && "komische Dinge geschehen");
418                         }
419
420                         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "CMP %1S, %2S", irn, irn);
421                         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Compare(%1S, %2S) -> CPSR */", irn, irn );
422                         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
423
424                         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B%s BLOCK_%d", suffix, get_irn_node_nr(true_block));
425                         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* true case */");
426                         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
427
428                         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "B BLOCK_%d", get_irn_node_nr(false_block));
429                         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* false case */");
430                         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
431                 }
432         }
433 }
434
435 static void emit_arm_CopyB(ir_node *irn, void *env) {
436         arm_emit_env_t *emit_env = env;
437         FILE *out = emit_env->out;
438         char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
439         unsigned int size = get_tarval_long(get_arm_value(irn));
440         const lc_arg_env_t *arg_env = arm_get_arg_env();
441
442         lc_esnprintf(arg_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* MemCopy (%2S)->(%1S) [%d bytes], Use %3S, %4S, %5S and %%r12 */", irn, irn, size, irn, irn, irn);
443
444         assert ( size > 0 && "CopyB needs size > 0" );
445         if (size & 3)
446                 size += 4;
447         size >>= 2;
448         switch(size & 3) {
449         case 0:
450                 break;
451         case 1:
452                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDR %%r12, [%2S, #0]!", irn);
453                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
454                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STR  %%r12, [%1S, #0]!", irn);
455                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
456                 break;
457         case 2:
458                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDMIA %2S!, {%%r12, %3S}", irn, irn);
459                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
460                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STMIA %1S!, {%%r12, %3S}", irn, irn);
461                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
462                 break;
463         case 3:
464                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDMIA %2S!, {%%r12, %3S, %4S}", irn, irn, irn);
465                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
466                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STMIA %1S!, {%%r12, %3S, %4S}", irn, irn, irn);
467                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
468                 break;
469         }
470         size >>= 2;
471         while (size) {
472                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "LDMIA %2S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn);
473                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
474                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "STMIA %1S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn);
475                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
476                 --size;
477         }
478 }
479
480 static void emit_arm_SwitchJmp(ir_node *irn, void *env) {
481         char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
482         const ir_edge_t    *edge;
483         ir_node            *proj;
484         arm_emit_env_t *emit_env = env;
485         FILE *out = emit_env->out;
486         int i;
487         ir_node **projs;
488         int n_projs;
489         int block_nr;
490         int default_block_num;
491
492         block_nr = get_irn_node_nr(irn);
493         n_projs = get_arm_n_projs(irn);
494
495         projs = xcalloc(n_projs , sizeof(ir_node*));
496
497         foreach_out_edge(irn, edge) {
498                 proj = get_edge_src_irn(edge);
499                 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
500
501                 if (get_Proj_proj(proj) == get_arm_default_proj_num(irn))
502                         default_block_num = get_irn_node_nr(get_irn_link(proj));
503
504                 projs[get_Proj_proj(proj)] = proj;
505         }
506
507         // CMP %1S, n_projs - 1
508         // BHI default
509
510
511
512         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "CMP %1S, #%u", irn, n_projs - 1);
513         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
514         lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
515
516         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "BHI BLOCK_%d", default_block_num);
517         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
518         lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
519
520
521         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "LDR %%r12, TABLE_%d_START", block_nr);
522         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
523         lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
524
525         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ADD %%r12, %%r12, %1S, LSL #2", irn);
526         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
527         lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
528
529         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "LDR %%r15, [%%r12, #0]");
530         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
531         lc_efprintf(arm_get_arg_env(), out, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
532
533         // LDR %r12, .TABLE_X_START
534         // ADD %r12, %r12, [%1S, LSL #2]
535         // LDR %r15, %r12
536
537         fprintf(out, "TABLE_%d_START:\n\t.word\tTABLE_%d\n", block_nr, block_nr);
538         fprintf(out, "\t.align 2\n");
539         fprintf(out, "TABLE_%d:\n", block_nr);
540
541
542         for ( i=0; i<n_projs; i++) {
543                 ir_node *block;
544                 proj = projs[i];
545                 if ( proj ) {
546                         block = get_irn_link(proj);
547                 } else {
548                         block = get_irn_link(projs[get_arm_default_proj_num(irn)]);
549                 }
550                 fprintf(out, "\t.word\tBLOCK_%ld\n",get_irn_node_nr(block));
551         }
552         fprintf(out, "\t.align 2\n");
553
554         xfree(projs);
555 }
556
557 /************************************************************************/
558 /* emit_be                                                              */
559 /************************************************************************/
560
561 static void emit_be_Call(ir_node *irn, void *env) {
562         arm_emit_env_t *emit_env = env;
563         FILE *out = emit_env->out;
564         entity *target_entity = be_Call_get_entity(irn);
565         const char *target_name = get_entity_name(target_entity);
566         fprintf(out, "\tBL %s\t\t\t\t/* Call */\n", target_name);
567 }
568
569 static void emit_be_IncSP(const ir_node *irn, arm_emit_env_t *emit_env) {
570         FILE *F = emit_env->out;
571         unsigned offs = be_get_IncSP_offset(irn);
572         if (offs) {
573                 char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
574                 lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ADD %1D, %1S, #%O", irn, irn, irn );
575                 lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* IncSP(%O) */", irn);
576                 lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
577         } else {
578                 char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
579                 lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "");
580                 lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* omitted IncSP(%O) */", irn);
581                 lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
582         }
583 }
584
585 // void emit_be_AddSP(const ir_node *irn, arm_emit_env_t *emit_env) {
586 //      FILE *F = emit_env->out;
587 //      char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
588 //      lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ADD %1D, %1S, %2S", irn, irn, irn );
589 //      lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* AddSP(%2S) */", irn);
590 //      lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
591 // }
592
593 static void emit_be_Copy(const ir_node *irn, arm_emit_env_t *emit_env) {
594         FILE *F    = emit_env->out;
595         ir_mode *mode = get_irn_mode(irn);
596         assert( (mode != mode_E) && "IEEE Extended FP not supported");
597
598         if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) {
599                 char cmd_buf[256], cmnt_buf[256];
600                 lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "");
601                 lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* omitted Copy: %1S -> %1D */", irn, irn);
602                 lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
603                 return;
604         }
605
606         if (mode == mode_F) {
607                 char cmd_buf[256], cmnt_buf[256];
608                 lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "FCPYS %1D, %1S", irn, irn);
609                 lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Copy: %1S -> %1D */", irn, irn);
610                 lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
611         } else if (mode == mode_D) {
612                 char cmd_buf[256], cmnt_buf[256];
613                 lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "FCPYD %1D, %1S", irn, irn);
614                 lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Copy: %1S -> %1D */", irn, irn);
615                 lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
616         } else if (mode_is_numP(mode)) {
617                 char cmd_buf[256], cmnt_buf[256];
618                 lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "MOV %1D, %1S", irn, irn);
619                 lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Copy: %1S -> %1D */", irn, irn);
620                 lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
621         } else {
622                 assert(0 && "move not supported for this mode");
623         }
624 //      emit_arm_Copy(irn, emit_env);
625 }
626
627 static void emit_be_Spill(const ir_node *irn, arm_emit_env_t *emit_env) {
628         FILE *F = emit_env->out;
629         ir_mode *mode = get_irn_mode(irn);
630         assert( (mode != mode_E) && "IEEE Extended FP not supported");
631         if (mode_is_dataM(mode)) {
632                 char cmd_buf[256], cmnt_buf[256];
633                 lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "STR %2S, [%1S, #%O]", irn, irn, irn );
634                 lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Spill(%2S) -> (%1S) */", irn, irn);
635                 lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
636         } else {
637                 assert(0 && "spill not supported for this mode");
638         }
639 }
640
641 static void emit_be_Reload(const ir_node* irn, arm_emit_env_t *emit_env) {
642         FILE *F = emit_env->out;
643         ir_mode *mode = get_irn_mode(irn);
644         assert( (mode != mode_E) && "IEEE Extended FP not supported");
645         if (mode_is_dataM(mode)) {
646                 char cmd_buf[256], cmnt_buf[256];
647                 lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "LDR %1D, [%1S, #%O]", irn, irn, irn );
648                 lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* Reload(%1S) -> (%1D) */", irn, irn);
649                 lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
650         } else {
651                 assert(0 && "reload not supported for this mode");
652         }
653 }
654
655 static void emit_be_Perm(const ir_node* irn, arm_emit_env_t *emit_env) {
656         FILE *F = emit_env->out;
657         ir_mode *mode = get_irn_mode(irn);
658         assert( (mode != mode_E) && "IEEE Extended FP not supported");
659         lc_efprintf(arm_get_arg_env(), F, "\tEOR %1S, %1S, %2S\t\t\t/* begin Perm(%1S, %2S) */\n", irn, irn, irn, irn, irn);
660         lc_efprintf(arm_get_arg_env(), F, "\tEOR %2S, %1S, %2S\n", irn, irn, irn);
661         lc_efprintf(arm_get_arg_env(), F, "\tEOR %1S, %1S, %2S\t\t\t/* end Perm(%1S, %2S) */\n", irn, irn, irn, irn, irn);
662 }
663
664 static void emit_be_StackParam(const ir_node *irn, arm_emit_env_t *emit_env) {
665         FILE *F = emit_env->out;
666         ir_mode *mode = get_irn_mode(irn);
667         char cmd_buf[256], cmnt_buf[256];
668         assert( (mode != mode_E) && "IEEE Extended FP not supported");
669
670         lc_esnprintf(arm_get_arg_env(), cmd_buf, 256, "LDR %1D, [%1S, #%O]", irn, irn, irn );
671         lc_esnprintf(arm_get_arg_env(), cmnt_buf, 256, "/* StackParam: (%1S + %O) -> %1D */",irn , irn, irn, get_irn_n(irn, 0));
672         lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
673 }
674
675 /************************************************************************/
676 /* emit                                                                 */
677 /************************************************************************/
678
679 static void emit_Jmp(ir_node *irn, void *env) {
680         arm_emit_env_t *emit_env = env;
681         FILE *out = emit_env->out;
682         const ir_edge_t *edge = get_irn_out_edge_first(irn);
683         ir_node *target_block = get_edge_src_irn(edge);
684         fprintf(out, "\tB BLOCK_%ld\t\t\t/* unconditional Jump */\n", get_irn_node_nr(target_block));
685 }
686
687 static void emit_Proj(ir_node *irn, void *env) {
688
689 }
690
691
692
693 /***********************************************************************************
694  *                  _          __                                             _
695  *                 (_)        / _|                                           | |
696  *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
697  * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
698  * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
699  * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
700  *
701  ***********************************************************************************/
702
703 /**
704  * Enters the emitter functions for handled nodes into the generic
705  * pointer of an opcode.
706  */
707 static void arm_register_emitters(void) {
708
709 #define ARM_EMIT(a) op_arm_##a->ops.generic = (op_func)emit_arm_##a
710 #define EMIT(a)      op_##a->ops.generic = (op_func)emit_##a
711 #define BE_EMIT(a)   op_be_##a->ops.generic = (op_func)emit_be_##a
712
713         /* first clear the generic function pointer for all ops */
714         clear_irp_opcodes_generic_func();
715
716         /* register all emitter functions defined in spec */
717         arm_register_spec_emitters();
718
719         /* other emitter functions */
720         ARM_EMIT(CondJmp);
721 //      ARM_EMIT(SwitchJmp);
722         ARM_EMIT(CopyB);
723 //      ARM_EMIT(CopyB_i);
724 //      ARM_EMIT(Const);
725         ARM_EMIT(SymConst);
726         ARM_EMIT(SwitchJmp);
727
728         /* benode emitter */
729         BE_EMIT(Call);
730         BE_EMIT(IncSP);
731 //      BE_EMIT(AddSP);
732         BE_EMIT(Copy);
733         BE_EMIT(Spill);
734         BE_EMIT(Reload);
735         BE_EMIT(Perm);
736         BE_EMIT(StackParam);
737
738         /* firm emitter */
739         EMIT(Jmp);
740
741
742         /* noisy stuff */
743 #ifdef SILENCER
744         EMIT(Proj);
745 #endif
746
747 #undef ARM_EMIT
748 #undef BE_EMIT
749 #undef EMIT
750 }
751
752 /**
753  * Emits code for a node.
754  */
755 static void arm_emit_node(const ir_node *irn, void *env) {
756         arm_emit_env_t        *emit_env = env;
757         FILE              *F        = emit_env->out;
758         ir_op             *op       = get_irn_op(irn);
759         DEBUG_ONLY(firm_dbg_module_t *mod      = emit_env->mod;)
760
761         DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));
762
763         if (op->ops.generic) {
764                 void (*emit)(const ir_node *, void *) = (void (*)(const ir_node *, void *))op->ops.generic;
765                 (*emit)(irn, env);
766         }
767         else {
768                 ir_fprintf(F, "\t\t\t\t\t/* %+F */\n", irn);
769         }
770 }
771
772 /**
773  * Walks over the nodes in a block connected by scheduling edges
774  * and emits code for each node.
775  */
776 void arm_gen_block(ir_node *block, void *env) {
777         ir_node *irn;
778
779         if (! is_Block(block))
780                 return;
781
782         fprintf(((arm_emit_env_t *)env)->out, "BLOCK_%ld:\n", get_irn_node_nr(block));
783         sched_foreach(block, irn) {
784                 arm_emit_node(irn, env);
785         }
786 }
787
788
789 /**
790  * Emits code for function start.
791  */
792 void arm_emit_start(FILE *F, ir_graph *irg) {
793         const char *irg_name = get_entity_name(get_irg_entity(irg));
794         fprintf(F, "\t.text\n");
795         fprintf(F, "\t.align  2\n");
796         fprintf(F, "\t.global %s\n", irg_name);
797         fprintf(F, "%s:\n", irg_name);
798 }
799
800 /**
801  * Emits code for function end
802  */
803 void arm_emit_end(FILE *F, ir_graph *irg) {
804 }
805
806 /**
807  * Sets labels for control flow nodes (jump target)
808  * TODO: Jump optimization
809  */
810 void arm_gen_labels(ir_node *block, void *env) {
811         ir_node *pred;
812         int n = get_Block_n_cfgpreds(block);
813
814         for (n--; n >= 0; n--) {
815                 pred = get_Block_cfgpred(block, n);
816                 set_irn_link(pred, block);
817         }
818 }
819
820
821 /**
822  * Main driver
823  */
824 void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg) {
825         arm_emit_env_t emit_env;
826
827         emit_env.out      = F;
828         emit_env.arch_env = cg->arch_env;
829         emit_env.cg       = cg;
830         FIRM_DBG_REGISTER(emit_env.mod, "firm.be.arm.emit");
831
832         /* set the global arch_env (needed by print hooks) */
833         arch_env = cg->arch_env;
834
835         arm_register_emitters();
836
837         arm_emit_start(F, irg);
838         irg_block_walk_graph(irg, arm_gen_labels, NULL, &emit_env);
839         irg_walk_blkwise_graph(irg, NULL, arm_gen_block, &emit_env);
840         arm_emit_end(F, irg);
841 }