no need for no_float_fold hack anymore
[libfirm] / ir / be / amd64 / amd64_transform.c
1 /*
2  * Copyright (C) 1995-2008 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   code selection (transform FIRM into amd64 FIRM)
23  * @version $Id: amd64_transform.c 26673 2009-10-01 16:43:13Z matze $
24  */
25 #include "config.h"
26
27 #include "irnode_t.h"
28 #include "irgraph_t.h"
29 #include "irmode_t.h"
30 #include "irgmod.h"
31 #include "iredges.h"
32 #include "ircons.h"
33 #include "iropt_t.h"
34 #include "error.h"
35 #include "debug.h"
36
37 #include "../benode.h"
38 #include "../betranshlp.h"
39 #include "../beutil.h"
40 #include "bearch_amd64_t.h"
41
42 #include "amd64_nodes_attr.h"
43 #include "amd64_transform.h"
44 #include "amd64_new_nodes.h"
45
46 #include "gen_amd64_regalloc_if.h"
47
48 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
49
50 /* Some support functions: */
51
52 static inline int mode_needs_gp_reg(ir_mode *mode)
53 {
54         return mode_is_int(mode) || mode_is_reference(mode);
55 }
56
57 /**
58  * Create a DAG constructing a given Const.
59  *
60  * @param irn  a Firm const
61  */
62 static ir_node *create_const_graph(ir_node *irn, ir_node *block)
63 {
64         tarval  *tv    = get_Const_tarval(irn);
65         ir_mode *mode  = get_tarval_mode(tv);
66         dbg_info *dbgi = get_irn_dbg_info(irn);
67         unsigned value;
68
69         if (mode_is_reference(mode)) {
70                 /* AMD64 is 64bit, so we can safely convert a reference tarval into Iu */
71                 assert(get_mode_size_bits(mode) == get_mode_size_bits(mode_Lu));
72                 tv = tarval_convert_to(tv, mode_Lu);
73         }
74
75         value = get_tarval_long(tv);
76         //d// printf ("TEST GENERATE %d\n", value);
77
78         return new_bd_amd64_Immediate(dbgi, block, value);
79 }
80
81 /* Op transformers: */
82
83 /**
84  * Transforms a Const node.
85  *
86  * @return The transformed AMD64 node.
87  */
88 static ir_node *gen_Const(ir_node *node) {
89         ir_node  *block = be_transform_node(get_nodes_block(node));
90         ir_mode  *mode  = get_irn_mode(node);
91         ir_node *res = create_const_graph(node, block);
92         (void) mode;
93
94         be_dep_on_frame(res);
95
96         return res;
97 }
98
99 /**
100  * Transforms a SymConst node.
101  *
102  * @return The transformed ARM node.
103  */
104 static ir_node *gen_SymConst(ir_node *node)
105 {
106         ir_node   *block  = be_transform_node(get_nodes_block(node));
107         ir_entity *entity = get_SymConst_entity(node);
108         dbg_info  *dbgi   = get_irn_dbg_info(node);
109         ir_node   *new_node;
110
111         new_node = new_bd_amd64_SymConst(dbgi, block, entity);
112         be_dep_on_frame(new_node);
113         return new_node;
114 }
115
116 /**
117  * Transforms an Add node.
118  *
119  * @return The transformed AMD64 node.
120  */
121 static ir_node *gen_Add(ir_node *node) {
122         ir_node  *block = be_transform_node(get_nodes_block(node));
123         /* ir_mode  *mode  = get_irn_mode(node); */
124         ir_node  *op1   = get_Add_left(node);
125         ir_node  *op2   = get_Add_right(node);
126         dbg_info *dbgi  = get_irn_dbg_info(node);
127         ir_node  *new_op1 = be_transform_node(op1);
128         ir_node  *new_op2 = be_transform_node(op2);
129
130         ir_node *res = new_bd_amd64_Add(dbgi, block, new_op1, new_op2);
131         be_dep_on_frame (res);
132         return res;
133 }
134
135 /**
136  * Transforms an Sub node.
137  *
138  * @return The transformed AMD64 node.
139  */
140 static ir_node *gen_Sub(ir_node *node) {
141         ir_node  *block = be_transform_node(get_nodes_block(node));
142         /* ir_mode  *mode  = get_irn_mode(node); */
143         ir_node  *op1   = get_Sub_left(node);
144         ir_node  *op2   = get_Sub_right(node);
145         dbg_info *dbgi  = get_irn_dbg_info(node);
146         ir_node  *new_op1 = be_transform_node(op1);
147         ir_node  *new_op2 = be_transform_node(op2);
148
149         ir_node *res = new_bd_amd64_Sub(dbgi, block, new_op1, new_op2);
150         be_dep_on_frame (res);
151         return res;
152 }
153
154 static ir_node *gen_Mul(ir_node *node) {
155         ir_node  *block = be_transform_node(get_nodes_block(node));
156         /* ir_mode  *mode  = get_irn_mode(node); */
157         ir_node  *op1   = get_Mul_left(node);
158         ir_node  *op2   = get_Mul_right(node);
159         dbg_info *dbgi  = get_irn_dbg_info(node);
160         ir_node  *new_op1 = be_transform_node(op1);
161         ir_node  *new_op2 = be_transform_node(op2);
162
163         ir_node *res = new_bd_amd64_Mul(dbgi, block, new_op1, new_op2);
164         be_dep_on_frame (res);
165         return res;
166 }
167
168 static ir_node *gen_Minus(ir_node *node)
169 {
170         ir_node  *block    = be_transform_node(get_nodes_block(node));
171         ir_node  *val      = be_transform_node(get_Minus_op(node));
172         dbg_info *dbgi     = get_irn_dbg_info(node);
173
174         return new_bd_amd64_Neg(dbgi, block, val);
175 }
176
177 static ir_node *gen_Jmp(ir_node *node)
178 {
179         ir_node  *block     = get_nodes_block(node);
180         ir_node  *new_block = be_transform_node(block);
181         dbg_info *dbgi      = get_irn_dbg_info(node);
182
183         return new_bd_amd64_Jmp(dbgi, new_block);
184 }
185
186 static ir_node *gen_be_Call(ir_node *node)
187 {
188         ir_node *res = be_duplicate_node(node);
189         arch_irn_add_flags(res, arch_irn_flags_modify_flags);
190
191         return res;
192 }
193
194 static ir_node *gen_Cmp(ir_node *node)
195 {
196         ir_node  *block    = be_transform_node(get_nodes_block(node));
197         ir_node  *op1      = get_Cmp_left(node);
198         ir_node  *op2      = get_Cmp_right(node);
199         ir_mode  *cmp_mode = get_irn_mode(op1);
200         dbg_info *dbgi     = get_irn_dbg_info(node);
201         ir_node  *new_op1;
202         ir_node  *new_op2;
203         bool      is_unsigned;
204
205         if (mode_is_float(cmp_mode)) {
206                 panic("Floating point not implemented yet (in gen_Cmp)!");
207         }
208
209         assert(get_irn_mode(op2) == cmp_mode);
210         is_unsigned = !mode_is_signed(cmp_mode);
211
212         new_op1 = be_transform_node(op1);
213 //      new_op1 = gen_extension(dbgi, block, new_op1, cmp_mode);
214         new_op2 = be_transform_node(op2);
215 //      new_op2 = gen_extension(dbgi, block, new_op2, cmp_mode);
216         return new_bd_amd64_Cmp(dbgi, block, new_op1, new_op2, false,
217                                 is_unsigned);
218 }
219
220 /**
221  * Transforms a Cond.
222  *
223  * @return the created ARM Cond node
224  */
225 static ir_node *gen_Cond(ir_node *node)
226 {
227         ir_node  *selector = get_Cond_selector(node);
228         ir_mode  *mode     = get_irn_mode(selector);
229         ir_node  *block;
230         ir_node  *flag_node;
231         dbg_info *dbgi;
232
233         if (mode != mode_b) {
234                 panic ("create_Switch not implemented yet!");
235                 // return gen_SwitchJmp(node);
236         }
237         assert(is_Proj(selector));
238
239         block     = be_transform_node(get_nodes_block(node));
240         dbgi      = get_irn_dbg_info(node);
241         flag_node = be_transform_node(get_Proj_pred(selector));
242
243         return new_bd_amd64_Jcc(dbgi, block, flag_node, get_Proj_proj(selector));
244 }
245
246 ///**
247 // * Create an And that will zero out upper bits.
248 // *
249 // * @param dbgi     debug info
250 // * @param block    the basic block
251 // * @param op       the original node
252 // * param src_bits  number of lower bits that will remain
253 // */
254 //static ir_node *gen_zero_extension(dbg_info *dbgi, ir_node *block, ir_node *op,
255 //                                   int src_bits)
256 //{
257 //      if (src_bits == 8) {
258 //              return new_bd_arm_And_imm(dbgi, block, op, 0xFF, 0);
259 //      } else if (src_bits == 16) {
260 //              ir_node *lshift = new_bd_arm_Mov_reg_shift_imm(dbgi, block, op, ARM_SHF_LSL_IMM, 16);
261 //              ir_node *rshift = new_bd_arm_Mov_reg_shift_imm(dbgi, block, lshift, ARM_SHF_LSR_IMM, 16);
262 //              return rshift;
263 //      } else {
264 //              panic("zero extension only supported for 8 and 16 bits");
265 //      }
266 //}
267 //
268 ///**
269 // * Generate code for a sign extension.
270 // */
271 //static ir_node *gen_sign_extension(dbg_info *dbgi, ir_node *block, ir_node *op,
272 //                                   int src_bits)
273 //{
274 //      int shift_width = 32 - src_bits;
275 //      ir_node *lshift_node = new_bd_arm_Mov_reg_shift_imm(dbgi, block, op, ARM_SHF_LSL_IMM, shift_width);
276 //      ir_node *rshift_node = new_bd_arm_Mov_reg_shift_imm(dbgi, block, lshift_node, ARM_SHF_ASR_IMM, shift_width);
277 //      return rshift_node;
278 //}
279 //
280 //static ir_node *gen_extension(dbg_info *dbgi, ir_node *block, ir_node *op,
281 //                              ir_mode *orig_mode)
282 //{
283 //      int bits = get_mode_size_bits(orig_mode);
284 //      if (bits == 32)
285 //              return op;
286 //
287 //      if (mode_is_signed(orig_mode)) {
288 //              return gen_sign_extension(dbgi, block, op, bits);
289 //      } else {
290 //              return gen_zero_extension(dbgi, block, op, bits);
291 //      }
292 //}
293 //
294 ///**
295 // * returns true if it is assured, that the upper bits of a node are "clean"
296 // * which means for a 16 or 8 bit value, that the upper bits in the register
297 // * are 0 for unsigned and a copy of the last significant bit for signed
298 // * numbers.
299 // */
300 //static bool upper_bits_clean(ir_node *transformed_node, ir_mode *mode)
301 //{
302 //      (void) transformed_node;
303 //      (void) mode;
304 //      /* TODO */
305 //      return false;
306 //}
307
308 /**
309  * Change some phi modes
310  */
311 static ir_node *gen_Phi(ir_node *node)
312 {
313         const arch_register_req_t *req;
314         ir_node  *block = be_transform_node(get_nodes_block(node));
315         ir_graph *irg   = current_ir_graph;
316         dbg_info *dbgi  = get_irn_dbg_info(node);
317         ir_mode  *mode  = get_irn_mode(node);
318         ir_node  *phi;
319
320         if (mode_needs_gp_reg(mode)) {
321                 /* all integer operations are on 64bit registers now */
322                 mode = mode_Lu;
323                 req  = amd64_reg_classes[CLASS_amd64_gp].class_req;
324         } else {
325                 req = arch_no_register_req;
326         }
327
328         /* phi nodes allow loops, so we use the old arguments for now
329          * and fix this later */
330         phi = new_ir_node(dbgi, irg, block, op_Phi, mode, get_irn_arity(node),
331                           get_irn_in(node) + 1);
332         copy_node_attr(irg, node, phi);
333         be_duplicate_deps(node, phi);
334
335         arch_set_out_register_req(phi, 0, req);
336
337         be_enqueue_preds(node);
338
339         return phi;
340 }
341
342
343
344 /**
345  * Transforms a Conv node.
346  *
347  * @return The created ia32 Conv node
348  */
349 static ir_node *gen_Conv(ir_node *node)
350 {
351         ir_node  *block    = be_transform_node(get_nodes_block(node));
352         ir_node  *op       = get_Conv_op(node);
353         ir_node  *new_op   = be_transform_node(op);
354         ir_mode  *src_mode = get_irn_mode(op);
355         ir_mode  *dst_mode = get_irn_mode(node);
356         dbg_info *dbgi     = get_irn_dbg_info(node);
357
358         if (src_mode == dst_mode)
359                 return new_op;
360
361         if (mode_is_float(src_mode) || mode_is_float(dst_mode)) {
362                 panic("float not supported yet");
363         } else { /* complete in gp registers */
364                 int src_bits = get_mode_size_bits(src_mode);
365                 int dst_bits = get_mode_size_bits(dst_mode);
366                 int min_bits;
367                 ir_mode *min_mode;
368
369                 if (src_bits == dst_bits) {
370                         /* kill unnecessary conv */
371                         return new_op;
372                 }
373
374                 if (src_bits < dst_bits) {
375                         min_bits = src_bits;
376                         min_mode = src_mode;
377                 } else {
378                         min_bits = dst_bits;
379                         min_mode = dst_mode;
380                 }
381
382
383                 return new_bd_amd64_Conv(dbgi, block, new_op, min_mode);
384
385                 //if (upper_bits_clean(new_op, min_mode)) {
386                 //      return new_op;
387                 //}
388
389                 //if (mode_is_signed(min_mode)) {
390                 //      return gen_sign_extension(dbg, block, new_op, min_bits);
391                 //} else {
392                 //      return gen_zero_extension(dbg, block, new_op, min_bits);
393                 //}
394         }
395 }
396
397 /**
398  * Transforms a Store.
399  *
400  * @return the created AMD64 Store node
401  */
402 static ir_node *gen_Store(ir_node *node)
403 {
404         ir_node  *block    = be_transform_node(get_nodes_block(node));
405         ir_node  *ptr      = get_Store_ptr(node);
406         ir_node  *new_ptr  = be_transform_node(ptr);
407         ir_node  *mem      = get_Store_mem(node);
408         ir_node  *new_mem  = be_transform_node(mem);
409         ir_node  *val      = get_Store_value(node);
410         ir_node  *new_val  = be_transform_node(val);
411         ir_mode  *mode     = get_irn_mode(val);
412         dbg_info *dbgi     = get_irn_dbg_info(node);
413         ir_node *new_store = NULL;
414
415         if (mode_is_float(mode)) {
416                 panic("Float not supported yet");
417         } else {
418                 assert(mode_is_data(mode) && "unsupported mode for Store");
419                 new_store = new_bd_amd64_Store(dbgi, block, new_ptr, new_val, new_mem, 0);
420         }
421         set_irn_pinned(new_store, get_irn_pinned(node));
422         return new_store;
423 }
424
425 /**
426  * Transforms a Load.
427  *
428  * @return the created AMD64 Load node
429  */
430 static ir_node *gen_Load(ir_node *node)
431 {
432         ir_node  *block    = be_transform_node(get_nodes_block(node));
433         ir_node  *ptr      = get_Load_ptr(node);
434         ir_node  *new_ptr  = be_transform_node(ptr);
435         ir_node  *mem      = get_Load_mem(node);
436         ir_node  *new_mem  = be_transform_node(mem);
437         ir_mode  *mode     = get_Load_mode(node);
438         dbg_info *dbgi     = get_irn_dbg_info(node);
439         ir_node  *new_load = NULL;
440
441         if (mode_is_float(mode)) {
442                 panic("Float not supported yet");
443         } else {
444                 assert(mode_is_data(mode) && "unsupported mode for Load");
445                 new_load = new_bd_amd64_Load(dbgi, block, new_ptr, new_mem, 0);
446         }
447         set_irn_pinned(new_load, get_irn_pinned(node));
448
449         /* check for special case: the loaded value might not be used */
450 //      if (be_get_Proj_for_pn(node, pn_Load_res) == NULL) {
451 //              /* add a result proj and a Keep to produce a pseudo use */
452 //              ir_node *proj = new_r_Proj(new_load, mode_Iu, pn_amd64_Load_res);
453 //              be_new_Keep(block, 1, &proj);
454 //      }
455
456         return new_load;
457 }
458
459 /**
460  * Transform a Proj from a Load.
461  */
462 static ir_node *gen_Proj_Load(ir_node *node)
463 {
464         ir_node  *load     = get_Proj_pred(node);
465         ir_node  *new_load = be_transform_node(load);
466         dbg_info *dbgi     = get_irn_dbg_info(node);
467         long     proj      = get_Proj_proj(node);
468
469         /* renumber the proj */
470         switch (get_amd64_irn_opcode(new_load)) {
471                 case iro_amd64_Load:
472                         /* handle all gp loads equal: they have the same proj numbers. */
473                         if (proj == pn_Load_res) {
474                                 return new_rd_Proj(dbgi, new_load, mode_Lu, pn_amd64_Load_res);
475                         } else if (proj == pn_Load_M) {
476                                 return new_rd_Proj(dbgi, new_load, mode_M, pn_amd64_Load_M);
477                         }
478                 break;
479         /*
480                 case iro_sparc_fpaLoad:
481                         panic("FP not implemented yet");
482                 break;
483         */
484                 default:
485                         panic("Unsupported Proj from Load");
486         }
487
488     return be_duplicate_node(node);
489 }
490
491 /**
492  * Transform a Proj node.
493  */
494 static ir_node *gen_Proj(ir_node *node)
495 {
496         ir_graph *irg  = current_ir_graph;
497         dbg_info *dbgi = get_irn_dbg_info(node);
498         ir_node  *pred = get_Proj_pred(node);
499         long     proj  = get_Proj_proj(node);
500
501         (void) irg;
502     (void) dbgi;
503
504         if (is_Store(pred)) {
505                 if (proj == pn_Store_M) {
506                         return be_transform_node(pred);
507                 } else {
508                         panic("Unsupported Proj from Store");
509                 }
510         } else if (is_Load(pred)) {
511                 return gen_Proj_Load(node);
512 //      } else if (be_is_SubSP(pred)) {
513 //              //panic("gen_Proj not implemented for SubSP");
514 //              return gen_Proj_be_SubSP(node);
515 //      } else if (be_is_AddSP(pred)) {
516 //              //panic("gen_Proj not implemented for AddSP");
517 //              return gen_Proj_be_AddSP(node);
518 //      } else if (is_Cmp(pred)) {
519 //              //panic("gen_Proj not implemented for Cmp");
520 //              return gen_Proj_Cmp(node);
521 //      } else if (is_Div(pred)) {
522 //              return gen_Proj_Div(node);
523         } else if (is_Start(pred)) {
524 //      /*
525 //              if (proj == pn_Start_X_initial_exec) {
526 //                      ir_node *block = get_nodes_block(pred);
527 //                      ir_node *jump;
528 //
529 //                      // we exchange the ProjX with a jump
530 //                      block = be_transform_node(block);
531 //                      jump  = new_rd_Jmp(dbgi, block);
532 //                      return jump;
533 //              }
534 //
535 //              if (node == get_irg_anchor(irg, anchor_tls)) {
536 //                      return gen_Proj_tls(node);
537 //              }
538 //      */
539 //      } else {
540 //              ir_node *new_pred = be_transform_node(pred);
541 //              ir_mode *mode     = get_irn_mode(node);
542 //              if (mode_needs_gp_reg(mode)) {
543 //                      ir_node *new_proj = new_r_Proj(new_pred, mode_Iu, get_Proj_proj(node));
544 //                      new_proj->node_nr = node->node_nr;
545 //                      return new_proj;
546 //              }
547         }
548
549     return be_duplicate_node(node);
550 }
551
552 /**
553  * Transforms a FrameAddr into an AMD64 Add.
554  */
555 static ir_node *gen_be_FrameAddr(ir_node *node)
556 {
557         ir_node   *block  = be_transform_node(get_nodes_block(node));
558         ir_entity *ent    = be_get_frame_entity(node);
559         ir_node   *fp     = be_get_FrameAddr_frame(node);
560         ir_node   *new_fp = be_transform_node(fp);
561         dbg_info  *dbgi   = get_irn_dbg_info(node);
562         ir_node   *new_node;
563
564         new_node = new_bd_amd64_FrameAddr(dbgi, block, new_fp, ent);
565         return new_node;
566 }
567
568 /* Boilerplate code for transformation: */
569
570 static void amd64_register_transformers(void)
571 {
572         be_start_transform_setup();
573
574         be_set_transform_function(op_Const,        gen_Const);
575         be_set_transform_function(op_SymConst,     gen_SymConst);
576         be_set_transform_function(op_Add,          gen_Add);
577         be_set_transform_function(op_Sub,          gen_Sub);
578         be_set_transform_function(op_Mul,          gen_Mul);
579         be_set_transform_function(op_be_Call,      gen_be_Call);
580         be_set_transform_function(op_be_FrameAddr, gen_be_FrameAddr);
581         be_set_transform_function(op_Conv,         gen_Conv);
582         be_set_transform_function(op_Jmp,          gen_Jmp);
583         be_set_transform_function(op_Cmp,          gen_Cmp);
584         be_set_transform_function(op_Cond,         gen_Cond);
585         be_set_transform_function(op_Phi,          gen_Phi);
586         be_set_transform_function(op_Load,         gen_Load);
587         be_set_transform_function(op_Store,        gen_Store);
588         be_set_transform_function(op_Proj,         gen_Proj);
589         be_set_transform_function(op_Minus,        gen_Minus);
590 }
591
592 void amd64_transform_graph(ir_graph *irg)
593 {
594         amd64_register_transformers();
595         be_transform_graph(irg, NULL);
596 }
597
598 void amd64_init_transform(void)
599 {
600         FIRM_DBG_REGISTER(dbg, "firm.be.amd64.transform");
601 }