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