3c730f6da3e93c7c73453415ff1e10c3b63a47ea
[libfirm] / ir / be / ppc32 / ppc32_transform_conv.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   The codegenerator (transform FIRM Conv nodes into ppc FIRM)
23  * @author  Moritz Kroll, Jens Mueller
24  * @version $Id$
25  */
26 #ifdef HAVE_CONFIG_H
27 #include "config.h"
28 #endif
29
30 #include "irnode_t.h"
31 #include "irgraph_t.h"
32 #include "irmode_t.h"
33 #include "irgmod.h"
34 #include "iredges.h"
35 #include "iredges_t.h"
36 #include "irvrfy.h"
37 #include "ircons.h"
38 #include "dbginfo.h"
39 #include "iropt_t.h"
40 #include "debug.h"
41
42 #include "../benode_t.h"
43 #include "bearch_ppc32_t.h"
44
45 #include "ppc32_nodes_attr.h"
46 //#include "../arch/archop.h"     /* we need this for Min and Max nodes */
47 #include "ppc32_transform_conv.h"
48 #include "ppc32_new_nodes.h"
49 #include "ppc32_map_regs.h"
50
51 #include "gen_ppc32_regalloc_if.h"
52
53 typedef struct
54 {
55         ir_node *first_conv;
56         ir_node **convs;
57         int conv_count;
58 } cw_block_attr;
59
60
61 ir_node *current_block;
62 int conv_nodes_found;
63 ir_entity *memslot;
64 ir_node *memory;
65
66 /**
67  * Conv walker initialization
68  */
69 void ppc32_init_conv_walk(void)
70 {
71         current_block = NULL;
72         conv_nodes_found = 0;
73         memslot = NULL;
74 }
75
76 static ir_node *own_gen_convert_call(ppc32_transform_env_t *env, ir_node *op, const char *funcname,
77                                                                          ir_mode *from_mode, ir_mode *to_mode)
78 {
79         ir_type *method_type;
80         ir_entity *method_ent;
81         ir_node *in[1];
82         ir_node *call, *callee, *call_results;
83
84         in[0] = op;
85
86         method_type = new_type_method(new_id_from_str("convert_call_type"), 1, 1);
87         set_method_param_type(method_type, 0, new_type_primitive(new_id_from_str("conv_param"), from_mode));
88         set_method_res_type(method_type, 0, new_type_primitive(new_id_from_str("conv_result"), to_mode));
89
90         method_ent   = new_entity(get_glob_type(), new_id_from_str(funcname), method_type);
91         callee       = new_rd_SymConst_addr_ent(env->dbg, env->irg, method_ent, method_type);
92         call         = new_rd_Call(env->dbg, env->irg, env->block, memory, callee, 1, in, method_type);
93         call_results = new_rd_Proj(env->dbg, env->irg, env->block, call, mode_T, pn_Call_T_result);
94         memory       = new_rd_Proj(env->dbg, env->irg, env->block, call, mode_M, pn_Call_M_regular);
95
96         return new_rd_Proj(env->dbg, env->irg, env->block, call_results, to_mode, 0);
97 }
98
99 /**
100  * Transforms a Conv node.
101  *
102  * @param mod     the debug module
103  * @param block   the block the new node should belong to
104  * @param node    the ir Conv node
105  * @param op      operator
106  * @param mode    node mode
107  * @return the created ppc Conv node
108  */
109 static ir_node *gen_Conv(ppc32_transform_env_t *env, ir_node *op) {
110         ir_mode *from_mode = get_irn_mode(get_irn_n(env->irn,0));
111         ir_mode *to_mode = env->mode;
112         modecode from_modecode=get_mode_modecode(from_mode);
113         modecode to_modecode=get_mode_modecode(to_mode);
114
115         switch(from_modecode){
116                 case irm_F:
117                         op = new_rd_Conv(env->dbg, env->irg, env->block, op, mode_D);
118                         // fall through
119                 case irm_D:
120                 {
121                         ir_node *res;
122                         if (mode_is_signed(to_mode))  // Float to integer
123                         {
124                                 ir_node *fctiw = new_rd_ppc32_fCtiw(env->dbg, env->irg, env->block, op, from_mode);
125                                 ir_node *stfd = new_rd_ppc32_Stfd(env->dbg, env->irg, env->block, get_irg_frame(env->irg),
126                                         fctiw, memory);
127                                 ir_node *storememproj = new_rd_Proj(env->dbg, env->irg, env->block, stfd, mode_M, pn_Store_M);
128                                 ir_node *lwz = new_rd_ppc32_Lwz(env->dbg, env->irg, env->block, get_irg_frame(env->irg),
129                                         storememproj);
130                                 set_ppc32_frame_entity(stfd, memslot);
131                                 set_ppc32_offset_mode(stfd, ppc32_ao_Lo16);     // TODO: only allows a 16-bit offset on stack
132                                 set_ppc32_frame_entity(lwz, memslot);
133                                 set_ppc32_offset_mode(stfd, ppc32_ao_Lo16);     // TODO: only allows a 16-bit offset on stack
134                                 memory = new_rd_Proj(env->dbg, env->irg, env->block, lwz, mode_M, pn_Store_M);
135                                 res = new_rd_Proj(env->dbg, env->irg, env->block, lwz, to_mode, pn_Load_res);
136
137                         }
138                         else
139                         {
140                                 res = own_gen_convert_call(env, op, "conv_double_to_unsigned_int", mode_D, mode_Iu);
141                         }
142
143                         switch(to_modecode)
144                         {
145                                 case irm_Bs:
146                                 case irm_Hs:
147                                 case irm_Bu:
148                                 case irm_Hu:
149                                         return new_rd_Conv(env->dbg, env->irg, env->block, res, to_mode);
150                                 case irm_Is:
151                                 case irm_Iu:
152                                         return res;
153                                 default:
154                                         break;
155                         }
156                         break;
157                 }
158                 case irm_Hs:
159                 case irm_Bs:
160                         op = new_rd_Conv(env->dbg, env->irg, env->block, op, mode_Is);
161                 case irm_Is:
162                         return own_gen_convert_call(env, op, (to_mode == mode_D) ? "conv_int_to_double" : "conv_int_to_single", mode_Is, to_mode);
163
164
165                 case irm_Hu:
166                 case irm_Bu:
167                         op = new_rd_Conv(env->dbg, env->irg, env->block, op, mode_Iu);
168                 case irm_Iu:
169                         return own_gen_convert_call(env, op, (to_mode == mode_D) ? "conv_unsigned_int_to_double": "conv_unsigned_int_to_single", mode_Iu, to_mode);
170
171                 case irm_P:
172                         break;
173
174                 default:
175                         break;
176         }
177         fprintf(stderr, "Mode for Conv not supported: %s -> %s\n", get_mode_name(from_mode), get_mode_name(to_mode));
178         assert(0);
179         return 0;
180
181         // return op;
182 }
183
184 int search_from_node_in_block(ir_node *from, ir_node *to)
185 {
186         int n = get_irn_arity(from), i;
187         for(i=0;i<n;i++)
188         {
189                 ir_node *pred = get_irn_n(from, i);
190                 if(pred==to) return 1;
191                 if(get_irn_n(pred, -1)==current_block)
192                 {
193                         if(search_from_node_in_block(pred, to)) return 1;
194                 }
195         }
196         return 0;
197 }
198
199 int nodes_dependency_order(ir_node **a, ir_node **b)
200 {
201         if(search_from_node_in_block(*a,*b)) return 1;
202         if(search_from_node_in_block(*b,*a)) return -1;
203         return 0;
204 }
205
206 void finalize_block(ppc32_code_gen_t *cgenv)
207 {
208         int i;
209         ir_node *current_conv;
210         cw_block_attr *attr = current_block->link;
211         ppc32_transform_env_t tenv;
212
213         if(!attr->conv_count) return;
214
215         if(!memslot)
216         {
217                 ir_type *frame_type = get_irg_frame_type(cgenv->irg);
218                 memslot = frame_alloc_area(frame_type, get_mode_size_bytes(mode_D), 4, 0);
219         }
220
221         attr->convs = xmalloc(attr->conv_count * sizeof(ir_node *));
222
223         for (i = 0, current_conv = attr->first_conv; i < attr->conv_count; i++, current_conv = current_conv->link)
224         {
225                 attr->convs[i] = current_conv;
226         }
227
228         qsort(attr->convs, attr->conv_count, sizeof(ir_node *),
229                 (int (*)(const void *, const void *)) nodes_dependency_order);
230
231         tenv.block    = current_block;
232         tenv.irg      = current_ir_graph;
233         DEBUG_ONLY(tenv.mod      = cgenv->mod;)
234
235         memory = get_irg_no_mem(current_ir_graph);
236         for(i = 0; i < attr->conv_count; i++)
237         {
238                 tenv.dbg      = get_irn_dbg_info(attr->convs[i]);
239                 tenv.irn      = attr->convs[i];
240                 tenv.mode     = get_irn_mode(attr->convs[i]);
241
242                 exchange(attr->convs[i], gen_Conv(&tenv, get_Conv_op(attr->convs[i])));
243         }
244 }
245
246 void init_block(void)
247 {
248         cw_block_attr *attr = xmalloc(sizeof(cw_block_attr));
249         attr->first_conv    = NULL;
250         attr->convs         = NULL; /* attr->convs is set in finalize_block() */
251         attr->conv_count    = 0;
252         current_block->link = attr;
253 }
254
255 /**
256  * Constant generating code
257  */
258
259 #if 0
260 struct tv_ent {
261         ir_entity *ent;
262         tarval *tv;
263 };
264
265 /* Compares two (entity, tarval) combinations */
266 static int cmp_tv_ent(const void *a, const void *b, size_t len) {
267         const struct tv_ent *e1 = a;
268         const struct tv_ent *e2 = b;
269
270         return !(e1->tv == e2->tv);
271 }
272
273 /* Generates a SymConst node for a known FP const */
274 static ir_node *gen_fp_known_symconst(ppc32_transform_env_t *env, tarval *known_const) {
275         static set    *const_set = NULL;
276         static ir_type *tp = NULL;
277         struct tv_ent  key;
278         struct tv_ent *entry;
279         ir_node       *cnst;
280         ir_graph      *rem;
281         ir_entity     *ent;
282
283         if(!const_set)
284                 const_set = new_set(cmp_tv_ent, 10);
285         if(!tp)
286                 tp = new_type_primitive(new_id_from_str("const_double_t"), env->mode);
287
288
289         key.tv  = known_const;
290         key.ent = NULL;
291
292         entry = set_insert(const_set, &key, sizeof(key), HASH_PTR(key.tv));
293
294         if(!entry->ent) {
295                 char buf[80];
296                 sprintf(buf, "const_%ld", get_irn_node_nr(env->irn));
297                 ent = new_entity(get_glob_type(), new_id_from_str(buf), tp);
298
299                 set_entity_ld_ident(ent, get_entity_ident(ent));
300                 set_entity_visibility(ent, visibility_local);
301                 set_entity_variability(ent, variability_constant);
302                 set_entity_allocation(ent, allocation_static);
303
304                 /* we create a new entity here: It's initialization must resist on the
305                     const code irg */
306                 rem = current_ir_graph;
307                 current_ir_graph = get_const_code_irg();
308                 cnst = new_Const(env->mode, key.tv);
309                 current_ir_graph = rem;
310
311                 set_atomic_ent_value(ent, cnst);
312
313                 /* set the entry for hashmap */
314                 entry->ent = ent;
315         }
316
317         return new_rd_SymConst_addr_ent(env->dbg, env->irg, ent, tp);
318 }
319 #endif
320
321 /**
322  * Transforms a Const
323  *
324  * @param env transformation environment
325  * @return the created ppc Const node
326  */
327 static ir_node *gen_Const(ppc32_transform_env_t *env) {
328         tarval *tv_const = get_Const_tarval(env->irn);
329         ir_node *constant;
330
331         if (mode_is_float(env->mode))
332                 constant = new_rd_ppc32_fConst(env->dbg, env->irg, env->block, env->mode);
333         else
334                 constant = new_rd_ppc32_Const(env->dbg, env->irg, env->block, env->mode);
335         set_ppc32_constant_tarval(constant, tv_const);
336         return constant;
337 }
338
339 /**
340  * Transforms a SymConst.
341  *
342  * @param env transformation environment
343  * @return the created ppc SymConst node
344  */
345 static ir_node *gen_SymConst(ppc32_transform_env_t *env) {
346         ir_node *symconst;
347         symconst = new_rd_ppc32_SymConst(env->dbg, env->irg, env->block, env->mode);
348         set_ppc32_frame_entity(symconst, get_SymConst_entity(env->irn));
349         return symconst;
350 }
351
352 /*********************************************************
353  *                  _             _      _
354  *                 (_)           | |    (_)
355  *  _ __ ___   __ _ _ _ __     __| |_ __ ___   _____ _ __
356  * | '_ ` _ \ / _` | | '_ \   / _` | '__| \ \ / / _ \ '__|
357  * | | | | | | (_| | | | | | | (_| | |  | |\ V /  __/ |
358  * |_| |_| |_|\__,_|_|_| |_|  \__,_|_|  |_| \_/ \___|_|
359  *
360  *********************************************************/
361
362
363
364 /**
365  * Transforms all conv nodes into ppc convs before abi
366  *
367  * @param node    the firm node
368  * @param env     the debug module
369  */
370 void ppc32_conv_walk(ir_node *node, void *env) {
371         ppc32_code_gen_t *cgenv = (ppc32_code_gen_t *)env;
372         ir_opcode  code         = get_irn_opcode(node);
373         ppc32_transform_env_t tenv;
374
375         if (is_Block(node))
376         {
377                 if(current_block != NULL)
378                         finalize_block(cgenv);
379
380                 current_block = node;
381                 init_block();
382
383                 return;
384         }
385
386         tenv.irg = current_ir_graph;
387         DEBUG_ONLY(tenv.mod = cgenv->mod;)
388
389         if (code == iro_Conv)
390         {
391                 modecode from_mode=get_mode_modecode(get_irn_mode(get_irn_n(node,0)));
392                 modecode to_mode=get_mode_modecode(get_irn_mode(node));
393                 cw_block_attr *attr;
394
395                 if(from_mode == to_mode) return;
396                 if(from_mode == irm_F || from_mode == irm_D)
397                 {
398                         switch(to_mode)
399                         {
400                                 case irm_Bs:
401                                 case irm_Bu:
402                                 case irm_Hs:
403                                 case irm_Hu:
404                                 case irm_Is:
405                                 case irm_Iu:
406                                         break;
407                                 default:
408                                         return;
409
410                         }
411                 }
412                 else if(to_mode == irm_F || to_mode == irm_D)
413                 {
414                         switch(from_mode)
415                         {
416                                 case irm_Bs:
417                                 case irm_Bu:
418                                 case irm_Hs:
419                                 case irm_Hu:
420                                 case irm_Is:
421                                 case irm_Iu:
422                                         break;
423                                 default:
424                                         return;
425                         }
426                 }
427                 else return;
428
429                 /* in Liste eintragen */
430                 attr = get_irn_link(current_block);
431                 set_irn_link(node, attr->first_conv);
432                 attr->first_conv = node;
433                 attr->conv_count++;
434                 conv_nodes_found++;
435         }
436         else if (code == iro_Call) {
437                 int i, size = 0;
438                 ir_type *tp = get_Call_type(node);
439                 ir_type *ptp;
440                 int stack_alignment = 4;
441
442                 for (i = get_Call_n_params(node) - 1; i >= 0; --i) {
443                         ir_mode *mode = get_irn_mode(get_Call_param(node, i));
444                         int s;
445
446                         if (mode_is_reference(mode)) {
447                                 /* might be a compound parameter */
448                                 ptp = get_method_param_type(tp, i);
449
450                                 if (is_compound_type(ptp)) {
451                                         s = (get_type_size_bytes(ptp) + stack_alignment - 1) & -stack_alignment;
452
453                                         size += s;
454                                         continue;
455                                 }
456                         }
457                         s = (get_mode_size_bytes(mode) + stack_alignment - 1) & -stack_alignment;
458                         size += s;
459                 }
460                 if ((unsigned) size > cgenv->area_size)
461                         cgenv->area_size = size;
462         }
463 }
464
465 /**
466  * Transforms all const nodes into ppc const nodes inside the using block
467  *
468  * @param node    the firm node
469  * @param env     the debug module
470  */
471 void ppc32_pretransform_walk(ir_node *node, void *env) {
472         ppc32_code_gen_t *cgenv = (ppc32_code_gen_t *)env;
473         ir_opcode  code         = get_irn_opcode(node);
474         ppc32_transform_env_t tenv;
475
476         if (is_Block(node))
477         {
478                 current_block = node;
479                 return;
480         }
481
482         tenv.irg = current_ir_graph;
483         DEBUG_ONLY(tenv.mod = cgenv->mod;)
484
485         if(code == iro_Const || code == iro_SymConst)
486         {
487                 ir_node *newconst;
488
489                 tenv.block    = cgenv->start_succ_block;
490                 tenv.irn      = node;
491                 tenv.mode     = get_irn_mode(node);
492                 tenv.dbg      = get_irn_dbg_info(node);
493
494                 if(code == iro_Const)
495                         newconst = gen_Const(&tenv);
496                 else
497                         newconst = gen_SymConst(&tenv);
498
499                 exchange(node, newconst);
500         }
501 }