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