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