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