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