Consistently use new function to create compilerlib function entities.
[libfirm] / ir / be / ia32 / ia32_intrinsics.c
1 /*
2  * Copyright (C) 1995-2008 University of Karlsruhe.  All right reserved.
3  *
4  * This file is part of libFirm.
5  *
6  * This file may be distributed and/or modified under the terms of the
7  * GNU General Public License version 2 as published by the Free Software
8  * Foundation and appearing in the file LICENSE.GPL included in the
9  * packaging of this file.
10  *
11  * Licensees holding valid libFirm Professional Edition licenses may use
12  * this file in accordance with the libFirm Commercial License.
13  * Agreement provided with the Software.
14  *
15  * This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE
16  * WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17  * PURPOSE.
18  */
19
20 /**
21  * @file
22  * @brief       This file implements the mapping of 64Bit intrinsic
23  *              functions to code or library calls.
24  * @author      Michael Beck
25  * @version     $Id$
26  */
27 #include "config.h"
28
29 #include "iredges.h"
30 #include "irgmod.h"
31 #include "irop.h"
32 #include "irnode_t.h"
33 #include "ircons.h"
34 #include "irprog_t.h"
35 #include "iroptimize.h"
36 #include "lower_dw.h"
37 #include "array.h"
38 #include "error.h"
39
40 #include "ia32_new_nodes.h"
41 #include "bearch_ia32_t.h"
42 #include "gen_ia32_regalloc_if.h"
43 #include "begnuas.h"
44
45 /** The array of all intrinsics that must be mapped. */
46 static i_record *intrinsics;
47
48 /** An array to cache all entities. */
49 static ir_entity *i_ents[iro_Last + 1];
50
51 /*
52  * Maps all intrinsic calls that the backend support
53  * and map all instructions the backend did not support
54  * to runtime calls.
55  */
56 void ia32_handle_intrinsics(void)
57 {
58         if (intrinsics && ARR_LEN(intrinsics) > 0) {
59                 lower_intrinsics(intrinsics, ARR_LEN(intrinsics), /*part_block_used=*/1);
60         }
61 }
62
63 #define BINOP_Left_Low   0
64 #define BINOP_Left_High  1
65 #define BINOP_Right_Low  2
66 #define BINOP_Right_High 3
67
68 /**
69  * Reroute edges from the pn_Call_T_result proj of a call.
70  *
71  * @param resproj  the pn_Call_T_result Proj
72  * @param l_res    the lower 32 bit result
73  * @param h_res    the upper 32 bit result or NULL
74  */
75 static void reroute_result(ir_node *resproj, ir_node *l_res, ir_node *h_res)
76 {
77         const ir_edge_t *edge, *next;
78
79         foreach_out_edge_safe(resproj, edge, next) {
80                 ir_node *proj = get_edge_src_irn(edge);
81                 long    pn    = get_Proj_proj(proj);
82
83                 if (pn == 0) {
84                         edges_reroute(proj, l_res);
85                 } else if (pn == 1 && h_res != NULL) {
86                         edges_reroute(proj, h_res);
87                 } else {
88                         panic("Unsupported Result-Proj from Call found");
89                 }
90         }
91 }
92
93 /**
94  * Replace a call be a tuple of l_res, h_res.
95  *
96  * @param call   the call node to replace
97  * @param l_res  the lower 32 bit result
98  * @param h_res  the upper 32 bit result or NULL
99  * @param irg    the graph to replace on
100  * @param block  the block to replace on (always the call block)
101  */
102 static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block)
103 {
104         ir_node *jmp, *res, *in[2];
105         ir_node *nomem = get_irg_no_mem(irg);
106         int     old_cse;
107
108         if (edges_activated(irg)) {
109                 /* use rerouting to prevent some warning in the backend */
110                 const ir_edge_t *edge, *next;
111
112                 foreach_out_edge_safe(call, edge, next) {
113                         ir_node *proj = get_edge_src_irn(edge);
114                         pn_Call pn    = (pn_Call)get_Proj_proj(proj);
115
116                         switch (pn) {
117                         case pn_Call_X_regular:
118                                 /* Beware:
119                                  * We do not check here if this call really has exception and regular Proj's.
120                                  * new_r_Jmp might than be CSEd with the real exit jmp and then bad things happen
121                                  * (in movgen.c from 186.crafty for example).
122                                  * So be sure the newly created Jmp cannot CSE.
123                                  */
124                                 old_cse = get_opt_cse();
125                                 set_opt_cse(0);
126                                 jmp = new_r_Jmp(block);
127                                 set_opt_cse(old_cse);
128                                 edges_reroute(proj, jmp);
129                                 break;
130
131                         case pn_Call_X_except:
132                                 /* should not happen here */
133                                 edges_reroute(proj, new_r_Bad(irg, mode_X));
134                                 break;
135                         case pn_Call_M:
136                                 /* should not happen here */
137                                 edges_reroute(proj, nomem);
138                                 break;
139                         case pn_Call_T_result:
140                                 reroute_result(proj, l_res, h_res);
141                                 break;
142                         default:
143                                 panic("Wrong Proj from Call");
144                         }
145                         kill_node(proj);
146                 }
147                 kill_node(call);
148         } else {
149                 /* no edges, build Tuple */
150                 if (h_res == NULL)
151                         res = l_res;
152                 else {
153                         in[0] = l_res;
154                         in[1] = h_res;
155                         res = new_r_Tuple(block, 2, in);
156                 }
157
158                 /*
159                  * Beware:
160                  * We do not check here if this call really has exception and regular Proj's.
161                  * new_r_Jmp might than be CSEd with the real exit jmp and then bad things happen
162                  * (in movgen.c from 186.crafty for example).
163                  * So be sure the newly created Jmp cannot CSE.
164                  */
165                 old_cse = get_opt_cse();
166                 set_opt_cse(0);
167                 jmp = new_r_Jmp(block);
168                 set_opt_cse(old_cse);
169
170                 turn_into_tuple(call, pn_Call_max+1);
171                 set_Tuple_pred(call, pn_Call_M,         nomem);
172                 set_Tuple_pred(call, pn_Call_X_regular, jmp);
173                 set_Tuple_pred(call, pn_Call_X_except,  new_r_Bad(irg, mode_X));
174                 set_Tuple_pred(call, pn_Call_T_result,  res);
175         }
176 }
177
178 /**
179  * Map an Add (a_l, a_h, b_l, b_h)
180  */
181 static int map_Add(ir_node *call, void *ctx)
182 {
183         dbg_info *dbg        = get_irn_dbg_info(call);
184         ir_node  *block      = get_nodes_block(call);
185         ir_node  **params    = get_Call_param_arr(call);
186         ir_type  *method     = get_Call_type(call);
187         ir_node  *a_l        = params[BINOP_Left_Low];
188         ir_node  *a_h        = params[BINOP_Left_High];
189         ir_node  *b_l        = params[BINOP_Right_Low];
190         ir_node  *b_h        = params[BINOP_Right_High];
191         ir_mode  *l_mode     = get_type_mode(get_method_res_type(method, 0));
192         ir_mode  *h_mode     = get_type_mode(get_method_res_type(method, 1));
193         ir_mode  *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
194         ir_node  *add_low, *add_high, *flags;
195         ir_node  *l_res, *h_res;
196         (void) ctx;
197
198         /* l_res = a_l + b_l */
199         /* h_res = a_h + b_h + carry */
200
201         add_low  = new_bd_ia32_l_Add(dbg, block, a_l, b_l, mode_T);
202         flags    = new_r_Proj(add_low, mode_flags, pn_ia32_flags);
203         add_high = new_bd_ia32_l_Adc(dbg, block, a_h, b_h, flags, h_mode);
204
205         l_res = new_r_Proj(add_low, l_mode, pn_ia32_res);
206         h_res = add_high;
207
208         resolve_call(call, l_res, h_res, current_ir_graph, block);
209         return 1;
210 }
211
212 /**
213  * Map a Sub (a_l, a_h, b_l, b_h)
214  */
215 static int map_Sub(ir_node *call, void *ctx)
216 {
217         dbg_info *dbg        = get_irn_dbg_info(call);
218         ir_node  *block      = get_nodes_block(call);
219         ir_node  **params    = get_Call_param_arr(call);
220         ir_type  *method     = get_Call_type(call);
221         ir_node  *a_l        = params[BINOP_Left_Low];
222         ir_node  *a_h        = params[BINOP_Left_High];
223         ir_node  *b_l        = params[BINOP_Right_Low];
224         ir_node  *b_h        = params[BINOP_Right_High];
225         ir_mode  *l_mode     = get_type_mode(get_method_res_type(method, 0));
226         ir_mode  *h_mode     = get_type_mode(get_method_res_type(method, 1));
227         ir_mode  *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
228         ir_node  *sub_low, *sub_high, *flags;
229         ir_node  *l_res, *h_res;
230         (void) ctx;
231
232         /* l_res = a_l - b_l */
233         /* h_res = a_h - b_h - carry */
234
235         sub_low  = new_bd_ia32_l_Sub(dbg, block, a_l, b_l, mode_T);
236         flags    = new_r_Proj(sub_low, mode_flags, pn_ia32_flags);
237         sub_high = new_bd_ia32_l_Sbb(dbg, block, a_h, b_h, flags, h_mode);
238
239         l_res = new_r_Proj(sub_low, l_mode, pn_ia32_res);
240         h_res = sub_high;
241
242         resolve_call(call, l_res, h_res, current_ir_graph, block);
243         return 1;
244 }
245
246 /**
247  * Checks where node high is a sign extension of low.
248  */
249 static int is_sign_extend(ir_node *low, ir_node *high)
250 {
251         if (is_Shrs(high)) {
252                 ir_node   *high_l;
253                 ir_node   *high_r;
254                 ir_tarval *shift_count;
255
256                 high_r = get_Shrs_right(high);
257                 if (!is_Const(high_r)) return 0;
258
259                 shift_count = get_Const_tarval(high_r);
260                 if (!tarval_is_long(shift_count))       return 0;
261                 if (get_tarval_long(shift_count) != 31) return 0;
262
263                 high_l = get_Shrs_left(high);
264
265                 if (is_Conv(low)    && get_Conv_op(low)    == high_l) return 1;
266                 if (is_Conv(high_l) && get_Conv_op(high_l) == low)    return 1;
267         } else if (is_Const(low) && is_Const(high)) {
268                 ir_tarval *tl = get_Const_tarval(low);
269                 ir_tarval *th = get_Const_tarval(high);
270
271                 if (tarval_is_long(th) && tarval_is_long(tl)) {
272                         long l = get_tarval_long(tl);
273                         long h = get_tarval_long(th);
274
275                         return (h == 0  && l >= 0) || (h == -1 && l <  0);
276                 }
277         }
278
279         return 0;
280 }
281
282 /**
283  * Map a Mul (a_l, a_h, b_l, b_h)
284  */
285 static int map_Mul(ir_node *call, void *ctx)
286 {
287         dbg_info *dbg     = get_irn_dbg_info(call);
288         ir_node  *block   = get_nodes_block(call);
289         ir_node  **params = get_Call_param_arr(call);
290         ir_type  *method  = get_Call_type(call);
291         ir_node  *a_l     = params[BINOP_Left_Low];
292         ir_node  *a_h     = params[BINOP_Left_High];
293         ir_node  *b_l     = params[BINOP_Right_Low];
294         ir_node  *b_h     = params[BINOP_Right_High];
295         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
296         ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
297         ir_node  *l_res, *h_res, *mul, *pEDX, *add;
298         (void) ctx;
299
300         /*
301                 EDX:EAX = a_l * b_l
302                 l_res   = EAX
303
304                 t1 = b_l * a_h
305                 t2 = t1 + EDX
306                 t3 = a_l * b_h
307                 h_res = t2 + t3
308         */
309
310         /* handle the often used case of 32x32=64 mul */
311         if (is_sign_extend(a_l, a_h) && is_sign_extend(b_l, b_h)) {
312                 mul   = new_bd_ia32_l_IMul(dbg, block, a_l, b_l);
313                 h_res = new_rd_Proj(dbg, mul, h_mode, pn_ia32_l_IMul_res_high);
314                 l_res = new_rd_Proj(dbg, mul, l_mode, pn_ia32_l_IMul_res_low);
315         } else {
316                 /* note that zero extension is handled hare efficiently */
317                 mul   = new_bd_ia32_l_Mul(dbg, block, a_l, b_l);
318                 pEDX  = new_rd_Proj(dbg, mul, h_mode, pn_ia32_l_Mul_res_high);
319                 l_res = new_rd_Proj(dbg, mul, l_mode, pn_ia32_l_Mul_res_low);
320
321                 b_l   = new_rd_Conv(dbg, block, b_l, h_mode);
322                 mul   = new_rd_Mul( dbg, block, a_h, b_l, h_mode);
323                 add   = new_rd_Add( dbg, block, mul, pEDX, h_mode);
324                 a_l   = new_rd_Conv(dbg, block, a_l, h_mode);
325                 mul   = new_rd_Mul( dbg, block, a_l, b_h, h_mode);
326                 h_res = new_rd_Add( dbg, block, add, mul, h_mode);
327         }
328         resolve_call(call, l_res, h_res, current_ir_graph, block);
329
330         return 1;
331 }
332
333 /**
334  * Map a Minus (a_l, a_h)
335  */
336 static int map_Minus(ir_node *call, void *ctx)
337 {
338         dbg_info *dbg     = get_irn_dbg_info(call);
339         ir_node  *block   = get_nodes_block(call);
340         ir_node  **params = get_Call_param_arr(call);
341         ir_type  *method  = get_Call_type(call);
342         ir_node  *a_l     = params[BINOP_Left_Low];
343         ir_node  *a_h     = params[BINOP_Left_High];
344         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
345         ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
346         ir_node  *l_res, *h_res, *res;
347         (void) ctx;
348
349         res   = new_bd_ia32_Minus64Bit(dbg, block, a_l, a_h);
350         l_res = new_r_Proj(res, l_mode, pn_ia32_Minus64Bit_low_res);
351         h_res = new_r_Proj(res, h_mode, pn_ia32_Minus64Bit_high_res);
352
353         resolve_call(call, l_res, h_res, current_ir_graph, block);
354
355         return 1;
356 }
357
358 #if 0
359 /**
360  * Map a Abs (a_l, a_h)
361  */
362 static int map_Abs(ir_node *call, void *ctx)
363 {
364         dbg_info *dbg        = get_irn_dbg_info(call);
365         ir_node  *block      = get_nodes_block(call);
366         ir_node  **params    = get_Call_param_arr(call);
367         ir_type  *method     = get_Call_type(call);
368         ir_node  *a_l        = params[BINOP_Left_Low];
369         ir_node  *a_h        = params[BINOP_Left_High];
370         ir_mode  *l_mode     = get_type_mode(get_method_res_type(method, 0));
371         ir_mode  *h_mode     = get_type_mode(get_method_res_type(method, 1));
372         ir_mode  *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
373         ir_node  *l_res, *h_res, *sign, *sub_l, *sub_h;
374         ir_node  *sign_l;
375         ir_node  *l_sub;
376         ir_node  *flags;
377         (void) ctx;
378
379         /*
380                 Code inspired by gcc output :) (although gcc doubles the
381                 operation for t1 as t2 and uses t1 for operations with low part
382                 and t2 for operations with high part which is actually unnecessary
383                 because t1 and t2 represent the same value)
384
385                 t1    = SHRS a_h, 31
386                 t2    = a_l ^ t1
387                 t3    = a_h ^ t1
388                 l_res = t2 - t1
389                 h_res = t3 - t1 - carry
390
391         */
392
393         /* TODO: give a hint to the backend somehow to not create a cltd here... */
394         sign   = new_rd_Shrs(dbg, block, a_h, new_r_Const_long(irg, l_mode, 31), h_mode);
395         sign_l = new_rd_Conv(dbg, block, sign, l_mode);
396         sub_l  = new_rd_Eor(dbg, block, a_l, sign_l, l_mode);
397         sub_h  = new_rd_Eor(dbg, block, a_h, sign,   h_mode);
398
399         l_sub  = new_bd_ia32_l_Sub(dbg, block, sub_l, sign_l, mode_T);
400         l_res  = new_r_Proj(l_sub, l_mode,     pn_ia32_res);
401         flags  = new_r_Proj(l_sub, mode_flags, pn_ia32_flags);
402         h_res  = new_bd_ia32_l_Sbb(dbg, block, sub_h, sign, flags, h_mode);
403
404         resolve_call(call, l_res, h_res, current_ir_graph, block);
405
406         return 1;
407 }
408 #endif
409
410 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
411
412 /**
413  * Maps a Div. Change into a library call.
414  */
415 static int map_Div(ir_node *call, void *ctx)
416 {
417         ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
418         ir_type   *method    = get_Call_type(call);
419         ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
420         ir_node   *ptr;
421         ir_entity *ent;
422         ir_graph  *irg = get_irn_irg(call);
423         symconst_symbol sym;
424
425         if (mode_is_signed(h_mode)) {
426                 /* 64bit signed Division */
427                 ent = env->divdi3;
428                 if (ent == NULL) {
429                         /* create library entity */
430                         ident *id = ID("__divdi3");
431                         ent = env->divdi3 = create_compilerlib_entity(id, method);
432                 }
433         } else {
434                 /* 64bit unsigned Division */
435                 ent = env->udivdi3;
436                 if (ent == NULL) {
437                         /* create library entity */
438                         ident *id = ID("__udivdi3");
439                         ent = env->udivdi3 = create_compilerlib_entity(id, method);
440                 }
441         }
442
443         ptr = get_Call_ptr(call);
444         sym.entity_p = ent;
445         ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
446         set_Call_ptr(call, ptr);
447
448         return 1;
449 }
450
451 /**
452  * Maps a Mod. Change into a library call
453  */
454 static int map_Mod(ir_node *call, void *ctx)
455 {
456         ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
457         ir_type   *method    = get_Call_type(call);
458         ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
459         ir_node   *ptr;
460         ir_entity *ent;
461         ir_graph  *irg = get_irn_irg(call);
462         symconst_symbol sym;
463
464         if (mode_is_signed(h_mode)) {
465                 /* 64bit signed Modulo */
466                 ent = env->moddi3;
467                 if (ent == NULL) {
468                         /* create library entity */
469                         ident *id = ID("__moddi3");
470                         ent = env->moddi3 = create_compilerlib_entity(id, method);
471                 }
472         } else {
473                 /* 64bit signed Modulo */
474                 ent = env->umoddi3;
475                 if (ent == NULL) {
476                         /* create library entity */
477                         ident *id = ID("__umoddi3");
478                         ent = env->umoddi3 = create_compilerlib_entity(id, method);
479                 }
480         }
481
482         ptr = get_Call_ptr(call);
483         sym.entity_p = ent;
484         ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
485         set_Call_ptr(call, ptr);
486
487         return 1;
488 }
489
490 /**
491  * Maps a Conv.
492  */
493 static int map_Conv(ir_node *call, void *ctx)
494 {
495         ir_graph  *irg     = current_ir_graph;
496         dbg_info  *dbg     = get_irn_dbg_info(call);
497         ir_node   *block   = get_nodes_block(call);
498         ir_node   **params = get_Call_param_arr(call);
499         ir_type   *method  = get_Call_type(call);
500         int       n        = get_Call_n_params(call);
501         ir_node   *l_res, *h_res;
502         (void) ctx;
503
504         if (n == 1) {
505                 ir_node *float_to_ll;
506
507                 /* We have a Conv float -> long long here */
508                 ir_node *a_f        = params[0];
509                 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
510                 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
511
512                 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
513
514                 if (mode_is_signed(h_res_mode)) {
515                         /* convert from float to signed 64bit */
516                         float_to_ll = new_bd_ia32_l_FloattoLL(dbg, block, a_f);
517
518                         l_res = new_r_Proj(float_to_ll, l_res_mode,
519                                            pn_ia32_l_FloattoLL_res_low);
520                         h_res = new_r_Proj(float_to_ll, h_res_mode,
521                                                            pn_ia32_l_FloattoLL_res_high);
522                 } else {
523                         /* Convert from float to unsigned 64bit. */
524                         ir_mode   *flt_mode = get_irn_mode(a_f);
525                         ir_tarval *flt_tv   = new_tarval_from_str("9223372036854775808", 19, flt_mode);
526                         ir_node   *flt_corr = new_r_Const(irg, flt_tv);
527                         ir_node   *lower_blk = block;
528                         ir_node   *upper_blk;
529                         ir_node   *cmp, *proj, *cond, *blk, *int_phi, *flt_phi;
530                         ir_node   *in[2];
531
532                         part_block(call);
533                         upper_blk = get_nodes_block(call);
534
535                         cmp   = new_rd_Cmp(dbg, upper_blk, a_f, flt_corr, ir_relation_less);
536                         cond  = new_rd_Cond(dbg, upper_blk, cmp);
537                         in[0] = new_r_Proj(cond, mode_X, pn_Cond_true);
538                         in[1] = new_r_Proj(cond, mode_X, pn_Cond_false);
539                         blk   = new_r_Block(irg, 1, &in[1]);
540                         in[1] = new_r_Jmp(blk);
541
542                         set_irn_in(lower_blk, 2, in);
543
544                         /* create to Phis */
545                         in[0] = new_r_Const(irg, get_mode_null(h_res_mode));
546                         in[1] = new_r_Const_long(irg, h_res_mode, 0x80000000);
547
548                         int_phi = new_r_Phi(lower_blk, 2, in, h_res_mode);
549
550                         in[0] = a_f;
551                         in[1] = new_rd_Sub(dbg, upper_blk, a_f, flt_corr, flt_mode);
552
553                         flt_phi = new_r_Phi(lower_blk, 2, in, flt_mode);
554
555                         /* fix Phi links for next part_block() */
556                         set_Block_phis(lower_blk, int_phi);
557                         set_Phi_next(int_phi, flt_phi);
558                         set_Phi_next(flt_phi, NULL);
559
560                         float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);
561
562                         l_res = new_r_Proj(float_to_ll, l_res_mode,
563                                                            pn_ia32_l_FloattoLL_res_low);
564                         h_res = new_r_Proj(float_to_ll, h_res_mode,
565                                                            pn_ia32_l_FloattoLL_res_high);
566
567                         h_res = new_rd_Add(dbg, lower_blk, h_res, int_phi, h_res_mode);
568
569                         /* move the call and its Proj's to the lower block */
570                         set_nodes_block(call, lower_blk);
571
572                         for (proj = (ir_node*)get_irn_link(call); proj != NULL;
573                              proj = (ir_node*)get_irn_link(proj)) {
574                                 set_nodes_block(proj, lower_blk);
575                         }
576                         block = lower_blk;
577                 }
578                 /* lower the call */
579                 resolve_call(call, l_res, h_res, irg, block);
580         } else if (n == 2) {
581                 ir_node *ll_to_float;
582
583                 /* We have a Conv long long -> float here */
584                 ir_node *a_l       = params[BINOP_Left_Low];
585                 ir_node *a_h       = params[BINOP_Left_High];
586                 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
587
588                 assert(! mode_is_float(get_irn_mode(a_l))
589                                 && ! mode_is_float(get_irn_mode(a_h)));
590
591                 ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
592
593                 /* lower the call */
594                 resolve_call(call, ll_to_float, NULL, irg, block);
595         } else {
596                 panic("unexpected Conv call %+F", call);
597         }
598
599         return 1;
600 }
601
602 /* Ia32 implementation of intrinsic mapping. */
603 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
604                                      const ir_mode *imode, const ir_mode *omode,
605                                      void *context)
606 {
607         i_record      elt;
608         ir_entity     **ent = NULL;
609         i_mapper_func mapper;
610
611         if (! intrinsics)
612                 intrinsics = NEW_ARR_F(i_record, 0);
613
614         switch (get_op_code(op)) {
615         case iro_Add:
616                 ent    = &i_ents[iro_Add];
617                 mapper = map_Add;
618                 break;
619         case iro_Sub:
620                 ent    = &i_ents[iro_Sub];
621                 mapper = map_Sub;
622                 break;
623         case iro_Mul:
624                 ent    = &i_ents[iro_Mul];
625                 mapper = map_Mul;
626                 break;
627         case iro_Minus:
628                 ent    = &i_ents[iro_Minus];
629                 mapper = map_Minus;
630                 break;
631         case iro_Div:
632                 ent    = &i_ents[iro_Div];
633                 mapper = map_Div;
634                 break;
635         case iro_Mod:
636                 ent    = &i_ents[iro_Mod];
637                 mapper = map_Mod;
638                 break;
639         case iro_Conv:
640                 ent    = &i_ents[iro_Conv];
641                 mapper = map_Conv;
642                 break;
643         default:
644                 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
645                 return def_create_intrinsic_fkt(method, op, imode, omode, context);
646         }
647
648         if (ent && ! *ent) {
649 #define IDENT(s)  new_id_from_chars(s, sizeof(s)-1)
650
651                 ident *id = id_mangle(IDENT("L"), get_op_ident(op));
652                 *ent = new_entity(get_glob_type(), id, method);
653                 set_entity_visibility(*ent, ir_visibility_private);
654         }
655
656         elt.i_call.kind     = INTRINSIC_CALL;
657         elt.i_call.i_ent    = *ent;
658         elt.i_call.i_mapper = mapper;
659         elt.i_call.ctx      = context;
660         elt.i_call.link     = NULL;
661
662         ARR_APP1(i_record, intrinsics, elt);
663         return *ent;
664 }