- Split bearch.h correctly into bearch.h and bearch_t.h
[libfirm] / ir / be / arm / arm_emitter.c
1 #define SILENCER
2 /* arm emitter */
3 /* $Id$ */
4
5 #ifdef HAVE_CONFIG_H
6 #include "config.h"
7 #endif
8
9 #include <limits.h>
10
11 #include "xmalloc.h"
12 #include "tv.h"
13 #include "iredges.h"
14 #include "debug.h"
15 #include "irgwalk.h"
16 #include "irprintf.h"
17 #include "irop_t.h"
18 #include "irprog_t.h"
19 #include "irargs_t.h"
20
21 #include "../besched.h"
22 #include "../beblocksched.h"
23 #include "../beirg_t.h"
24
25 #include "arm_emitter.h"
26 #include "gen_arm_emitter.h"
27 #include "arm_nodes_attr.h"
28 #include "arm_new_nodes.h"
29 #include "arm_map_regs.h"
30 #include "gen_arm_regalloc_if.h"
31
32 #include "../benode_t.h"
33
34 #define SNPRINTF_BUF_LEN 128
35
36 static const arch_env_t *arch_env = NULL;
37
38 /**
39  * Switch to a new section
40  */
41 void arm_switch_section(FILE *f, sections sec) {
42         static sections curr_sec = NO_SECTION;
43
44         if (curr_sec == sec)
45                 return;
46
47         curr_sec = sec;
48         switch (sec) {
49
50         case NO_SECTION:
51                 break;
52
53         case SECTION_TEXT:
54                 fprintf(f, "\t.text\n");
55                 break;
56
57         case SECTION_DATA:
58                 fprintf(f, "\t.data\n");
59                 break;
60
61         default:
62                 assert(0);
63         }
64 }
65
66 /*************************************************************
67  *             _       _    __   _          _
68  *            (_)     | |  / _| | |        | |
69  *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
70  * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
71  * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
72  * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
73  * | |                                       | |
74  * |_|                                       |_|
75  *************************************************************/
76
77 /**
78  * Returns non-zero if a mode has a Immediate attribute.
79  */
80 int is_immediate_node(ir_node *irn) {
81         arm_attr_t *attr = get_arm_attr(irn);
82         return ARM_GET_SHF_MOD(attr) == ARM_SHF_IMM;
83 }
84
85 /**
86  * Return a const or SymConst as string.
87  */
88 static const char *node_const_to_str(ir_node *n, char *buf, int buflen) {
89         if (is_immediate_node(n)) {
90                 snprintf(buf, buflen, "#0x%X", arm_decode_imm_w_shift(get_arm_value(n)));
91                 return buf;
92         }
93         else if (is_arm_SymConst(n))
94                 return get_arm_symconst_label(n);
95
96         assert( 0 && "das ist gar keine Konstante");
97         return NULL;
98 }
99
100 /**
101  * Returns node's offset as string.
102  */
103 static const char *node_offset_to_str(ir_node *n, char *buf, int buflen) {
104         int offset = 0;
105         ir_op *irn_op = get_irn_op(n);
106
107         if (irn_op == op_be_StackParam) {
108                 ir_entity *ent = be_get_frame_entity(n);
109                 offset = get_entity_offset(ent);
110         } else if (irn_op == op_be_Reload || irn_op == op_be_Spill) {
111                 ir_entity *ent = be_get_frame_entity(n);
112                 offset = get_entity_offset(ent);
113         } else if (irn_op == op_be_IncSP) {
114                 offset = - be_get_IncSP_offset(n);
115         } else {
116                 return "node_offset_to_str will fuer diesen Knotentyp noch implementiert werden";
117         }
118         snprintf(buf, buflen, "%d", offset);
119         return buf;
120 }
121
122 /* We always pass the ir_node which is a pointer. */
123 static int arm_get_arg_type(const lc_arg_occ_t *occ) {
124         return lc_arg_type_ptr;
125 }
126
127
128 /**
129  * Returns the register at in position pos.
130  */
131 static const arch_register_t *get_in_reg(const ir_node *irn, int pos) {
132         ir_node                *op;
133         const arch_register_t  *reg = NULL;
134
135         assert(get_irn_arity(irn) > pos && "Invalid IN position");
136
137         /* The out register of the operator at position pos is the
138            in register we need. */
139         op = get_irn_n(irn, pos);
140
141         reg = arch_get_irn_register(arch_env, op);
142
143         assert(reg && "no in register found");
144         return reg;
145 }
146
147 /**
148  * Returns the register at out position pos.
149  */
150 static const arch_register_t *get_out_reg(const ir_node *irn, int pos) {
151         ir_node                *proj;
152         const arch_register_t  *reg = NULL;
153
154         assert(get_irn_n_edges(irn) > pos && "Invalid OUT position");
155
156         /* 1st case: irn is not of mode_T, so it has only                 */
157         /*           one OUT register -> good                             */
158         /* 2nd case: irn is of mode_T -> collect all Projs and ask the    */
159         /*           Proj with the corresponding projnum for the register */
160
161         if (get_irn_mode(irn) != mode_T) {
162                 reg = arch_get_irn_register(arch_env, irn);
163         }
164         else if (is_arm_irn(irn)) {
165                 reg = get_arm_out_reg(irn, pos);
166         }
167         else {
168                 const ir_edge_t *edge;
169
170                 foreach_out_edge(irn, edge) {
171                         proj = get_edge_src_irn(edge);
172                         assert(is_Proj(proj) && "non-Proj from mode_T node");
173                         if (get_Proj_proj(proj) == pos) {
174                                 reg = arch_get_irn_register(arch_env, proj);
175                                 break;
176                         }
177                 }
178         }
179
180         assert(reg && "no out register found");
181         return reg;
182 }
183
184 /**
185  * Returns the number of the in register at position pos.
186  */
187 int get_arm_reg_nr(ir_node *irn, int pos, int in_out) {
188         const arch_register_t *reg;
189
190         if (in_out == 1) {
191                 reg = get_in_reg(irn, pos);
192         }
193         else {
194                 reg = get_out_reg(irn, pos);
195         }
196
197         return arch_register_get_index(reg);
198 }
199
200 /**
201  * Returns the name of the in register at position pos.
202  */
203 const char *get_arm_reg_name(ir_node *irn, int pos, int in_out) {
204         const arch_register_t *reg;
205
206         if (in_out == 1) {
207                 reg = get_in_reg(irn, pos);
208         }
209         else {
210                 reg = get_out_reg(irn, pos);
211         }
212
213         return arch_register_get_name(reg);
214 }
215
216 /**
217  * Get the register name for a node.
218  */
219 static int arm_get_reg_name(lc_appendable_t *app,
220     const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
221 {
222         const char *buf;
223         ir_node    *X  = arg->v_ptr;
224         int         nr = occ->width - 1;
225
226         if (!X)
227                 return lc_appendable_snadd(app, "(null)", 6);
228
229         if (occ->conversion == 'S') {
230                 buf = get_arm_reg_name(X, nr, 1);
231         }
232         else { /* 'D' */
233                 buf = get_arm_reg_name(X, nr, 0);
234         }
235
236         lc_appendable_chadd(app, '%');
237         return lc_appendable_snadd(app, buf, strlen(buf));
238 }
239
240 /**
241  * Returns the tarval or offset of an arm node as a string.
242  */
243 static int arm_const_to_str(lc_appendable_t *app,
244     const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
245 {
246         char buffer[SNPRINTF_BUF_LEN];
247         const char *buf;
248         ir_node    *X = arg->v_ptr;
249
250         if (!X)
251                 return lc_appendable_snadd(app, "(null)", 6);
252
253         if (occ->conversion == 'C') {
254                 buf = node_const_to_str(X, buffer, sizeof(buffer));
255         }
256         else { /* 'O' */
257                 buf = node_offset_to_str(X, buffer, sizeof(buffer));
258         }
259
260         return lc_appendable_snadd(app, buf, strlen(buf));
261 }
262
263 /**
264  * Returns the tarval or offset of an arm node as a string.
265  */
266 static int arm_shift_str(lc_appendable_t *app,
267     const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
268 {
269         char buffer[SNPRINTF_BUF_LEN];
270         ir_node            *irn = arg->v_ptr;
271         arm_shift_modifier mod;
272
273         if (!irn)
274                 return lc_appendable_snadd(app, "(null)", 6);
275
276         mod = get_arm_shift_modifier(irn);
277         if (ARM_HAS_SHIFT(mod)) {
278                 long v = get_tarval_long(get_arm_value(irn));
279
280                 snprintf(buffer, sizeof(buffer), ", %s #%ld", arm_shf_mod_name(mod), v);
281                 return lc_appendable_snadd(app, buffer, strlen(buffer));
282         }
283         return 0;
284 }
285
286 /**
287  * Determines the instruction suffix depending on the mode.
288  */
289 static int arm_get_mode_suffix(lc_appendable_t *app,
290     const lc_arg_occ_t *occ, const lc_arg_value_t *arg)
291 {
292         ir_node *irn = arg->v_ptr;
293         arm_attr_t *attr;
294         ir_mode *mode;
295         int bits;
296
297         if (! irn)
298                 return lc_appendable_snadd(app, "(null)", 6);
299
300         attr = get_arm_attr(irn);
301         mode = attr->op_mode ? attr->op_mode : get_irn_mode(irn);
302         bits = get_mode_size_bits(mode);
303
304         if (bits == 32)
305                 return lc_appendable_chadd(app, 's');
306         else if (bits == 64)
307                 return lc_appendable_chadd(app, 'd');
308         else
309                 return lc_appendable_chadd(app, 'e');
310 }
311
312 /**
313  * Return the arm printf arg environment.
314  * We use the firm environment with some additional handlers.
315  */
316 const lc_arg_env_t *arm_get_arg_env(void) {
317         static lc_arg_env_t *env = NULL;
318
319         static const lc_arg_handler_t arm_reg_handler   = { arm_get_arg_type, arm_get_reg_name };
320         static const lc_arg_handler_t arm_const_handler = { arm_get_arg_type, arm_const_to_str };
321         static const lc_arg_handler_t arm_mode_handler  = { arm_get_arg_type, arm_get_mode_suffix };
322         static const lc_arg_handler_t arm_shf_handler   = { arm_get_arg_type, arm_shift_str };
323
324         if (env == NULL) {
325                 /* extend the firm printer */
326                 env = firm_get_arg_env();
327                         //lc_arg_new_env();
328
329                 lc_arg_register(env, "arm:sreg", 'S', &arm_reg_handler);
330                 lc_arg_register(env, "arm:dreg", 'D', &arm_reg_handler);
331                 lc_arg_register(env, "arm:cnst", 'C', &arm_const_handler);
332                 lc_arg_register(env, "arm:offs", 'O', &arm_const_handler);
333                 lc_arg_register(env, "arm:mode", 'M', &arm_mode_handler);
334                 lc_arg_register(env, "arm:shf",  'X', &arm_shf_handler);
335         }
336
337         return env;
338 }
339
340 /**
341  * Formated print of commands and comments.
342  */
343 static void arm_fprintf_format(FILE *F, const char *cmd_buf, const char *cmnt_buf, const ir_node *irn) {
344         lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F (%G) */\n", cmd_buf, cmnt_buf, irn, irn);
345 }
346
347 /**
348  * Returns a unique label. This number will not be used a second time.
349  */
350 static unsigned get_unique_label(void) {
351         static unsigned id = 0;
352         return ++id;
353 }
354
355 /**
356  * Emit a SymConst
357  */
358 static void emit_arm_SymConst(ir_node *irn, void *env) {
359         arm_emit_env_t *emit_env = env;
360         FILE *F = emit_env->out;
361         SymConstEntry *entry = obstack_alloc(&emit_env->obst, sizeof(*entry));
362         const lc_arg_env_t *arg_env = arm_get_arg_env();
363         char cmd_buf[256];
364
365         entry->label      = get_unique_label();
366         entry->symconst   = irn;
367         entry->next       = emit_env->symbols;
368         emit_env->symbols = entry;
369
370         lc_esnprintf(arg_env, cmd_buf, 256, "ldr %1D, .L%u", irn, entry->label);
371         arm_fprintf_format(F, cmd_buf, "/* indirect SymConst */", irn);
372 }
373
374 /**
375  * Returns the next block in a block schedule.
376  */
377 static ir_node *sched_next_block(ir_node *block) {
378     return get_irn_link(block);
379 }
380
381 /**
382  * Emit a conditional jump.
383  */
384 static void emit_arm_CondJmp(ir_node *irn, void *env) {
385         arm_emit_env_t *emit_env = env;
386         FILE *out = emit_env->out;
387         const ir_edge_t *edge;
388         ir_node *true_block = NULL;
389         ir_node *false_block = NULL;
390         ir_node *op1 = get_irn_n(irn, 0);
391         ir_mode *opmode = get_irn_mode(op1);
392         char *suffix;
393         int proj_num = get_arm_proj_num(irn);
394         char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
395
396
397         foreach_out_edge(irn, edge) {
398                 ir_node *proj = get_edge_src_irn(edge);
399                 long nr = get_Proj_proj(proj);
400                 ir_node *block = get_irn_link(proj);
401                 if ( nr == pn_Cond_true) {
402                         true_block = block;
403                 } else if (nr == pn_Cond_false) {
404                         false_block = block;
405                 } else {
406                         assert(0 && "tertium non datur! (CondJmp)");
407                 }
408         }
409
410         if (proj_num == pn_Cmp_False) {
411                 /* always false: should not happen */
412                 fprintf(out, "\tb BLOCK_%ld\t\t\t/* false case */\n", get_irn_node_nr(false_block));
413         } else if (proj_num == pn_Cmp_True) {
414                 /* always true: should not happen */
415                 fprintf(out, "\tb BLOCK_%ld\t\t\t/* true case */\n", get_irn_node_nr(true_block));
416         } else {
417                 ir_node *block = get_nodes_block(irn);
418
419                 if (mode_is_float(opmode)) {
420                         suffix = "ICHWILLIMPLEMENTIERTWERDEN";
421
422                         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "fcmp %1S, %2S", irn, irn);
423                         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Compare(%1S, %2S) -> FCPSR */", irn, irn );
424                         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
425
426                         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "fmstat", irn, irn);
427                         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* FCSPR -> CPSR */");
428                         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
429                 } else {
430                         if (true_block == sched_next_block(block)) {
431                                 /* negate it */
432                                 proj_num = get_negated_pnc(proj_num, opmode);
433                         }
434                         switch(proj_num) {
435                                 case pn_Cmp_Eq:  suffix = "eq"; break;
436                                 case pn_Cmp_Lt:  suffix = "lt"; break;
437                                 case pn_Cmp_Le:  suffix = "le"; break;
438                                 case pn_Cmp_Gt:  suffix = "gt"; break;
439                                 case pn_Cmp_Ge:  suffix = "ge"; break;
440                                 case pn_Cmp_Lg:  suffix = "ne"; break;
441                                 case pn_Cmp_Leg: suffix = "al"; break;
442                         default: assert(0 && "komische Dinge geschehen"); suffix = "al";
443                         }
444
445                         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "cmp %1S, %2S", irn, irn);
446                         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* Compare(%1S, %2S) -> CPSR */", irn, irn );
447                         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
448                 }
449
450                 if (true_block == sched_next_block(block)) {
451                         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "b%s BLOCK_%d", suffix, get_irn_node_nr(true_block));
452                         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* false case */");
453                         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
454
455                         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrough BLOCK_%d */", get_irn_node_nr(false_block));
456                         arm_fprintf_format(out, "", cmnt_buf, irn);
457                 }
458                 else {
459                         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "b%s BLOCK_%d", suffix, get_irn_node_nr(true_block));
460                         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* true case */");
461                         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
462
463             if (false_block == sched_next_block(block)) {
464                 lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* fallthrough BLOCK_%d */", get_irn_node_nr(false_block));
465                 arm_fprintf_format(out, "", cmnt_buf, irn);
466             }
467             else {
468                             lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "b BLOCK_%d", get_irn_node_nr(false_block));
469                             lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* false case */");
470                             arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
471             }
472         }
473         }
474 }
475
476 static void emit_arm_CopyB(ir_node *irn, void *env) {
477         arm_emit_env_t *emit_env = env;
478         FILE *out = emit_env->out;
479         char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
480         unsigned int size = get_tarval_long(get_arm_value(irn));
481         const lc_arg_env_t *arg_env = arm_get_arg_env();
482
483         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);
484
485         assert ( size > 0 && "CopyB needs size > 0" );
486         if (size & 3)
487                 size += 4;
488         size >>= 2;
489         switch(size & 3) {
490         case 0:
491                 break;
492         case 1:
493                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ldr %%r12, [%2S, #0]!", irn);
494                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
495                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "str  %%r12, [%1S, #0]!", irn);
496                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
497                 break;
498         case 2:
499                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ldmia %2S!, {%%r12, %3S}", irn, irn);
500                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
501                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "stmia %1S!, {%%r12, %3S}", irn, irn);
502                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
503                 break;
504         case 3:
505                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ldmia %2S!, {%%r12, %3S, %4S}", irn, irn, irn);
506                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
507                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "stmia %1S!, {%%r12, %3S, %4S}", irn, irn, irn);
508                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
509                 break;
510         }
511         size >>= 2;
512         while (size) {
513                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "ldmia %2S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn);
514                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
515                 lc_esnprintf(arg_env, cmd_buf, SNPRINTF_BUF_LEN, "stmia %1S!, {%%r12, %3S, %4S, %5S}", irn, irn, irn, irn);
516                 arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
517                 --size;
518         }
519 }
520
521 static void emit_arm_SwitchJmp(ir_node *irn, void *env) {
522         char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
523         const ir_edge_t    *edge;
524         ir_node            *proj;
525         arm_emit_env_t *emit_env = env;
526         FILE *out = emit_env->out;
527         int i;
528         ir_node **projs;
529         int n_projs;
530         int block_nr;
531         int default_block_num = -1;
532
533         block_nr = get_irn_node_nr(irn);
534         n_projs = get_arm_n_projs(irn);
535
536         projs = xcalloc(n_projs , sizeof(ir_node*));
537
538         foreach_out_edge(irn, edge) {
539                 proj = get_edge_src_irn(edge);
540                 assert(is_Proj(proj) && "Only proj allowed at SwitchJmp");
541
542                 if (get_Proj_proj(proj) == get_arm_default_proj_num(irn))
543                         default_block_num = get_irn_node_nr(get_irn_link(proj));
544
545                 projs[get_Proj_proj(proj)] = proj;
546         }
547         assert(default_block_num >= 0);
548
549         // CMP %1S, n_projs - 1
550         // BHI default
551
552
553
554         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "cmp %1S, #%u", irn, n_projs - 1);
555         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
556         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
557
558         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "bhi BLOCK_%d", default_block_num);
559         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
560         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
561
562
563         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ldr %%r12, TABLE_%d_START", block_nr);
564         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
565         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
566
567         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "add %%r12, %%r12, %1S, LSL #2", irn);
568         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
569         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
570
571         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ldr %%r15, [%%r12, #0]");
572         lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "", irn);
573         arm_fprintf_format(out, cmd_buf, cmnt_buf, irn);
574
575         // LDR %r12, .TABLE_X_START
576         // ADD %r12, %r12, [%1S, LSL #2]
577         // LDR %r15, %r12
578
579         fprintf(out, "TABLE_%d_START:\n\t.word\tTABLE_%d\n", block_nr, block_nr);
580         fprintf(out, "\t.align 2\n");
581         fprintf(out, "TABLE_%d:\n", block_nr);
582
583
584         for ( i=0; i<n_projs; i++) {
585                 ir_node *block;
586                 proj = projs[i];
587                 if ( proj ) {
588                         block = get_irn_link(proj);
589                 } else {
590                         block = get_irn_link(projs[get_arm_default_proj_num(irn)]);
591                 }
592                 fprintf(out, "\t.word\tBLOCK_%ld\n",get_irn_node_nr(block));
593         }
594         fprintf(out, "\t.align 2\n");
595
596         xfree(projs);
597 }
598
599 /************************************************************************/
600 /* emit_be                                                              */
601 /************************************************************************/
602
603 static void emit_be_Call(ir_node *irn, void *env) {
604         arm_emit_env_t *emit_env = env;
605         FILE *F = emit_env->out;
606         ir_entity *ent = be_Call_get_entity(irn);
607     char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
608
609     if (ent)
610             lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "bl %s", get_entity_ld_name(ent));
611     else
612         lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "%1D", get_irn_n(irn, be_pos_Call_ptr));
613     lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* %+F (be_Call) */", irn);
614     arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
615 }
616
617 /** Emit an IncSP node */
618 static void emit_be_IncSP(const ir_node *irn, arm_emit_env_t *emit_env) {
619         FILE *F = emit_env->out;
620         int offs = be_get_IncSP_offset(irn);
621
622         if (offs != 0) {
623                 char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
624                 lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "add %1D, %1S, #%O", irn, irn, irn );
625                 lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* IncSP(%O) */", irn);
626                 arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
627         } else {
628                 char cmnt_buf[SNPRINTF_BUF_LEN];
629                 lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* omitted IncSP(%O) */", irn);
630                 arm_fprintf_format(F, "", cmnt_buf, irn);
631         }
632 }
633
634 // void emit_be_AddSP(const ir_node *irn, arm_emit_env_t *emit_env) {
635 //      FILE *F = emit_env->out;
636 //      char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
637 //      lc_esnprintf(arm_get_arg_env(), cmd_buf, SNPRINTF_BUF_LEN, "ADD %1D, %1S, %2S", irn, irn, irn );
638 //      lc_esnprintf(arm_get_arg_env(), cmnt_buf, SNPRINTF_BUF_LEN, "/* AddSP(%2S) */", irn);
639 //      lc_efprintf(arm_get_arg_env(), F, "\t%-35s %-60s /* %+F */\n", cmd_buf, cmnt_buf, irn);
640 // }
641
642 static void emit_be_Copy(const ir_node *irn, arm_emit_env_t *emit_env) {
643         FILE *F    = emit_env->out;
644         ir_mode *mode = get_irn_mode(irn);
645         const lc_arg_env_t *arm_env = arm_get_arg_env();
646         char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
647
648         if (get_in_reg(irn, 0) == get_out_reg(irn, 0)) {
649                 lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* omitted Copy: %1S -> %1D */", irn, irn);
650                 lc_efprintf(arm_env, F, "\t%-35s %-60s /* %+F */\n", "", cmnt_buf, irn);
651                 return;
652         }
653
654         if (mode_is_float(mode)) {
655                 if (USE_FPA(emit_env->cg->isa)) {
656                         lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "mvf%M %1D, %1S", irn, irn, irn);
657                         lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Copy: %1S -> %1D */", irn, irn);
658                         arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
659                 }
660                 else {
661                         assert(0 && "move not supported for this mode");
662                 }
663         } else if (mode_is_numP(mode)) {
664                 lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "mov %1D, %1S", irn, irn);
665                 lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Copy: %1S -> %1D */", irn, irn);
666                 arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
667         } else {
668                 assert(0 && "move not supported for this mode");
669         }
670 //      emit_arm_Copy(irn, emit_env);
671 }
672
673 /**
674  * Emit code for a Spill.
675  */
676 static void emit_be_Spill(const ir_node *irn, arm_emit_env_t *emit_env) {
677         FILE *F = emit_env->out;
678         ir_mode *mode = get_irn_mode(irn);
679         const lc_arg_env_t *arm_env = arm_get_arg_env();
680         char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
681
682         if (mode_is_float(mode)) {
683                 if (USE_FPA(emit_env->cg->isa)) {
684                         lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "stf %2S, [%1S, #%O]", irn, irn, irn );
685                         lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Spill(%2S) -> (%1S) */", irn, irn);
686                         arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
687                 }
688                 else {
689                         assert(0 && "move not supported for this mode");
690                 }
691         } else if (mode_is_dataM(mode)) {
692                 lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "str %2S, [%1S, #%O]", irn, irn, irn );
693                 lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Spill(%2S) -> (%1S) */", irn, irn);
694                 arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
695         } else {
696                 assert(0 && "spill not supported for this mode");
697         }
698 }
699
700 /**
701  * Emit code for a Reload.
702  */
703 static void emit_be_Reload(const ir_node* irn, arm_emit_env_t *emit_env) {
704         FILE *F = emit_env->out;
705         ir_mode *mode = get_irn_mode(irn);
706         const lc_arg_env_t *arm_env = arm_get_arg_env();
707         char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
708
709         if (mode_is_float(mode)) {
710                 if (USE_FPA(emit_env->cg->isa)) {
711                         lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "ldf %1D, [%1S, #%O]", irn, irn, irn );
712                         lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Reload(%1S) -> (%1D) */", irn, irn);
713                         arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
714                 }
715                 else {
716                         assert(0 && "move not supported for this mode");
717                 }
718         } else if (mode_is_dataM(mode)) {
719                 lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "ldr %1D, [%1S, #%O]", irn, irn, irn );
720                 lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* Reload(%1S) -> (%1D) */", irn, irn);
721                 arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
722         } else {
723                 assert(0 && "reload not supported for this mode");
724         }
725 }
726
727 static void emit_be_Perm(const ir_node* irn, arm_emit_env_t *emit_env) {
728         FILE *F = emit_env->out;
729         const lc_arg_env_t *arm_env = arm_get_arg_env();
730         char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
731
732         lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "eor %1S, %1S, %2S", irn, irn, irn);
733         lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* begin Perm(%1S, %2S) */", irn, irn);
734         arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
735
736         lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "eor %2S, %1S, %2S", irn, irn, irn);
737         lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, " ");
738         arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
739
740         lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "eor %1S, %1S, %2S", irn, irn, irn);
741         lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* end Perm(%1S, %2S) */", irn, irn);
742         arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
743 }
744
745 static void emit_be_StackParam(const ir_node *irn, arm_emit_env_t *emit_env) {
746         FILE *F = emit_env->out;
747         ir_mode *mode = get_irn_mode(irn);
748         const lc_arg_env_t *arm_env = arm_get_arg_env();
749         char cmd_buf[SNPRINTF_BUF_LEN], cmnt_buf[SNPRINTF_BUF_LEN];
750
751         if (mode_is_float(mode)) {
752                 if (USE_FPA(emit_env->cg->isa)) {
753                         lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "ldf %1D, [%1S, #%O]", irn, irn, irn );
754                         lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* StackParam: (%1S + %O) -> %1D */",irn , irn, irn, get_irn_n(irn, 0));
755                         arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
756                 }
757                 else {
758                         assert(0 && "move not supported for this mode");
759                 }
760         } else {
761                 lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "ldr %1D, [%1S, #%O]", irn, irn, irn );
762                 lc_esnprintf(arm_env, cmnt_buf, SNPRINTF_BUF_LEN, "/* StackParam: (%1S + %O) -> %1D */",irn , irn, irn, get_irn_n(irn, 0));
763                 arm_fprintf_format(F, cmd_buf, cmnt_buf, irn);
764         }
765 }
766
767 /************************************************************************/
768 /* emit                                                                 */
769 /************************************************************************/
770
771 static void emit_Jmp(ir_node *irn, void *env) {
772         char cmd_buf[SNPRINTF_BUF_LEN];
773         arm_emit_env_t *emit_env = env;
774         FILE *F = emit_env->out;
775         const ir_edge_t *edge = get_irn_out_edge_first(irn);
776         const lc_arg_env_t *arm_env = arm_get_arg_env();
777         ir_node *target_block = get_edge_src_irn(edge);
778
779         lc_esnprintf(arm_env, cmd_buf, SNPRINTF_BUF_LEN, "b BLOCK_%d", get_irn_node_nr(target_block));
780         arm_fprintf_format(F, cmd_buf, "/* unconditional Jump */", irn);
781 }
782
783 static void emit_arm_fpaDbl2GP(const ir_node *n, arm_emit_env_t *env) {
784   FILE *F = env->out;
785   char cmd_buf[256];
786   const lc_arg_env_t *arg_env = arm_get_arg_env();
787
788   lc_esnprintf(arg_env, cmd_buf, 256, "stfd %1S, [sp, #-8]! ", n);
789   arm_fprintf_format(F, cmd_buf, "/* Push fp to stack */", n);
790
791   lc_esnprintf(arg_env, cmd_buf, 256, "ldmfd sp!, {%2D, %1D} ", n, n);
792   arm_fprintf_format(F, cmd_buf, "/* Pop destination */", n);
793 }
794
795 static void emit_silence(ir_node *irn, void *env) {
796
797 }
798
799
800 /***********************************************************************************
801  *                  _          __                                             _
802  *                 (_)        / _|                                           | |
803  *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
804  * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
805  * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
806  * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
807  *
808  ***********************************************************************************/
809
810 /**
811  * Enters the emitter functions for handled nodes into the generic
812  * pointer of an opcode.
813  */
814 static void arm_register_emitters(void) {
815
816 #define ARM_EMIT(a)  op_arm_##a->ops.generic = (op_func)emit_arm_##a
817 #define EMIT(a)      op_##a->ops.generic = (op_func)emit_##a
818 #define BE_EMIT(a)   op_be_##a->ops.generic = (op_func)emit_be_##a
819 #define SILENCE(a)   op_##a->ops.generic = (op_func)emit_silence
820
821         /* first clear the generic function pointer for all ops */
822         clear_irp_opcodes_generic_func();
823
824         /* register all emitter functions defined in spec */
825         arm_register_spec_emitters();
826
827         /* other emitter functions */
828         ARM_EMIT(CondJmp);
829         ARM_EMIT(CopyB);
830 //      ARM_EMIT(CopyB_i);
831 //      ARM_EMIT(Const);
832         ARM_EMIT(SymConst);
833         ARM_EMIT(SwitchJmp);
834         ARM_EMIT(fpaDbl2GP);
835
836         /* benode emitter */
837         BE_EMIT(Call);
838         BE_EMIT(IncSP);
839 //      BE_EMIT(AddSP);
840         BE_EMIT(Copy);
841         BE_EMIT(Spill);
842         BE_EMIT(Reload);
843         BE_EMIT(Perm);
844         BE_EMIT(StackParam);
845
846         /* firm emitter */
847         EMIT(Jmp);
848
849         /* noisy stuff */
850 #ifdef SILENCER
851         SILENCE(Proj);
852         SILENCE(Phi);
853         SILENCE(be_Keep);
854         SILENCE(be_CopyKeep);
855 #endif
856
857 #undef ARM_EMIT
858 #undef BE_EMIT
859 #undef EMIT
860 #undef SILENCE
861 }
862
863 typedef void (node_emitter)(const ir_node *, void *);
864
865 /**
866  * Emits code for a node.
867  */
868 static void arm_emit_node(const ir_node *irn, void *env) {
869         arm_emit_env_t *emit_env = env;
870         FILE           *F        = emit_env->out;
871         ir_op          *op       = get_irn_op(irn);
872         DEBUG_ONLY(firm_dbg_module_t *mod = emit_env->mod;)
873
874         DBG((mod, LEVEL_1, "emitting code for %+F\n", irn));
875
876         if (op->ops.generic) {
877                 node_emitter *emit = (node_emitter *)op->ops.generic;
878                 emit(irn, env);
879         }
880         else {
881                 ir_fprintf(F, "\t%-35s /* %+F %G */\n", "", irn, irn);
882         }
883 }
884
885 /**
886  * Walks over the nodes in a block connected by scheduling edges
887  * and emits code for each node.
888  */
889 void arm_gen_block(ir_node *block, void *env) {
890         ir_node *irn;
891
892         fprintf(((arm_emit_env_t *)env)->out, "BLOCK_%ld:\n", get_irn_node_nr(block));
893         sched_foreach(block, irn) {
894                 arm_emit_node(irn, env);
895         }
896 }
897
898
899 /**
900  * Emits code for function start.
901  */
902 void arm_emit_start(FILE *F, ir_graph *irg) {
903         ir_entity *ent = get_irg_entity(irg);
904         const char *irg_name = get_entity_ld_name(ent);
905         arm_switch_section(F, SECTION_TEXT);
906         fprintf(F, "\t.align  2\n");
907
908         if (get_entity_visibility(ent) == visibility_external_visible)
909                 fprintf(F, "\t.global %s\n", irg_name);
910         fprintf(F, "%s:\n", irg_name);
911 }
912
913 /**
914  * Emits code for function end
915  */
916 void arm_emit_end(FILE *F, ir_graph *irg) {
917         fprintf(F, "\t.ident \"firmcc\"\n");
918 }
919
920 /**
921  * Sets labels for control flow nodes (jump target)
922  * TODO: Jump optimization
923  */
924 void arm_gen_labels(ir_node *block, void *env) {
925         ir_node *pred;
926         int n = get_Block_n_cfgpreds(block);
927
928         for (n--; n >= 0; n--) {
929                 pred = get_Block_cfgpred(block, n);
930                 set_irn_link(pred, block);
931         }
932 }
933
934
935 /**
936  * Main driver. Emits the code for one routine.
937  */
938 void arm_gen_routine(FILE *F, ir_graph *irg, const arm_code_gen_t *cg) {
939         SymConstEntry *entry;
940         arm_emit_env_t emit_env;
941     ir_node **blk_sched;
942     int i, n;
943
944         emit_env.out      = F;
945         emit_env.arch_env = cg->arch_env;
946         emit_env.cg       = cg;
947         emit_env.symbols  = NULL;
948         obstack_init(&emit_env.obst);
949         FIRM_DBG_REGISTER(emit_env.mod, "firm.be.arm.emit");
950
951         /* set the global arch_env (needed by print hooks) */
952         arch_env = cg->arch_env;
953
954         arm_register_emitters();
955
956         /* create the block schedule. For now, we don't need it earlier. */
957         blk_sched = be_create_block_schedule(cg->irg, cg->birg->exec_freq);
958
959         arm_emit_start(F, irg);
960         irg_block_walk_graph(irg, arm_gen_labels, NULL, &emit_env);
961
962         n = ARR_LEN(blk_sched);
963         for (i = 0; i < n;) {
964                 ir_node *block, *next_bl;
965
966                 block   = blk_sched[i];
967                 ++i;
968                 next_bl = i < n ? blk_sched[i] : NULL;
969
970                 /* set here the link. the emitter expects to find the next block here */
971                 set_irn_link(block, next_bl);
972                 arm_gen_block(block, &emit_env);
973         }
974
975         /* emit SymConst values */
976         if (emit_env.symbols)
977                 fprintf(F, "\t.align 2\n");
978
979         for (entry = emit_env.symbols; entry; entry = entry->next) {
980                 fprintf(F, ".L%u:\n", entry->label);
981                 lc_efprintf(arm_get_arg_env(), F, "\t.word\t%C\n", entry->symconst);
982         }
983
984         obstack_free(&emit_env.obst, NULL);
985 }