232e70a9cf1dc98b693934e4f416c384112d9f2a
[libfirm] / ir / be / amd64 / amd64_emitter.c
1 /*
2  * Copyright (C) 1995-2011 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief   emit assembler for a backend graph
23  */
24 #include "config.h"
25
26 #include <limits.h>
27
28 #include "be_t.h"
29 #include "error.h"
30 #include "xmalloc.h"
31 #include "tv.h"
32 #include "iredges.h"
33 #include "debug.h"
34 #include "irgwalk.h"
35 #include "irprintf.h"
36 #include "irop_t.h"
37 #include "irargs_t.h"
38 #include "irprog.h"
39
40 #include "besched.h"
41 #include "begnuas.h"
42 #include "beblocksched.h"
43
44 #include "amd64_emitter.h"
45 #include "gen_amd64_emitter.h"
46 #include "gen_amd64_regalloc_if.h"
47 #include "amd64_nodes_attr.h"
48 #include "amd64_new_nodes.h"
49
50 #include "benode.h"
51
52 /*************************************************************
53  *             _       _    __   _          _
54  *            (_)     | |  / _| | |        | |
55  *  _ __  _ __ _ _ __ | |_| |_  | |__   ___| |_ __   ___ _ __
56  * | '_ \| '__| | '_ \| __|  _| | '_ \ / _ \ | '_ \ / _ \ '__|
57  * | |_) | |  | | | | | |_| |   | | | |  __/ | |_) |  __/ |
58  * | .__/|_|  |_|_| |_|\__|_|   |_| |_|\___|_| .__/ \___|_|
59  * | |                                       | |
60  * |_|                                       |_|
61  *************************************************************/
62
63 /**
64  * Returns the target block for a control flow node.
65  */
66 static ir_node *get_cfop_target_block(const ir_node *irn)
67 {
68         return (ir_node*)get_irn_link(irn);
69 }
70
71 void amd64_emitf(ir_node const *const node, char const *fmt, ...)
72 {
73         va_list ap;
74         va_start(ap, fmt);
75
76         be_emit_char('\t');
77         for (;;) {
78                 char const *start = fmt;
79
80                 while (*fmt != '%' && *fmt != '\n' && *fmt != '\0')
81                         ++fmt;
82                 if (fmt != start) {
83                         be_emit_string_len(start, fmt - start);
84                 }
85
86                 if (*fmt == '\n') {
87                         be_emit_char('\n');
88                         be_emit_write_line();
89                         be_emit_char('\t');
90                         ++fmt;
91                         continue;
92                 }
93
94                 if (*fmt == '\0')
95                         break;
96
97                 ++fmt;
98
99                 switch (*fmt++) {
100                         arch_register_t const *reg;
101
102                         case '%':
103                                 be_emit_char('%');
104                                 break;
105
106                         case 'C': {
107                                 amd64_attr_t const *const attr = get_amd64_attr_const(node);
108                                 be_emit_irprintf("$0x%X", attr->ext.imm_value);
109                                 break;
110                         }
111
112                         case 'D':
113                                 if (*fmt < '0' || '9' <= *fmt)
114                                         goto unknown;
115                                 reg = arch_get_irn_register_out(node, *fmt++ - '0');
116                                 goto emit_R;
117
118                         case 'E': {
119                                 ir_entity const *const ent = va_arg(ap, ir_entity const*);
120                                 be_gas_emit_entity(ent);
121                                 break;
122                         }
123
124                         case 'L': {
125                                 ir_node *const block = get_cfop_target_block(node);
126                                 be_gas_emit_block_name(block);
127                                 break;
128                         }
129
130                         case 'O': {
131                                 amd64_SymConst_attr_t const *const attr = get_amd64_SymConst_attr_const(node);
132                                 if (attr->fp_offset)
133                                         be_emit_irprintf("%d", attr->fp_offset);
134                                 break;
135                         }
136
137                         case 'R':
138                                 reg = va_arg(ap, arch_register_t const*);
139 emit_R:
140                                 be_emit_char('%');
141                                 be_emit_string(reg->name);
142                                 break;
143
144                         case 'S': {
145                                 int pos;
146                                 if ('0' <= *fmt && *fmt <= '9') {
147                                         pos = *fmt++ - '0';
148                                 } else if (*fmt == '*') {
149                                         ++fmt;
150                                         pos = va_arg(ap, int);
151                                 } else {
152                                         goto unknown;
153                                 }
154                                 reg = arch_get_irn_register_in(node, pos);
155                                 goto emit_R;
156                         }
157
158                         case 'd': {
159                                 int const num = va_arg(ap, int);
160                                 be_emit_irprintf("%d", num);
161                                 break;
162                         }
163
164                         case 's': {
165                                 char const *const str = va_arg(ap, char const*);
166                                 be_emit_string(str);
167                                 break;
168                         }
169
170                         case 'u': {
171                                 unsigned const num = va_arg(ap, unsigned);
172                                 be_emit_irprintf("%u", num);
173                                 break;
174                         }
175
176                         default:
177 unknown:
178                                 panic("unknown format conversion");
179                 }
180         }
181
182         be_emit_finish_line_gas(node);
183         va_end(ap);
184 }
185
186 /***********************************************************************************
187  *                  _          __                                             _
188  *                 (_)        / _|                                           | |
189  *  _ __ ___   __ _ _ _ __   | |_ _ __ __ _ _ __ ___   _____      _____  _ __| | __
190  * | '_ ` _ \ / _` | | '_ \  |  _| '__/ _` | '_ ` _ \ / _ \ \ /\ / / _ \| '__| |/ /
191  * | | | | | | (_| | | | | | | | | | | (_| | | | | | |  __/\ V  V / (_) | |  |   <
192  * |_| |_| |_|\__,_|_|_| |_| |_| |_|  \__,_|_| |_| |_|\___| \_/\_/ \___/|_|  |_|\_\
193  *
194  ***********************************************************************************/
195
196 /**
197  * Emit a SymConst.
198  */
199 static void emit_amd64_SymConst(const ir_node *irn)
200 {
201         const amd64_SymConst_attr_t *attr = get_amd64_SymConst_attr_const(irn);
202 #if 0
203         sym_or_tv_t key, *entry;
204         unsigned label;
205
206         key.u.id     = get_entity_ld_ident(attr->entity);
207         key.is_ident = 1;
208         key.label    = 0;
209         entry = set_insert(sym_or_tv_t, sym_or_tv, &key, sizeof(key), hash_ptr(key.u.generic));
210         if (entry->label == 0) {
211                 /* allocate a label */
212                 entry->label = get_unique_label();
213         }
214         label = entry->label;
215 #endif
216
217         amd64_emitf(irn, "mov $%E, %D0", attr->entity);
218 }
219
220 /**
221  * Emit a Conv.
222  */
223 static void emit_amd64_Conv(const ir_node *irn)
224 {
225         amd64_emitf(irn, "mov %S0, %D0");
226 }
227
228
229 /**
230  * Returns the next block in a block schedule.
231  */
232 static ir_node *sched_next_block(const ir_node *block)
233 {
234     return (ir_node*)get_irn_link(block);
235 }
236
237 /**
238  * Emit a Jmp.
239  */
240 static void emit_amd64_Jmp(const ir_node *node)
241 {
242         ir_node *block, *next_block;
243
244         /* for now, the code works for scheduled and non-schedules blocks */
245         block = get_nodes_block(node);
246
247         /* we have a block schedule */
248         next_block = sched_next_block(block);
249         if (get_cfop_target_block(node) != next_block) {
250                 amd64_emitf(node, "jmp %L");
251         } else if (be_options.verbose_asm) {
252                 amd64_emitf(node, "/* fallthrough to %L */");
253         }
254 }
255
256 /**
257  * Emit a Compare with conditional branch.
258  */
259 static void emit_amd64_Jcc(const ir_node *irn)
260 {
261         const ir_node      *proj_true  = NULL;
262         const ir_node      *proj_false = NULL;
263         const ir_node      *block;
264         const ir_node      *next_block;
265         const char         *suffix;
266         const amd64_attr_t *attr      = get_amd64_attr_const(irn);
267         ir_relation         relation  = attr->ext.relation;
268         ir_node            *op1       = get_irn_n(irn, 0);
269         const amd64_attr_t *cmp_attr  = get_amd64_attr_const(op1);
270         bool                is_signed = !cmp_attr->data.cmp_unsigned;
271
272         assert(is_amd64_Cmp(op1));
273
274         foreach_out_edge(irn, edge) {
275                 ir_node *proj = get_edge_src_irn(edge);
276                 long nr = get_Proj_proj(proj);
277                 if (nr == pn_Cond_true) {
278                         proj_true = proj;
279                 } else {
280                         proj_false = proj;
281                 }
282         }
283
284         if (cmp_attr->data.ins_permuted) {
285                 relation = get_inversed_relation(relation);
286         }
287
288         /* for now, the code works for scheduled and non-schedules blocks */
289         block = get_nodes_block(irn);
290
291         /* we have a block schedule */
292         next_block = sched_next_block(block);
293
294         assert(relation != ir_relation_false);
295         assert(relation != ir_relation_true);
296
297         if (get_cfop_target_block(proj_true) == next_block) {
298                 /* exchange both proj's so the second one can be omitted */
299                 const ir_node *t = proj_true;
300
301                 proj_true  = proj_false;
302                 proj_false = t;
303                 relation   = get_negated_relation(relation);
304         }
305
306         switch (relation & ir_relation_less_equal_greater) {
307                 case ir_relation_equal:              suffix = "e"; break;
308                 case ir_relation_less:               suffix = is_signed ? "l"  : "b"; break;
309                 case ir_relation_less_equal:         suffix = is_signed ? "le" : "be"; break;
310                 case ir_relation_greater:            suffix = is_signed ? "g"  : "a"; break;
311                 case ir_relation_greater_equal:      suffix = is_signed ? "ge" : "ae"; break;
312                 case ir_relation_less_greater:       suffix = "ne"; break;
313                 case ir_relation_less_equal_greater: suffix = "mp"; break;
314                 default: panic("Cmp has unsupported pnc");
315         }
316
317         /* emit the true proj */
318         amd64_emitf(proj_true, "j%s %L", suffix);
319
320         if (get_cfop_target_block(proj_false) != next_block) {
321                 amd64_emitf(proj_false, "jmp %L");
322         } else if (be_options.verbose_asm) {
323                 amd64_emitf(proj_false, "/* fallthrough to %L */");
324         }
325 }
326
327 /**
328  * Emits code for a call.
329  */
330 static void emit_be_Call(const ir_node *node)
331 {
332         ir_entity *entity = be_Call_get_entity(node);
333
334         /* %eax/%rax is used in AMD64 to pass the number of vector parameters for
335          * variable argument counts */
336         if (get_method_variadicity (be_Call_get_type((ir_node *) node))) {
337                 /* But this still is a hack... */
338                 amd64_emitf(node, "xor %%rax, %%rax");
339         }
340
341         if (entity) {
342                 amd64_emitf(node, "call %E", entity);
343         } else {
344                 be_emit_pad_comment();
345                 be_emit_cstring("/* FIXME: call NULL entity?! */\n");
346         }
347 }
348
349 /**
350  * emit copy node
351  */
352 static void emit_be_Copy(const ir_node *irn)
353 {
354         ir_mode *mode = get_irn_mode(irn);
355
356         if (arch_get_irn_register_in(irn, 0) == arch_get_irn_register_out(irn, 0)) {
357                 /* omitted Copy */
358                 return;
359         }
360
361         if (mode_is_float(mode)) {
362                 panic("move not supported for FP");
363         } else if (mode_is_data(mode)) {
364                 amd64_emitf(irn, "mov %S0, %D0");
365         } else {
366                 panic("move not supported for this mode");
367         }
368 }
369
370 static void emit_be_Perm(const ir_node *node)
371 {
372         const arch_register_t *in0, *in1;
373
374         in0 = arch_get_irn_register(get_irn_n(node, 0));
375         in1 = arch_get_irn_register(get_irn_n(node, 1));
376
377         arch_register_class_t const* const cls0 = in0->reg_class;
378         assert(cls0 == in1->reg_class && "Register class mismatch at Perm");
379
380         amd64_emitf(node, "xchg %R, %R", in0, in1);
381
382         if (cls0 != &amd64_reg_classes[CLASS_amd64_gp]) {
383                 panic("unexpected register class in be_Perm (%+F)", node);
384         }
385 }
386
387 static void emit_amd64_FrameAddr(const ir_node *irn)
388 {
389         const amd64_SymConst_attr_t *attr =
390                 (const amd64_SymConst_attr_t*) get_amd64_attr_const(irn);
391
392         amd64_emitf(irn, "mov %S0, %D0");
393         amd64_emitf(irn, "add $%u, %D0", attr->fp_offset);
394 }
395
396 /**
397  * Emits code to increase stack pointer.
398  */
399 static void emit_be_IncSP(const ir_node *node)
400 {
401         int offs = be_get_IncSP_offset(node);
402
403         if (offs == 0)
404                 return;
405
406         if (offs > 0) {
407                 amd64_emitf(node, "sub, $%d, %D0", offs);
408         } else {
409                 amd64_emitf(node, "add, $%d, %D0", -offs);
410         }
411 }
412
413 /**
414  * Emits code for a return.
415  */
416 static void emit_be_Return(const ir_node *node)
417 {
418         be_emit_cstring("\tret");
419         be_emit_finish_line_gas(node);
420 }
421
422
423 static void emit_amd64_binop_op(const ir_node *irn, int second_op)
424 {
425         if (irn->op == op_amd64_Add) {
426                 amd64_emitf(irn, "add %S*, %D0", second_op);
427         } else if (irn->op == op_amd64_Sub) {
428                 amd64_emitf(irn, "neg %S*",      second_op);
429                 amd64_emitf(irn, "add %S*, %D0", second_op);
430                 amd64_emitf(irn, "neg %S*",      second_op);
431         }
432
433 }
434
435 /**
436  * Emits an arithmetic operation that handles arbitraty input registers.
437  */
438 static void emit_amd64_binop(const ir_node *irn)
439 {
440         const arch_register_t *reg_s1 = arch_get_irn_register_in(irn, 0);
441         const arch_register_t *reg_s2 = arch_get_irn_register_in(irn, 1);
442         const arch_register_t *reg_d1 = arch_get_irn_register_out(irn, 0);
443
444         int second_op = 0;
445
446         if (reg_d1 != reg_s1 && reg_d1 != reg_s2) {
447                 amd64_emitf(irn, "mov %R, %R", reg_s1, reg_d1);
448                 second_op = 1;
449         } else if (reg_d1 == reg_s2 && reg_d1 != reg_s1) {
450                 second_op = 0;
451         }
452
453         emit_amd64_binop_op(irn, second_op);
454 }
455
456 /**
457  * Enters the emitter functions for handled nodes into the generic
458  * pointer of an opcode.
459  */
460 static void amd64_register_emitters(void)
461 {
462         /* first clear the generic function pointer for all ops */
463         ir_clear_opcodes_generic_func();
464
465         /* register all emitter functions defined in spec */
466         amd64_register_spec_emitters();
467
468         be_set_emitter(op_amd64_Add,        emit_amd64_binop);
469         be_set_emitter(op_amd64_Conv,       emit_amd64_Conv);
470         be_set_emitter(op_amd64_FrameAddr,  emit_amd64_FrameAddr);
471         be_set_emitter(op_amd64_Jcc,        emit_amd64_Jcc);
472         be_set_emitter(op_amd64_Jmp,        emit_amd64_Jmp);
473         be_set_emitter(op_amd64_Sub,        emit_amd64_binop);
474         be_set_emitter(op_amd64_SymConst,   emit_amd64_SymConst);
475         be_set_emitter(op_be_Call,          emit_be_Call);
476         be_set_emitter(op_be_Copy,          emit_be_Copy);
477         be_set_emitter(op_be_IncSP,         emit_be_IncSP);
478         be_set_emitter(op_be_Perm,          emit_be_Perm);
479         be_set_emitter(op_be_Return,        emit_be_Return);
480
481         be_set_emitter(op_Phi,      be_emit_nothing);
482         be_set_emitter(op_be_Keep,  be_emit_nothing);
483         be_set_emitter(op_be_Start, be_emit_nothing);
484 }
485
486 /**
487  * Walks over the nodes in a block connected by scheduling edges
488  * and emits code for each node.
489  */
490 static void amd64_gen_block(ir_node *block, void *data)
491 {
492         (void) data;
493
494         if (! is_Block(block))
495                 return;
496
497         be_gas_begin_block(block, true);
498
499         sched_foreach(block, node) {
500                 be_emit_node(node);
501         }
502 }
503
504
505 /**
506  * Sets labels for control flow nodes (jump target)
507  * TODO: Jump optimization
508  */
509 static void amd64_gen_labels(ir_node *block, void *env)
510 {
511         ir_node *pred;
512         int n = get_Block_n_cfgpreds(block);
513         (void) env;
514
515         for (n--; n >= 0; n--) {
516                 pred = get_Block_cfgpred(block, n);
517                 set_irn_link(pred, block);
518         }
519 }
520
521 /**
522  * Main driver
523  */
524 void amd64_gen_routine(ir_graph *irg)
525 {
526         ir_entity *entity = get_irg_entity(irg);
527         ir_node  **blk_sched;
528         size_t i, n;
529
530         /* register all emitter functions */
531         amd64_register_emitters();
532
533         blk_sched = be_create_block_schedule(irg);
534
535         be_gas_emit_function_prolog(entity, 4, NULL);
536
537         irg_block_walk_graph(irg, amd64_gen_labels, NULL, NULL);
538
539         n = ARR_LEN(blk_sched);
540         for (i = 0; i < n; i++) {
541                 ir_node *block = blk_sched[i];
542                 ir_node *next  = (i + 1) < n ? blk_sched[i+1] : NULL;
543
544                 set_irn_link(block, next);
545         }
546
547         for (i = 0; i < n; ++i) {
548                 ir_node *block = blk_sched[i];
549
550                 amd64_gen_block(block, 0);
551         }
552
553         be_gas_emit_function_epilog(entity);
554 }