add special constant to represent VA_START-address in a parameter_entity
[libfirm] / ir / lower / lower_softfloat.c
1 /*
2  * Copyright (C) 1995-2011 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   Lower floating point operations to function calls
23  * @author  Sebastian Buchwald
24  */
25 #include "config.h"
26
27 #include <stdbool.h>
28
29 #include "be.h"
30 #include "dbginfo_t.h"
31 #include "debug.h"
32 #include "error.h"
33 #include "ircons.h"
34 #include "iredges.h"
35 #include "irgmod.h"
36 #include "irnodeset.h"
37 #include "irgwalk.h"
38 #include "irmode.h"
39 #include "iropt_dbg.h"
40 #include "irprog_t.h"
41 #include "lower_softfloat.h"
42 #include "lowering.h"
43 #include "pmap.h"
44 #include "type_t.h"
45 #include "tv_t.h"
46
47 /** The debug handle */
48 DEBUG_ONLY(static firm_dbg_module_t *dbg = NULL;)
49
50 typedef void (*lower_softfloat_func)(ir_node *node);
51
52 static ir_type *binop_tp_d;
53 static ir_type *binop_tp_f;
54 static ir_type *cmp_tp_d;
55 static ir_type *cmp_tp_f;
56 static ir_type *unop_tp_d;
57 static ir_type *unop_tp_f;
58 static ir_type *unop_tp_d_f;
59 static ir_type *unop_tp_d_is;
60 static ir_type *unop_tp_d_iu;
61 static ir_type *unop_tp_d_ls;
62 static ir_type *unop_tp_d_lu;
63 static ir_type *unop_tp_f_d;
64 static ir_type *unop_tp_f_is;
65 static ir_type *unop_tp_f_iu;
66 static ir_type *unop_tp_f_ls;
67 static ir_type *unop_tp_f_lu;
68 static ir_type *unop_tp_is_d;
69 static ir_type *unop_tp_is_f;
70 static ir_type *unop_tp_iu_d;
71 static ir_type *unop_tp_iu_f;
72 static ir_type *unop_tp_ls_d;
73 static ir_type *unop_tp_ls_f;
74 static ir_type *unop_tp_lu_d;
75 static ir_type *unop_tp_lu_f;
76
77 /** A map from a method type to its lowered type. */
78 static pmap *lowered_type;
79
80 static ir_nodeset_t created_mux_nodes;
81
82 /**
83  * @return The lowered (floating point) mode.
84  */
85 static ir_mode *get_lowered_mode(ir_mode *mode)
86 {
87         if (! mode_is_float(mode))
88                 return mode;
89
90         if (mode == mode_F)
91                 return mode_Iu;
92         else if (mode == mode_D)
93                 return mode_Lu;
94
95         panic("Unsupported floating point type");
96 }
97
98 /**
99  * Adapts the mode of the given node.
100  */
101 static void lower_mode(ir_node *n, void *env)
102 {
103         ir_op                *op         = get_irn_op(n);
104         lower_softfloat_func  lower_func = (lower_softfloat_func) op->ops.generic;
105         ir_mode              *mode       = get_irn_mode(n);
106
107         (void) env;
108
109         if (lower_func != NULL) {
110                 lower_func(n);
111                 return;
112         }
113
114         set_irn_mode(n, get_lowered_mode(mode));
115 }
116
117 /**
118  * Wrapper for specific lower function.
119  */
120 static void lower_node(ir_node *n, void *env)
121 {
122         ir_op                *op         = get_irn_op(n);
123         lower_softfloat_func  lower_func = (lower_softfloat_func) op->ops.generic;
124
125         (void) env;
126
127         if (lower_func != NULL)
128                 lower_func(n);
129 }
130
131 /**
132  * @return The type of the function replacing the given node.
133  */
134 static ir_type *get_softfloat_type(const ir_node *n)
135 {
136         unsigned opcode       = get_irn_opcode(n);
137         ir_mode *mode         = get_irn_mode(n);
138         ir_node *operand      = get_irn_n(n, 0);
139         ir_mode *operand_mode = get_irn_mode(operand);
140
141         switch (opcode) {
142         case iro_Div:
143                 mode         = get_Div_resmode(n);
144                 operand_mode = get_irn_mode(get_Div_left(n));
145                 /* fall through */
146         case iro_Add:
147         case iro_Mul:
148         case iro_Sub:
149                 if (operand_mode == mode_F)
150                         return binop_tp_f;
151                 else if (operand_mode == mode_D)
152                         return binop_tp_d;
153                 break;
154         case iro_Cmp:
155                 if (operand_mode == mode_F)
156                         return cmp_tp_f;
157                 else if (operand_mode == mode_D)
158                         return cmp_tp_d;
159                 break;
160         case iro_Conv:
161                 if (operand_mode == mode_D) {
162                         if (mode == mode_F)
163                                 return unop_tp_d_f;
164                         else if (mode == mode_Is || mode == mode_Hs || mode == mode_Bs)
165                                 return unop_tp_d_is;
166                         else if (mode == mode_Iu || mode == mode_Hu || mode == mode_Bu)
167                                 return unop_tp_d_iu;
168                         else if (mode == mode_Ls)
169                                 return unop_tp_d_ls;
170                         else if (mode == mode_Lu)
171                                 return unop_tp_d_lu;
172                 }
173                 else if (operand_mode == mode_F) {
174                         if (mode == mode_D)
175                                 return unop_tp_f_d;
176                         else if (mode == mode_Is || mode == mode_Hs || mode == mode_Bs)
177                                 return unop_tp_f_is;
178                         else if (mode == mode_Iu || mode == mode_Hu || mode == mode_Bu)
179                                 return unop_tp_f_iu;
180                         else if (mode == mode_Ls)
181                                 return unop_tp_f_ls;
182                         else if (mode == mode_Lu)
183                                 return unop_tp_f_lu;
184                 }
185                 else if (operand_mode == mode_Is || operand_mode == mode_Hs || operand_mode == mode_Bs) {
186                         if (mode == mode_D)
187                                 return unop_tp_is_d;
188                         else if (mode == mode_F)
189                                 return unop_tp_is_f;
190                 }
191                 else if (operand_mode == mode_Iu || operand_mode == mode_Hu || operand_mode == mode_Bu) {
192                         if (mode == mode_D)
193                                 return unop_tp_iu_d;
194                         else if (mode == mode_F)
195                                 return unop_tp_iu_f;
196                 }
197                 else if (operand_mode == mode_Ls) {
198                         if (mode == mode_D)
199                                 return unop_tp_ls_d;
200                         else if (mode == mode_F)
201                                 return unop_tp_ls_f;
202                 }
203                 else if (operand_mode == mode_Lu) {
204                         if (mode == mode_D)
205                                 return unop_tp_lu_d;
206                         else if (mode == mode_F)
207                                 return unop_tp_lu_f;
208                 }
209                 break;
210         case iro_Minus:
211                 if (operand_mode == mode_F)
212                         return unop_tp_f;
213                 else if (operand_mode == mode_D)
214                         return unop_tp_d;
215                 break;
216         default: break;
217         }
218
219         assert(0 && "Could not determine a suitable type");
220
221         return NULL;
222 }
223
224 /**
225  * @return A SymConst representing the function that replaces the given node.
226  */
227 static ir_node *create_softfloat_symconst(const ir_node *n, const char *name)
228 {
229         char             buf[16];
230         const char      *first_param = "";
231         const char      *second_param = "";
232         const char      *result = "";
233         ir_entity       *ent;
234         size_t           n_params;
235         ident           *id;
236         symconst_symbol  sym;
237         unsigned         float_types  = 0;
238         unsigned         double_types  = 0;
239         ir_graph        *irg    = get_irn_irg(n);
240         ir_type         *method = get_softfloat_type(n);
241
242         n_params = get_method_n_params(method);
243
244         /* Parameter types. */
245         switch (n_params) {
246         case 2:
247                 {
248                         ir_type *param_type = get_method_param_type(method, 1);
249                         ir_mode *mode       = get_type_mode(param_type);
250
251                         if (mode == mode_F) {
252                                 second_param = "sf";
253                                 float_types++;
254                         }
255                         else if (mode == mode_D) {
256                                 second_param = "df";
257                                 double_types++;
258                         }
259                         else if (mode == mode_Iu || mode == mode_Is)
260                                 second_param = "si";
261                         else if (mode == mode_Lu || mode == mode_Ls)
262                                 second_param = "di";
263                 }
264                 /* fall through */
265         case 1:
266                 {
267                         ir_type *param_type = get_method_param_type(method, 0);
268                         ir_mode *mode       = get_type_mode(param_type);
269
270                         if (mode == mode_F) {
271                                 first_param = float_types > 0 ? "" : "sf";
272                                 float_types++;
273                         }
274                         else if (mode == mode_D) {
275                                 first_param = double_types > 0 ? "" : "df";
276                                 double_types++;
277                         }
278                         else if (mode == mode_Iu || mode == mode_Is)
279                                 first_param = "si";
280                         else if (mode == mode_Lu || mode == mode_Ls)
281                                 first_param = "di";
282                 }
283                 break;
284         default:
285                 break;
286         }
287
288         /* Result type. */
289         {
290                 ir_mode *mode;
291
292                 if (is_Div(n))
293                         mode = get_Div_resmode(n);
294                 else
295                         mode = get_irn_mode(n);
296
297                 if (mode == mode_F) {
298                         result = float_types > 0 ? "" : "sf";
299                         float_types++;
300                 }
301                 else if (mode == mode_D) {
302                         result = double_types > 0 ? "" : "df";
303                         double_types++;
304                 }
305                 else if (mode == mode_Iu || mode == mode_Hu || mode == mode_Bu
306                                 || mode == mode_Is || mode == mode_Hs || mode == mode_Bs)
307                         result = "si";
308                 else if (mode == mode_Lu || mode == mode_Ls)
309                         result = "di";
310         }
311
312         assert(float_types <= 3);
313         assert(double_types <= 3);
314
315         if (float_types + double_types > 1)
316                 snprintf(buf, sizeof(buf), "__%s%s%s%s%u", name, first_param, second_param, result, float_types + double_types);
317         else
318                 snprintf(buf, sizeof(buf), "__%s%s%s%s", name, first_param, second_param, result);
319
320         id  = new_id_from_str(buf);
321         ent = new_entity(get_glob_type(), id, method);
322
323         set_entity_ld_ident(ent, get_entity_ident(ent));
324         sym.entity_p = ent;
325
326         return new_r_SymConst(irg, mode_P_code, sym, symconst_addr_ent);
327 }
328
329 /**
330  * Transforms an Add into the appropriate soft float function.
331  */
332 static void lower_Add(ir_node *n)
333 {
334         ir_node         *symconst;
335         ir_node         *block       = get_nodes_block(n);
336         ir_node         *call_result = NULL;
337         dbg_info        *dbgi        = get_irn_dbg_info(n);
338         ir_graph        *irg         = get_irn_irg(n);
339         ir_node         *left        = get_Add_left(n);
340         ir_node         *right       = get_Add_right(n);
341         ir_mode         *mode        = get_irn_mode(n);
342
343         if (! mode_is_float(mode))
344                 return;
345
346         symconst = create_softfloat_symconst(n, "add");
347
348         ir_node *call;
349         ir_node *call_results;
350         ir_node *in[2]    = {left, right};
351         ir_node *nomem    = get_irg_no_mem(irg);
352         ir_type *type     = get_softfloat_type(n);
353         ir_mode *res_mode = get_type_mode(get_method_res_type(type, 0));
354
355         call         = new_rd_Call(dbgi, block, nomem, symconst, 2, in, type);
356         call_results = new_r_Proj(call, mode_T, pn_Call_T_result);
357         call_result  = new_r_Proj(call_results, res_mode, 0);
358
359         exchange(n, call_result);
360 }
361
362 /**
363  * @return The lowered (floating point) type.
364  */
365 static ir_type *lower_type(ir_type *tp)
366 {
367         ir_mode *mode         = get_type_mode(tp);
368         ir_mode *lowered_mode = get_lowered_mode(mode);
369
370         return get_type_for_mode(lowered_mode);
371 }
372
373 /**
374  * @return The lowered method type.
375  */
376 static ir_type *lower_method_type(ir_type *mtp)
377 {
378         ir_type *res;
379         size_t   i;
380         size_t   n_param;
381         size_t   n_res;
382
383         res = (ir_type*)pmap_get(lowered_type, mtp);
384         if (res != NULL)
385                 return res;
386
387         n_param = get_method_n_params(mtp);
388         n_res   = get_method_n_ress(mtp);
389
390         res = new_type_method(n_param, n_res);
391
392         /* set param types and result types */
393         for (i = 0; i < n_param; ++i) {
394                 ir_type *ptp   = get_method_param_type(mtp, i);
395                 ir_mode *pmode = get_type_mode(ptp);
396
397                 if (pmode != NULL && mode_is_float(pmode)) {
398                         ptp = lower_type(ptp);
399                 }
400
401                 set_method_param_type(res, i, ptp);
402         }
403         for (i = 0; i < n_res; ++i) {
404                 ir_type *rtp   = get_method_res_type(mtp, i);
405                 ir_mode *rmode = get_type_mode(rtp);
406
407                 if (rmode != NULL && mode_is_float(rmode)) {
408                         rtp = lower_type(rtp);
409                 }
410
411                 set_method_res_type(res, i, rtp);
412         }
413
414         set_method_variadicity(res, get_method_variadicity(mtp));
415         set_method_calling_convention(res, get_method_calling_convention(mtp));
416         set_method_additional_properties(res, get_method_additional_properties(mtp));
417
418         set_lowered_type(mtp, res);
419
420         pmap_insert(lowered_type, mtp, res);
421         return res;
422 }
423
424 /**
425  * Adapts the method type of a Call.
426  */
427 static void lower_Call(ir_node *node)
428 {
429         ir_type  *tp = get_Call_type(node);
430         size_t   n_params;
431         size_t   n_res;
432         bool     need_lower = false;
433         size_t   i;
434         size_t   p;
435
436         n_params = get_method_n_params(tp);
437
438         for (p = 0; p < n_params; ++p) {
439                 ir_type *ptp   = get_method_param_type(tp, p);
440                 ir_mode *pmode = get_type_mode(ptp);
441
442                 if (pmode == NULL)
443                         continue;
444
445                 if (mode_is_float(pmode)) {
446                         need_lower = true;
447                         break;
448                 }
449         }
450
451         n_res = get_method_n_ress(tp);
452
453         for (i = 0; i < n_res; ++i) {
454                 ir_type *rtp   = get_method_res_type(tp, i);
455                 ir_mode *rmode = get_type_mode(rtp);
456
457                 if (rmode == NULL)
458                         continue;
459
460                 if (mode_is_float(rmode)) {
461                         need_lower = true;
462                         break;
463                 }
464         }
465
466         if (! need_lower)
467                 return;
468
469         tp = lower_method_type(tp);
470         set_Call_type(node, tp);
471 }
472
473 /**
474  * Transforms a Cmp into the appropriate soft float function.
475  */
476 static void lower_Cmp(ir_node *n)
477 {
478         ir_node         *symconst    = NULL;
479         ir_node         *block       = get_nodes_block(n);
480         ir_node         *call_result = NULL;
481         dbg_info        *dbgi        = get_irn_dbg_info(n);
482         ir_graph        *irg         = get_irn_irg(n);
483         ir_node         *left        = get_Cmp_left(n);
484         ir_relation      relation    = get_Cmp_relation(n);
485         ir_mode         *op_mode     = get_irn_mode(left);
486         ir_node         *right       = get_Cmp_right(n);
487         ir_node         *symconst2   = NULL;
488         ir_node         *zero        = new_rd_Const(dbgi, irg, get_mode_null(mode_Is));
489
490         if (! mode_is_float(op_mode))
491                 return;
492
493         switch (relation) {
494         case ir_relation_false:
495                 call_result = zero;
496                 break;
497         case ir_relation_equal:
498                 symconst = create_softfloat_symconst(n, "eq");
499                 break;
500         case ir_relation_less:
501                 symconst = create_softfloat_symconst(n, "lt");
502                 break;
503         case ir_relation_greater:
504                 symconst = create_softfloat_symconst(n, "gt");
505                 break;
506         case ir_relation_unordered:
507                 symconst = create_softfloat_symconst(n, "unord");
508                 relation = ir_relation_less_greater;
509                 break;
510         case ir_relation_less_equal:
511                 symconst = create_softfloat_symconst(n, "le");
512                 break;
513         case ir_relation_greater_equal:
514                 symconst = create_softfloat_symconst(n, "ge");
515                 break;
516         case ir_relation_less_greater:
517                 symconst  = create_softfloat_symconst(n, "unord");
518                 symconst2 = create_softfloat_symconst(n, "ne");
519                 break;
520         case ir_relation_less_equal_greater:
521                 symconst = create_softfloat_symconst(n, "unord");
522                 relation = ir_relation_equal;
523                 break;
524         case ir_relation_unordered_equal:
525                 symconst  = create_softfloat_symconst(n, "unord");
526                 relation  = ir_relation_less_greater;
527                 symconst2 = create_softfloat_symconst(n, "ne");
528                 break;
529         case ir_relation_unordered_less:
530                 symconst = create_softfloat_symconst(n, "ge");
531                 relation = ir_relation_less;
532                 break;
533         case ir_relation_unordered_less_equal:
534                 symconst = create_softfloat_symconst(n, "gt");
535                 relation = ir_relation_less_equal;
536                 break;
537         case ir_relation_unordered_greater:
538                 symconst = create_softfloat_symconst(n, "le");
539                 relation = ir_relation_greater;
540                 break;
541         case ir_relation_unordered_greater_equal:
542                 symconst = create_softfloat_symconst(n, "lt");
543                 relation = ir_relation_greater_equal;
544                 break;
545         case ir_relation_unordered_less_greater:
546                 symconst = create_softfloat_symconst(n, "eq");
547                 relation = ir_relation_less_greater;
548                 break;
549         case ir_relation_true:
550                 call_result = zero;
551                 break;
552         }
553
554         if (call_result == NULL) {
555                 ir_node *call;
556                 ir_node *call_results;
557                 ir_node *in[2] = {left, right};
558                 ir_node *nomem = get_irg_no_mem(irg);
559                 ir_type *type  = get_softfloat_type(n);
560
561                 call         = new_rd_Call(dbgi, block, nomem, symconst, 2, in, type);
562                 call_results = new_r_Proj(call, mode_T, pn_Call_T_result);
563                 call_result  = new_r_Proj(call_results, mode_Is, 0);
564         }
565
566         ir_node *cmp = new_r_Cmp(block, call_result, zero, relation);
567
568         /* We need two calls into the softfloat library */
569         if (symconst2 != NULL) {
570                 ir_node *call;
571                 ir_node *call_results;
572                 ir_node *mux;
573                 arch_allow_ifconv_func allow_ifconv = be_get_backend_param()->allow_ifconv;
574                 ir_node *in[2]                      = {left, right};
575                 ir_node *nomem                      = get_irg_no_mem(irg);
576                 ir_type *type                       = get_softfloat_type(n);
577
578                 call         = new_rd_Call(dbgi, block, nomem, symconst2, 2, in, type);
579                 call_results = new_r_Proj(call, mode_T, pn_Call_T_result);
580                 call_result  = new_r_Proj(call_results, mode_Is, 0);
581                 relation     = get_Cmp_relation(n);
582
583                 mux = new_rd_Mux(dbgi, block, cmp, call_result, zero, mode_Is);
584
585                 if (! allow_ifconv(cmp, call_result, zero))
586                         ir_nodeset_insert(&created_mux_nodes, mux);
587
588                 cmp = new_r_Cmp(block, mux, zero, relation);
589         }
590
591         exchange(n, cmp);
592 }
593
594 static const tarval_mode_info hex_output = {
595         TVO_HEX,
596         "0x",
597         NULL,
598 };
599
600 /**
601  * Adapts floating point constants.
602  */
603 static void lower_Const(ir_node *n)
604 {
605         ir_mode   *lowered_mode;
606         ir_mode   *mode         = get_irn_mode(n);
607         ir_tarval *tv = get_Const_tarval(n);
608         char       buf[100];
609         size_t     len;
610
611         if (! mode_is_float(mode))
612                 return;
613
614         lowered_mode = get_lowered_mode(mode);
615         set_irn_mode(n, lowered_mode);
616
617         set_tarval_mode_output_option(mode, &hex_output);
618         tarval_snprintf(buf, 100, get_Const_tarval(n));
619
620         len = strlen(buf);
621         tv  = new_tarval_from_str(buf, len, lowered_mode);
622         set_Const_tarval(n, tv);
623 }
624
625 /**
626  * Transforms a Conv into the appropriate soft float function.
627  */
628 static void lower_Conv(ir_node *n)
629 {
630         ir_node         *symconst;
631         ir_node         *block       = get_nodes_block(n);
632         ir_node         *call_result = NULL;
633         dbg_info        *dbgi        = get_irn_dbg_info(n);
634         ir_graph        *irg         = get_irn_irg(n);
635         ir_node         *op          = get_Conv_op(n);
636         ir_mode         *mode        = get_irn_mode(n);
637         ir_mode         *op_mode     = get_irn_mode(op);
638
639         if (! mode_is_float(mode) && ! mode_is_float(op_mode))
640                 return;
641
642         /* Remove unnecessary Convs. */
643         if (op_mode == mode) {
644                 exchange(n, op);
645                 return;
646         }
647         else if (op_mode == mode_Hs || op_mode == mode_Bs) {
648                 op_mode = mode_Is;
649                 op     = new_rd_Conv(dbgi, block, op, op_mode);
650         }
651         else if (op_mode == mode_Hu || op_mode == mode_Bu) {
652                 op_mode = mode_Iu;
653                 op     = new_rd_Conv(dbgi, block, op, op_mode);
654         }
655
656         if (mode_is_float(op_mode) && mode_is_float(mode)) {
657                 if (get_mode_size_bits(op_mode) > get_mode_size_bits(mode))
658                         symconst = create_softfloat_symconst(n, "trunc");
659                 else
660                         symconst = create_softfloat_symconst(n, "extend");
661         }
662         else if (mode_is_float(op_mode)) {
663                 if (mode_is_signed(mode))
664                         symconst = create_softfloat_symconst(n, "fix");
665                 else
666                         symconst = create_softfloat_symconst(n, "fixuns");
667         }
668         else {
669                 if (mode_is_signed(op_mode))
670                         symconst = create_softfloat_symconst(n, "float");
671                 else
672                         symconst = create_softfloat_symconst(n, "floatun");
673         }
674
675         ir_node *call;
676         ir_node *call_results;
677         ir_node *in[1]    = {op};
678         ir_node *nomem    = get_irg_no_mem(irg);
679         ir_type *type     = get_softfloat_type(n);
680         ir_mode *res_mode = get_type_mode(get_method_res_type(type, 0));
681
682         call         = new_rd_Call(dbgi, block, nomem, symconst, 1, in, type);
683         call_results = new_r_Proj(call, mode_T, pn_Call_T_result);
684         call_result  = new_r_Proj(call_results, res_mode, 0);
685
686         /* Check whether we need a Conv for the result. */
687         if (res_mode != mode)
688                 call_result = new_rd_Conv(dbgi, block, call_result, mode);
689
690         exchange(n, call_result);
691 }
692
693 /**
694  * Transforms a Div into the appropriate soft float function.
695  */
696 static void lower_Div(ir_node *n)
697 {
698         ir_node         *symconst;
699         ir_node         *block       = get_nodes_block(n);
700         ir_node         *call_result = NULL;
701         dbg_info        *dbgi        = get_irn_dbg_info(n);
702         ir_graph        *irg         = get_irn_irg(n);
703         ir_node         *left        = get_Div_left(n);
704         ir_mode         *mode        = get_Div_resmode(n);
705         ir_node         *right       = get_Div_right(n);
706         const ir_edge_t *edge;
707         const ir_edge_t *next;
708
709         if (! mode_is_float(mode))
710                 return;
711
712         symconst = create_softfloat_symconst(n, "div");
713
714         ir_node *call;
715         ir_node *call_results;
716         ir_node *in[2]    = {left, right};
717         ir_node *nomem    = get_irg_no_mem(irg);
718         ir_type *type     = get_softfloat_type(n);
719         ir_mode *res_mode = get_type_mode(get_method_res_type(type, 0));
720
721         call         = new_rd_Call(dbgi, block, nomem, symconst, 2, in, type);
722         call_results = new_r_Proj(call, mode_T, pn_Call_T_result);
723         call_result  = new_r_Proj(call_results, res_mode, 0);
724
725         set_irn_pinned(call, get_irn_pinned(n));
726
727         foreach_out_edge_safe(n, edge, next) {
728                 ir_node *proj = get_edge_src_irn(edge);
729                 if (! is_Proj(proj))
730                         continue;
731
732                 switch (get_Proj_proj(proj)) {
733                 case pn_Div_M:
734                         set_Proj_pred(proj, call);
735                         set_Proj_proj(proj, pn_Call_M);
736                         break;
737                 case pn_Div_X_regular:
738                         set_Proj_pred(proj, call);
739                         set_Proj_proj(proj, pn_Call_X_regular);
740                         break;
741                 case pn_Div_X_except:
742                         set_Proj_pred(proj, call);
743                         set_Proj_proj(proj, pn_Call_X_except);
744                         break;
745                 case pn_Div_res:
746                         exchange(proj, call_result);
747                         break;
748                 default:
749                         assert(0 && "unexpected Proj number");
750                 }
751         }
752
753 }
754
755 /**
756  * Adapts the resmode of a Div.
757  */
758 static void lower_Div_mode(ir_node *n)
759 {
760         ir_mode *res_mode         = get_Div_resmode(n);
761         ir_mode *lowered_res_mode = get_lowered_mode(res_mode);
762         ir_mode *mode             = get_irn_mode(n);
763         ir_mode *lowered_mode     = get_lowered_mode(mode);
764
765         set_irn_mode(n, lowered_mode);
766         set_Div_resmode(n, lowered_res_mode);
767 }
768
769 /**
770  * Adapts the ls_mode of a Load.
771  */
772 static void lower_Load(ir_node *n)
773 {
774         ir_mode *ls_mode         = get_Load_mode(n);
775         ir_mode *lowered_ls_mode = get_lowered_mode(ls_mode);
776         ir_mode *mode            = get_irn_mode(n);
777         ir_mode *lowered_mode    = get_lowered_mode(mode);
778
779         set_irn_mode(n, lowered_mode);
780         set_Load_mode(n, lowered_ls_mode);
781 }
782
783 /**
784  * Transforms a Minus into the appropriate soft float function.
785  */
786 static void lower_Minus(ir_node *n)
787 {
788         ir_node         *symconst;
789         ir_node         *block       = get_nodes_block(n);
790         ir_node         *call_result = NULL;
791         dbg_info        *dbgi        = get_irn_dbg_info(n);
792         ir_graph        *irg         = get_irn_irg(n);
793         ir_mode         *mode        = get_irn_mode(n);
794         ir_node         *op          = get_Minus_op(n);
795
796         if (! mode_is_float(mode))
797                 return;
798
799         symconst = create_softfloat_symconst(n, "neg");
800
801         ir_node *call;
802         ir_node *call_results;
803         ir_node *in[1]    = {op};
804         ir_node *nomem    = get_irg_no_mem(irg);
805         ir_type *type     = get_softfloat_type(n);
806         ir_mode *res_mode = get_type_mode(get_method_res_type(type, 0));
807
808         call         = new_rd_Call(dbgi, block, nomem, symconst, 1, in, type);
809         call_results = new_r_Proj(call, mode_T, pn_Call_T_result);
810         call_result  = new_r_Proj(call_results, res_mode, 0);
811
812         exchange(n, call_result);
813 }
814
815 /**
816  * Transforms a Mul into the appropriate soft float function.
817  */
818 static void lower_Mul(ir_node *n)
819 {
820         ir_node         *symconst;
821         ir_node         *block       = get_nodes_block(n);
822         ir_node         *call_result = NULL;
823         dbg_info        *dbgi        = get_irn_dbg_info(n);
824         ir_graph        *irg         = get_irn_irg(n);
825         ir_node         *left        = get_Mul_left(n);
826         ir_mode         *mode        = get_irn_mode(n);
827         ir_node         *right       = get_Mul_right(n);
828
829         if (! mode_is_float(mode))
830                 return;
831
832         symconst = create_softfloat_symconst(n, "mul");
833
834         ir_node *call;
835         ir_node *call_results;
836         ir_node *in[2]    = {left, right};
837         ir_node *nomem    = get_irg_no_mem(irg);
838         ir_type *type     = get_softfloat_type(n);
839         ir_mode *res_mode = get_type_mode(get_method_res_type(type, 0));
840
841         call         = new_rd_Call(dbgi, block, nomem, symconst, 2, in, type);
842         call_results = new_r_Proj(call, mode_T, pn_Call_T_result);
843         call_result  = new_r_Proj(call_results, res_mode, 0);
844
845         exchange(n, call_result);
846 }
847
848 /**
849  * Transforms a Sub into the appropriate soft float function.
850  */
851 static void lower_Sub(ir_node *n)
852 {
853         ir_node         *symconst;
854         ir_node         *block       = get_nodes_block(n);
855         ir_node         *call_result = NULL;
856         dbg_info        *dbgi        = get_irn_dbg_info(n);
857         ir_graph        *irg         = get_irn_irg(n);
858         ir_node         *left        = get_Sub_left(n);
859         ir_mode         *mode        = get_irn_mode(n);
860         ir_node         *right       = get_Sub_right(n);
861
862         if (! mode_is_float(mode))
863                 return;
864
865         symconst = create_softfloat_symconst(n, "sub");
866
867         ir_node *call;
868         ir_node *call_results;
869         ir_node *in[2]    = {left, right};
870         ir_node *nomem    = get_irg_no_mem(irg);
871         ir_type *type     = get_softfloat_type(n);
872         ir_mode *res_mode = get_type_mode(get_method_res_type(type, 0));
873
874         call         = new_rd_Call(dbgi, block, nomem, symconst, 2, in, type);
875         call_results = new_r_Proj(call, mode_T, pn_Call_T_result);
876         call_result  = new_r_Proj(call_results, res_mode, 0);
877
878         exchange(n, call_result);
879 }
880
881 /**
882  * Enter a lowering function into an ir_op.
883  */
884 static void ir_register_softloat_lower_function(ir_op *op, lower_softfloat_func func)
885 {
886         op->ops.generic = (op_func)func;
887 }
888
889 /*
890  * Initializes softfloat lowering.
891  */
892 static void ir_prepare_softfloat_lowering(void)
893 {
894         FIRM_DBG_REGISTER(dbg, "firm.lower.softfloat");
895
896         if (! lowered_type)
897                 lowered_type = pmap_create();
898
899         if (! binop_tp_d) {
900                 binop_tp_d = new_type_method(2, 1);
901                 set_method_param_type(binop_tp_d, 0, get_type_for_mode(mode_D));
902                 set_method_param_type(binop_tp_d, 1, get_type_for_mode(mode_D));
903                 set_method_res_type(binop_tp_d, 0, get_type_for_mode(mode_D));
904         }
905
906         if (! binop_tp_f) {
907                 binop_tp_f = new_type_method(2, 1);
908                 set_method_param_type(binop_tp_f, 0, get_type_for_mode(mode_F));
909                 set_method_param_type(binop_tp_f, 1, get_type_for_mode(mode_F));
910                 set_method_res_type(binop_tp_f, 0, get_type_for_mode(mode_F));
911         }
912
913         if (! cmp_tp_d) {
914                 cmp_tp_d = new_type_method(2, 1);
915                 set_method_param_type(cmp_tp_d, 0, get_type_for_mode(mode_D));
916                 set_method_param_type(cmp_tp_d, 1, get_type_for_mode(mode_D));
917                 set_method_res_type(cmp_tp_d, 0, get_type_for_mode(mode_Is));
918         }
919
920         if (! cmp_tp_f) {
921                 cmp_tp_f = new_type_method(2, 1);
922                 set_method_param_type(cmp_tp_f, 0, get_type_for_mode(mode_F));
923                 set_method_param_type(cmp_tp_f, 1, get_type_for_mode(mode_F));
924                 set_method_res_type(cmp_tp_f, 0, get_type_for_mode(mode_Is));
925         }
926
927         if (! unop_tp_d) {
928                 unop_tp_d = new_type_method(1, 1);
929                 set_method_param_type(unop_tp_d, 0, get_type_for_mode(mode_D));
930                 set_method_res_type(unop_tp_d, 0, get_type_for_mode(mode_D));
931         }
932
933         if (! unop_tp_f) {
934                 unop_tp_f = new_type_method(1, 1);
935                 set_method_param_type(unop_tp_f, 0, get_type_for_mode(mode_F));
936                 set_method_res_type(unop_tp_f, 0, get_type_for_mode(mode_F));
937         }
938
939         if (! unop_tp_d_f) {
940                 unop_tp_d_f = new_type_method(1, 1);
941                 set_method_param_type(unop_tp_d_f, 0, get_type_for_mode(mode_D));
942                 set_method_res_type(unop_tp_d_f, 0, get_type_for_mode(mode_F));
943         }
944
945         if (! unop_tp_d_is) {
946                 unop_tp_d_is = new_type_method(1, 1);
947                 set_method_param_type(unop_tp_d_is, 0, get_type_for_mode(mode_D));
948                 set_method_res_type(unop_tp_d_is, 0, get_type_for_mode(mode_Is));
949         }
950
951         if (! unop_tp_d_iu) {
952                 unop_tp_d_iu = new_type_method(1, 1);
953                 set_method_param_type(unop_tp_d_iu, 0, get_type_for_mode(mode_D));
954                 set_method_res_type(unop_tp_d_iu, 0, get_type_for_mode(mode_Iu));
955         }
956
957         if (! unop_tp_d_ls) {
958                 unop_tp_d_ls = new_type_method(1, 1);
959                 set_method_param_type(unop_tp_d_ls, 0, get_type_for_mode(mode_D));
960                 set_method_res_type(unop_tp_d_ls, 0, get_type_for_mode(mode_Ls));
961         }
962
963         if (! unop_tp_d_lu) {
964                 unop_tp_d_lu = new_type_method(1, 1);
965                 set_method_param_type(unop_tp_d_lu, 0, get_type_for_mode(mode_D));
966                 set_method_res_type(unop_tp_d_lu, 0, get_type_for_mode(mode_Lu));
967         }
968
969         if (! unop_tp_f_d) {
970                 unop_tp_f_d = new_type_method(1, 1);
971                 set_method_param_type(unop_tp_f_d, 0, get_type_for_mode(mode_F));
972                 set_method_res_type(unop_tp_f_d, 0, get_type_for_mode(mode_D));
973         }
974
975         if (! unop_tp_f_is) {
976                 unop_tp_f_is = new_type_method(1, 1);
977                 set_method_param_type(unop_tp_f_is, 0, get_type_for_mode(mode_F));
978                 set_method_res_type(unop_tp_f_is, 0, get_type_for_mode(mode_Is));
979         }
980
981         if (! unop_tp_f_iu) {
982                 unop_tp_f_iu = new_type_method(1, 1);
983                 set_method_param_type(unop_tp_f_iu, 0, get_type_for_mode(mode_F));
984                 set_method_res_type(unop_tp_f_iu, 0, get_type_for_mode(mode_Iu));
985         }
986
987         if (! unop_tp_f_ls) {
988                 unop_tp_f_ls = new_type_method(1, 1);
989                 set_method_param_type(unop_tp_f_ls, 0, get_type_for_mode(mode_F));
990                 set_method_res_type(unop_tp_f_ls, 0, get_type_for_mode(mode_Ls));
991         }
992
993         if (! unop_tp_f_lu) {
994                 unop_tp_f_lu = new_type_method(1, 1);
995                 set_method_param_type(unop_tp_f_lu, 0, get_type_for_mode(mode_F));
996                 set_method_res_type(unop_tp_f_lu, 0, get_type_for_mode(mode_Lu));
997         }
998
999         if (! unop_tp_is_d) {
1000                 unop_tp_is_d = new_type_method(1, 1);
1001                 set_method_param_type(unop_tp_is_d, 0, get_type_for_mode(mode_Is));
1002                 set_method_res_type(unop_tp_is_d, 0, get_type_for_mode(mode_D));
1003         }
1004
1005         if (! unop_tp_is_f) {
1006                 unop_tp_is_f = new_type_method(1, 1);
1007                 set_method_param_type(unop_tp_is_f, 0, get_type_for_mode(mode_Is));
1008                 set_method_res_type(unop_tp_is_f, 0, get_type_for_mode(mode_F));
1009         }
1010
1011         if (! unop_tp_iu_d) {
1012                 unop_tp_iu_d = new_type_method(1, 1);
1013                 set_method_param_type(unop_tp_iu_d, 0, get_type_for_mode(mode_Iu));
1014                 set_method_res_type(unop_tp_iu_d, 0, get_type_for_mode(mode_D));
1015         }
1016
1017         if (! unop_tp_iu_f) {
1018                 unop_tp_iu_f = new_type_method(1, 1);
1019                 set_method_param_type(unop_tp_iu_f, 0, get_type_for_mode(mode_Iu));
1020                 set_method_res_type(unop_tp_iu_f, 0, get_type_for_mode(mode_F));
1021         }
1022
1023         if (! unop_tp_ls_d) {
1024                 unop_tp_ls_d = new_type_method(1, 1);
1025                 set_method_param_type(unop_tp_ls_d, 0, get_type_for_mode(mode_Ls));
1026                 set_method_res_type(unop_tp_ls_d, 0, get_type_for_mode(mode_D));
1027         }
1028
1029         if (! unop_tp_ls_f) {
1030                 unop_tp_ls_f = new_type_method(1, 1);
1031                 set_method_param_type(unop_tp_ls_f, 0, get_type_for_mode(mode_Ls));
1032                 set_method_res_type(unop_tp_ls_f, 0, get_type_for_mode(mode_F));
1033         }
1034
1035         if (! unop_tp_lu_d) {
1036                 unop_tp_lu_d = new_type_method(1, 1);
1037                 set_method_param_type(unop_tp_lu_d, 0, get_type_for_mode(mode_Lu));
1038                 set_method_res_type(unop_tp_lu_d, 0, get_type_for_mode(mode_D));
1039         }
1040
1041         if (! unop_tp_lu_f) {
1042                 unop_tp_lu_f = new_type_method(1, 1);
1043                 set_method_param_type(unop_tp_lu_f, 0, get_type_for_mode(mode_Lu));
1044                 set_method_res_type(unop_tp_lu_f, 0, get_type_for_mode(mode_F));
1045         }
1046 }
1047
1048 /**
1049  * Callback to lower only the Mux nodes we created.
1050  */
1051 static int lower_mux_cb(ir_node *mux)
1052 {
1053         return ir_nodeset_contains(&created_mux_nodes, mux);
1054 }
1055
1056 void lower_floating_point(void)
1057 {
1058         size_t i;
1059         size_t n_irgs = get_irp_n_irgs();
1060
1061         FIRM_DBG_REGISTER(dbg, "firm.lower.softfloat");
1062
1063         ir_prepare_softfloat_lowering();
1064
1065         clear_irp_opcodes_generic_func();
1066         ir_register_softloat_lower_function(op_Add,   lower_Add);
1067         ir_register_softloat_lower_function(op_Cmp,   lower_Cmp);
1068         ir_register_softloat_lower_function(op_Conv,  lower_Conv);
1069         ir_register_softloat_lower_function(op_Div,   lower_Div);
1070         ir_register_softloat_lower_function(op_Minus, lower_Minus);
1071         ir_register_softloat_lower_function(op_Mul,   lower_Mul);
1072         ir_register_softloat_lower_function(op_Sub,   lower_Sub);
1073
1074         for (i = 0; i < n_irgs; ++i) {
1075                 ir_graph *irg = get_irp_irg(i);
1076
1077                 ir_nodeset_init(&created_mux_nodes);
1078
1079                 edges_assure(irg);
1080
1081                 irg_walk_graph(irg, NULL, lower_node, NULL);
1082
1083                 if (ir_nodeset_size(&created_mux_nodes) > 0)
1084                         lower_mux(irg, lower_mux_cb);
1085
1086                 ir_nodeset_destroy(&created_mux_nodes);
1087         }
1088
1089         clear_irp_opcodes_generic_func();
1090         ir_register_softloat_lower_function(op_Call,  lower_Call);
1091         ir_register_softloat_lower_function(op_Const, lower_Const);
1092         ir_register_softloat_lower_function(op_Div,   lower_Div_mode);
1093         ir_register_softloat_lower_function(op_Load,  lower_Load);
1094
1095         for (i = 0; i < n_irgs; ++i) {
1096                 ir_graph *irg          = get_irp_irg(i);
1097                 ir_entity *ent         = get_irg_entity(irg);
1098                 ir_type   *mtp         = get_entity_type(ent);
1099                 ir_type   *lowered_mtp = lower_method_type(mtp);
1100
1101                 if (lowered_mtp != mtp)
1102                         set_entity_type(ent, lowered_mtp);
1103
1104                 irg_walk_graph(irg, NULL, lower_mode, NULL);
1105         }
1106 }