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