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