fix sse/x87 fixup code added at wrong places
[libfirm] / ir / be / ia32 / ia32_intrinsics.c
1 /*
2  * Copyright (C) 1995-2007 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 #ifdef HAVE_CONFIG_H
28 #include "config.h"
29 #endif
30
31 #include "irgmod.h"
32 #include "irop.h"
33 #include "irnode_t.h"
34 #include "ircons.h"
35 #include "irprog_t.h"
36 #include "lowering.h"
37 #include "array.h"
38
39 #include "ia32_new_nodes.h"
40 #include "bearch_ia32_t.h"
41 #include "gen_ia32_regalloc_if.h"
42
43 /** The array of all intrinsics that must be mapped. */
44 static i_record *intrinsics;
45
46 /** An array to cache all entities */
47 static ir_entity *i_ents[iro_MaxOpcode];
48
49 /*
50  * Maps all intrinsic calls that the backend support
51  * and map all instructions the backend did not support
52  * to runtime calls.
53  */
54 void ia32_handle_intrinsics(void) {
55         if (intrinsics && ARR_LEN(intrinsics) > 0) {
56                 lower_intrinsics(intrinsics, ARR_LEN(intrinsics), /*part_block_used=*/1);
57         }
58 }
59
60 #define BINOP_Left_Low   0
61 #define BINOP_Left_High  1
62 #define BINOP_Right_Low  2
63 #define BINOP_Right_High 3
64
65 /**
66  * Replace a call be a tuple of l_res, h_res.
67  */
68 static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block) {
69         ir_node *res, *in[2];
70
71         in[0] = l_res;
72         in[1] = h_res;
73         res = new_r_Tuple(irg, block, h_res == NULL ? 1 : 2, in);
74
75         turn_into_tuple(call, pn_Call_max);
76         set_Tuple_pred(call, pn_Call_M_regular,        get_irg_no_mem(irg));
77         set_Tuple_pred(call, pn_Call_X_regular,        new_r_Jmp(irg, block));
78         set_Tuple_pred(call, pn_Call_X_except,         get_irg_bad(irg));
79         set_Tuple_pred(call, pn_Call_T_result,         res);
80         set_Tuple_pred(call, pn_Call_M_except,         get_irg_no_mem(irg));
81         set_Tuple_pred(call, pn_Call_P_value_res_base, get_irg_bad(irg));
82 }
83
84 /**
85  * Map an Add (a_l, a_h, b_l, b_h)
86  */
87 static int map_Add(ir_node *call, void *ctx) {
88         ir_graph *irg     = current_ir_graph;
89         dbg_info *dbg     = get_irn_dbg_info(call);
90         ir_node  *block   = get_nodes_block(call);
91         ir_node  **params = get_Call_param_arr(call);
92         ir_type  *method  = get_Call_type(call);
93         ir_node  *a_l     = params[BINOP_Left_Low];
94         ir_node  *a_h     = params[BINOP_Left_High];
95         ir_node  *b_l     = params[BINOP_Right_Low];
96         ir_node  *b_h     = params[BINOP_Right_High];
97         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
98         ir_node  *l_res, *h_res, *add;
99         (void) ctx;
100
101         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
102
103         /* l_res = a_l + b_l */
104         /* h_res = a_h + b_h + carry */
105
106         add   = new_rd_ia32_Add64Bit(dbg, irg, block, a_l, a_h, b_l, b_h);
107         l_res = new_r_Proj(irg, block, add, l_mode, pn_ia32_Add64Bit_low_res);
108         h_res = new_r_Proj(irg, block, add, l_mode, pn_ia32_Add64Bit_high_res);
109
110         resolve_call(call, l_res, h_res, irg, block);
111         return 1;
112 }
113
114 /**
115  * Map a Sub (a_l, a_h, b_l, b_h)
116  */
117 static int map_Sub(ir_node *call, void *ctx) {
118         ir_graph *irg     = current_ir_graph;
119         dbg_info *dbg     = get_irn_dbg_info(call);
120         ir_node  *block   = get_nodes_block(call);
121         ir_node  **params = get_Call_param_arr(call);
122         ir_type  *method  = get_Call_type(call);
123         ir_node  *a_l     = params[BINOP_Left_Low];
124         ir_node  *a_h     = params[BINOP_Left_High];
125         ir_node  *b_l     = params[BINOP_Right_Low];
126         ir_node  *b_h     = params[BINOP_Right_High];
127         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
128         ir_node  *l_res, *h_res, *res;
129         (void) ctx;
130
131         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
132
133         /* l_res = a_l - b_l */
134         /* h_res = a_h - b_h - carry */
135
136         res   = new_rd_ia32_Sub64Bit(dbg, irg, block, a_l, a_h, b_l, b_h);
137         l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
138         h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);
139
140         resolve_call(call, l_res, h_res, irg, block);
141         return 1;
142 }
143
144 /**
145  * Map a Shl (a_l, a_h, count)
146  */
147 static int map_Shl(ir_node *call, void *ctx) {
148         ir_graph *irg     = current_ir_graph;
149         dbg_info *dbg     = get_irn_dbg_info(call);
150         ir_node  *block   = get_nodes_block(call);
151         ir_node  **params = get_Call_param_arr(call);
152         ir_type  *method  = get_Call_type(call);
153         ir_node  *a_l     = params[BINOP_Left_Low];
154         ir_node  *a_h     = params[BINOP_Left_High];
155         ir_node  *cnt     = params[BINOP_Right_Low];
156         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
157         ir_mode  *c_mode;
158         ir_node  *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
159         (void) ctx;
160
161         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
162
163         if (is_Const(cnt)) {
164                 /* the shift count is a const, create better code */
165                 tarval *tv = get_Const_tarval(cnt);
166
167                 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
168                         /* simplest case: shift only the lower bits. Note that there is no
169                            need to reduce the constant here, this is done by the hardware.  */
170                         h_res = new_rd_Shl(dbg, irg, block, a_l, cnt, l_mode);
171                         l_res = new_rd_Const(dbg, irg, block, l_mode, get_mode_null(l_mode));
172
173                         resolve_call(call, l_res, h_res, irg, block);
174                         return 1;
175                 }
176         }
177
178         part_block(call);
179         upper = get_nodes_block(call);
180
181         /* h_res = SHLD a_h, a_l, cnt */
182         h1 = new_rd_ia32_l_ShlD(dbg, irg, upper, a_h, a_l, cnt, l_mode);
183
184         /* l_res = SHL a_l, cnt */
185         l1 = new_rd_ia32_l_ShlDep(dbg, irg, upper, a_l, cnt, h1, l_mode);
186
187         c_mode = get_irn_mode(cnt);
188         irn    = new_r_Const_long(irg, upper, c_mode, 32);
189         irn    = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
190         irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
191         irn    = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
192         cond   = new_rd_Cond(dbg, irg, upper, irn);
193
194         in[0]  = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
195         in[1]  = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
196
197         /* the block for cnt >= 32 */
198         n_block = new_rd_Block(dbg, irg, 1, &in[1]);
199         h2      = l1;
200         l2      = new_r_Const(irg, n_block, l_mode, get_mode_null(l_mode));
201         in[1]   = new_r_Jmp(irg, n_block);
202
203         set_irn_in(block, 2, in);
204
205         in[0] = l1;
206         in[1] = l2;
207         l_res = new_r_Phi(irg, block, 2, in, l_mode);
208         set_irn_link(block, l_res);
209
210         in[0] = h1;
211         in[1] = h2;
212         h_res = new_r_Phi(irg, block, 2, in, l_mode);
213         set_irn_link(l_res, h_res);
214         set_irn_link(h_res, NULL);
215
216         /* move it down */
217         set_nodes_block(call, block);
218         for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
219                 set_nodes_block(irn, block);
220
221         resolve_call(call, l_res, h_res, irg, block);
222         return 1;
223 }
224
225 /**
226  * Map a Shr (a_l, a_h, count)
227  */
228 static int map_Shr(ir_node *call, void *ctx) {
229         ir_graph *irg     = current_ir_graph;
230         dbg_info *dbg     = get_irn_dbg_info(call);
231         ir_node  *block   = get_nodes_block(call);
232         ir_node  **params = get_Call_param_arr(call);
233         ir_type  *method  = get_Call_type(call);
234         ir_node  *a_l     = params[BINOP_Left_Low];
235         ir_node  *a_h     = params[BINOP_Left_High];
236         ir_node  *cnt     = params[BINOP_Right_Low];
237         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
238         ir_mode  *c_mode;
239         ir_node  *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
240         (void) ctx;
241
242         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
243
244         if (is_Const(cnt)) {
245                 /* the shift count is a const, create better code */
246                 tarval *tv = get_Const_tarval(cnt);
247
248                 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
249                         /* simplest case: shift only the higher bits. Note that there is no
250                            need to reduce the constant here, this is done by the hardware.  */
251                         h_res = new_rd_Const(dbg, irg, block, l_mode, get_mode_null(l_mode));
252                         l_res = new_rd_Shr(dbg, irg, block, a_h, cnt, l_mode);
253
254                         resolve_call(call, l_res, h_res, irg, block);
255                         return 1;
256                 }
257         }
258
259         part_block(call);
260         upper = get_nodes_block(call);
261
262         /* l_res = SHRD a_h:a_l, cnt */
263         l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
264
265         /* h_res = SHR a_h, cnt */
266         h1 = new_rd_ia32_l_ShrDep(dbg, irg, upper, a_h, cnt, l1, l_mode);
267
268         c_mode = get_irn_mode(cnt);
269         irn    = new_r_Const_long(irg, upper, c_mode, 32);
270         irn    = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
271         irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
272         irn    = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
273         cond   = new_rd_Cond(dbg, irg, upper, irn);
274
275         in[0]  = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
276         in[1]  = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
277
278         /* the block for cnt >= 32 */
279         n_block = new_rd_Block(dbg, irg, 1, &in[1]);
280         l2      = h1;
281         h2      = new_r_Const(irg, n_block, l_mode, get_mode_null(l_mode));
282         in[1]   = new_r_Jmp(irg, n_block);
283
284         set_irn_in(block, 2, in);
285
286         in[0] = l1;
287         in[1] = l2;
288         l_res = new_r_Phi(irg, block, 2, in, l_mode);
289         set_irn_link(block, l_res);
290
291         in[0] = h1;
292         in[1] = h2;
293         h_res = new_r_Phi(irg, block, 2, in, l_mode);
294         set_irn_link(l_res, h_res);
295         set_irn_link(h_res, NULL);
296
297         /* move it down */
298         set_nodes_block(call, block);
299         for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
300                 set_nodes_block(irn, block);
301
302         resolve_call(call, l_res, h_res, irg, block);
303         return 1;
304 }
305
306 /**
307  * Map a Shrs (a_l, a_h, count)
308  */
309 static int map_Shrs(ir_node *call, void *ctx) {
310         ir_graph *irg     = current_ir_graph;
311         dbg_info *dbg     = get_irn_dbg_info(call);
312         ir_node  *block   = get_nodes_block(call);
313         ir_node  **params = get_Call_param_arr(call);
314         ir_type  *method  = get_Call_type(call);
315         ir_node  *a_l     = params[BINOP_Left_Low];
316         ir_node  *a_h     = params[BINOP_Left_High];
317         ir_node  *cnt     = params[BINOP_Right_Low];
318         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
319         ir_mode  *c_mode;
320         ir_node  *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
321         (void) ctx;
322
323         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
324
325         if (is_Const(cnt)) {
326                 /* the shift count is a const, create better code */
327                 tarval *tv = get_Const_tarval(cnt);
328
329                 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
330                         /* simplest case: shift only the higher bits. Note that there is no
331                            need to reduce the constant here, this is done by the hardware.  */
332                         ir_mode  *c_mode  = get_irn_mode(cnt);
333
334                         h_res = new_rd_Shrs(dbg, irg, block, a_h, new_r_Const_long(irg, block, c_mode, 31), l_mode);
335                         l_res = new_rd_Shrs(dbg, irg, block, a_h, cnt, l_mode);
336
337                         resolve_call(call, l_res, h_res, irg, block);
338                         return 1;
339                 }
340         }
341
342         part_block(call);
343         upper = get_nodes_block(call);
344
345         /* l_res = SHRD a_h:a_l, cnt */
346         l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
347
348         /* h_res = SAR a_h, cnt */
349         h1 = new_rd_ia32_l_SarDep(dbg, irg, upper, a_h, cnt, l1, l_mode);
350
351         c_mode = get_irn_mode(cnt);
352         irn    = new_r_Const_long(irg, upper, c_mode, 32);
353         irn    = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
354         irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
355         irn    = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
356         cond   = new_rd_Cond(dbg, irg, upper, irn);
357
358         in[0]  = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
359         in[1]  = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
360
361         /* the block for cnt >= 32 */
362         n_block = new_rd_Block(dbg, irg, 1, &in[1]);
363         l2      = h1;
364         h2      = new_rd_Shrs(dbg, irg, n_block, a_h, new_r_Const_long(irg, block, c_mode, 31), l_mode);
365         in[1]   = new_r_Jmp(irg, n_block);
366
367         set_irn_in(block, 2, in);
368
369         in[0] = l1;
370         in[1] = l2;
371         l_res = new_r_Phi(irg, block, 2, in, l_mode);
372         set_irn_link(block, l_res);
373
374         in[0] = h1;
375         in[1] = h2;
376         h_res = new_r_Phi(irg, block, 2, in, l_mode);
377         set_irn_link(l_res, h_res);
378         set_irn_link(h_res, NULL);
379
380         /* move it down */
381         set_nodes_block(call, block);
382         for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
383                 set_nodes_block(irn, block);
384
385         resolve_call(call, l_res, h_res, irg, block);
386         return 1;
387 }
388
389 /**
390  * Map a Mul (a_l, a_h, b_l, b_h)
391  */
392 static int map_Mul(ir_node *call, void *ctx) {
393         ir_graph *irg     = current_ir_graph;
394         dbg_info *dbg     = get_irn_dbg_info(call);
395         ir_node  *block   = get_nodes_block(call);
396         ir_node  **params = get_Call_param_arr(call);
397         ir_type  *method  = get_Call_type(call);
398         ir_node  *a_l     = params[BINOP_Left_Low];
399         ir_node  *a_h     = params[BINOP_Left_High];
400         ir_node  *b_l     = params[BINOP_Right_Low];
401         ir_node  *b_h     = params[BINOP_Right_High];
402         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
403         ir_node  *l_res, *h_res, *mul, *pEDX, *add;
404         (void) ctx;
405
406         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
407         /*
408                 EDX:EAX = a_l * b_l
409                 l_res   = EAX
410
411                 t1 = b_l * a_h
412                 t2 = t1 + EDX
413                 t3 = a_l * b_h
414                 h_res = t2 + t3
415         */
416
417         mul   = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
418         pEDX  = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
419         l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
420
421         mul   = new_rd_Mul(dbg, irg, block, a_h, b_l, l_mode);
422         add   = new_rd_Add(dbg, irg, block, mul, pEDX, l_mode);
423         mul   = new_rd_Mul(dbg, irg, block, a_l, b_h, l_mode);
424         h_res = new_rd_Add(dbg, irg, block, add, mul, l_mode);
425
426         resolve_call(call, l_res, h_res, irg, block);
427
428         return 1;
429 }
430
431 /**
432  * Map a Minus (a_l, a_h)
433  */
434 static int map_Minus(ir_node *call, void *ctx) {
435         ir_graph *irg     = current_ir_graph;
436         dbg_info *dbg     = get_irn_dbg_info(call);
437         ir_node  *block   = get_nodes_block(call);
438         ir_node  **params = get_Call_param_arr(call);
439         ir_type  *method  = get_Call_type(call);
440         ir_node  *a_l     = params[BINOP_Left_Low];
441         ir_node  *a_h     = params[BINOP_Left_High];
442         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
443         ir_node  *l_res, *h_res, *cnst, *res;
444         (void) ctx;
445
446         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
447
448         /* too bad: we need 0 in a register here */
449         cnst  = new_Const_long(l_mode, 0);
450
451         /* l_res = 0 - a_l */
452         /* h_res = 0 - a_h - carry */
453
454         res   = new_rd_ia32_Minus64Bit(dbg, irg, block, cnst, a_l, a_h);
455         l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
456         h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_high_res);
457
458         resolve_call(call, l_res, h_res, irg, block);
459
460         return 1;
461 }
462
463 /**
464  * Map a Abs (a_l, a_h)
465  */
466 static int map_Abs(ir_node *call, void *ctx) {
467         ir_graph *irg     = current_ir_graph;
468         dbg_info *dbg     = get_irn_dbg_info(call);
469         ir_node  *block   = get_nodes_block(call);
470         ir_node  **params = get_Call_param_arr(call);
471         ir_type  *method  = get_Call_type(call);
472         ir_node  *a_l     = params[BINOP_Left_Low];
473         ir_node  *a_h     = params[BINOP_Left_High];
474         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
475         ir_node  *l_res, *h_res, *sign, *sub_l, *sub_h, *res;
476         (void) ctx;
477
478         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
479
480         /*
481                 Code inspired by gcc output :) (although gcc doubles the
482                 operation for t1 as t2 and uses t1 for operations with low part
483                 and t2 for operations with high part which is actually unnecessary
484                 because t1 and t2 represent the same value)
485
486                 t1    = SHRS a_h, 31
487                 t2    = a_l ^ t1
488                 t3    = a_h ^ t1
489                 l_res = t2 - t1
490                 h_res = t3 - t1 - carry
491
492         */
493
494         sign  = new_rd_ia32_l_Sar(dbg, irg, block, a_h, new_Const_long(l_mode, 31), l_mode);
495         sub_l = new_rd_ia32_l_Xor(dbg, irg, block, a_l, sign, l_mode);
496         sub_h = new_rd_ia32_l_Xor(dbg, irg, block, a_h, sign, l_mode);
497         res   = new_rd_ia32_Sub64Bit(dbg, irg, block, sub_l, sub_h, sign, sign);
498         l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
499         h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);
500
501         resolve_call(call, l_res, h_res, irg, block);
502
503         return 1;
504 }
505
506 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
507
508 /**
509  * Maps a Div. Change into a library call
510  */
511 static int map_Div(ir_node *call, void *ctx) {
512         ia32_intrinsic_env_t *env = ctx;
513         ir_type   *method    = get_Call_type(call);
514         ir_mode   *l_mode    = get_type_mode(get_method_res_type(method, 0));
515         ir_node   *ptr;
516         ir_entity *ent;
517         symconst_symbol sym;
518
519         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
520
521         if (mode_is_signed(l_mode)) {
522                 /* 64bit signed Division */
523                 ent = env->divdi3;
524                 if (ent == NULL) {
525                         /* create library entity */
526                         ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
527                         set_entity_visibility(ent, visibility_external_allocated);
528                         set_entity_ld_ident(ent, ID("__divdi3"));
529                 }
530         } else {
531                 /* 64bit signed Division */
532                 ent = env->udivdi3;
533                 if (ent == NULL) {
534                         /* create library entity */
535                         ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
536                         set_entity_visibility(ent, visibility_external_allocated);
537                         set_entity_ld_ident(ent, ID("__udivdi3"));
538                 }
539         }
540         sym.entity_p = ent;
541         ptr = get_Call_ptr(call);
542         set_SymConst_symbol(ptr, sym);
543         return 1;
544 }
545
546 /**
547  * Maps a Mod. Change into a library call
548  */
549 static int map_Mod(ir_node *call, void *ctx) {
550         ia32_intrinsic_env_t *env = ctx;
551         ir_type   *method    = get_Call_type(call);
552         ir_mode   *l_mode    = get_type_mode(get_method_res_type(method, 0));
553         ir_node   *ptr;
554         ir_entity *ent;
555         symconst_symbol sym;
556
557         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
558
559         if (mode_is_signed(l_mode)) {
560                 /* 64bit signed Modulo */
561                 ent = env->moddi3;
562                 if (ent == NULL) {
563                         /* create library entity */
564                         ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
565                         set_entity_visibility(ent, visibility_external_allocated);
566                         set_entity_ld_ident(ent, ID("__moddi3"));
567                 }
568         } else {
569                 /* 64bit signed Modulo */
570                 ent = env->umoddi3;
571                 if (ent == NULL) {
572                         /* create library entity */
573                         ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
574                         set_entity_visibility(ent, visibility_external_allocated);
575                         set_entity_ld_ident(ent, ID("__umoddi3"));
576                 }
577         }
578         sym.entity_p = ent;
579         ptr = get_Call_ptr(call);
580         set_SymConst_symbol(ptr, sym);
581         return 1;
582 }
583
584 /**
585  * Maps a Conv.
586  */
587 static int map_Conv(ir_node *call, void *ctx) {
588         ia32_intrinsic_env_t *env = ctx;
589         ir_graph  *irg        = current_ir_graph;
590         dbg_info  *dbg        = get_irn_dbg_info(call);
591         ir_node   *block      = get_nodes_block(call);
592         ir_node   **params    = get_Call_param_arr(call);
593         ir_type   *method     = get_Call_type(call);
594         int       n           = get_Call_n_params(call);
595         int       gp_bytes    = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
596         ir_entity *ent;
597         ir_node   *l_res, *h_res, *frame, *fres;
598         ir_node   *store_l, *store_h;
599         ir_node   *op_mem[2], *mem;
600
601         if (n == 1) {
602                 /* We have a Conv float -> long long here */
603                 ir_node *a_f        = params[0];
604                 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
605                 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
606
607                 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
608
609                 /* allocate memory on frame to store args */
610                 ent = env->irg == irg ? env->d_ll_conv : NULL;
611                 if (! ent) {
612                         ent      = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
613                         env->irg = irg;
614                 }
615
616                 /* Store arg */
617                 frame = get_irg_frame(irg);
618
619                 /*
620                         Now we create a node to move the value from a XMM register into
621                         x87 FPU because it is unknown here, which FPU is used.
622                         This node is killed in transformation phase when not needed.
623                         Otherwise it is split up into a movsd + fld
624                 */
625                 a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
626                 set_ia32_frame_ent(a_f, ent);
627                 set_ia32_use_frame(a_f);
628                 set_ia32_ls_mode(a_f, mode_D);
629
630                 /* store from FPU as Int */
631                 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
632                 set_ia32_frame_ent(a_f, ent);
633                 set_ia32_use_frame(a_f);
634                 set_ia32_ls_mode(a_f, mode_D);
635                 mem = a_f;
636
637                 /* load low part of the result */
638                 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
639                 set_ia32_frame_ent(l_res, ent);
640                 set_ia32_use_frame(l_res);
641                 set_ia32_ls_mode(l_res, l_res_mode);
642                 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
643
644                 /* load hight part of the result */
645                 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
646                 set_ia32_frame_ent(h_res, ent);
647                 add_ia32_am_offs_int(h_res, gp_bytes);
648                 set_ia32_use_frame(h_res);
649                 set_ia32_ls_mode(h_res, h_res_mode);
650                 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
651
652                 /* lower the call */
653                 resolve_call(call, l_res, h_res, irg, block);
654         }
655         else if (n == 2) {
656                 /* We have a Conv long long -> float here */
657                 ir_node *a_l       = params[BINOP_Left_Low];
658                 ir_node *a_h       = params[BINOP_Left_High];
659                 ir_mode *mode_a_l  = get_irn_mode(a_l);
660                 ir_mode *mode_a_h  = get_irn_mode(a_h);
661                 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
662
663                 assert(! mode_is_float(mode_a_l) && ! mode_is_float(mode_a_h) && "unexpected Conv call");
664
665                 /* allocate memory on frame to store args */
666                 ent = env->irg == irg ? env->ll_d_conv : NULL;
667                 if (! ent) {
668                         ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
669                         env->irg = irg;
670                 }
671
672                 /* Store arg */
673                 frame = get_irg_frame(irg);
674
675                 /* store first arg (low part) */
676                 store_l   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
677                 set_ia32_frame_ent(store_l, ent);
678                 set_ia32_use_frame(store_l);
679                 set_ia32_ls_mode(store_l, get_irn_mode(a_l));
680                 op_mem[0] = store_l;
681
682                 /* store second arg (high part) */
683                 store_h   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
684                 set_ia32_frame_ent(store_h, ent);
685                 add_ia32_am_offs_int(store_h, gp_bytes);
686                 set_ia32_use_frame(store_h);
687                 set_ia32_ls_mode(store_h, get_irn_mode(a_h));
688                 op_mem[1] = store_h;
689
690                 mem = new_r_Sync(irg, block, 2, op_mem);
691
692                 /* Load arg into x87 FPU (implicit convert) */
693                 fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
694                 set_ia32_frame_ent(fres, ent);
695                 set_ia32_use_frame(fres);
696                 set_ia32_ls_mode(fres, mode_D);
697                 mem  = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
698                 fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);
699
700                 /*
701                         Now we create a node to move the loaded value into a XMM
702                         register because it is unknown here, which FPU is used.
703                         This node is killed in transformation phase when not needed.
704                         Otherwise it is split up into a fst + movsd
705                 */
706                 fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
707                 set_ia32_frame_ent(fres, ent);
708                 set_ia32_use_frame(fres);
709                 set_ia32_ls_mode(fres, fres_mode);
710
711                 /* lower the call */
712                 resolve_call(call, fres, NULL, irg, block);
713         }
714         else {
715                 assert(0 && "unexpected Conv call");
716         }
717
718         return 1;
719 }
720
721 /* Ia32 implementation of intrinsic mapping. */
722 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
723                                      const ir_mode *imode, const ir_mode *omode,
724                                      void *context)
725 {
726         i_record      elt;
727         ir_entity     **ent = NULL;
728         i_mapper_func mapper;
729
730         if (! intrinsics)
731                 intrinsics = NEW_ARR_F(i_record, 0);
732
733         switch (get_op_code(op)) {
734         case iro_Add:
735                 ent    = &i_ents[iro_Add];
736                 mapper = map_Add;
737                 break;
738         case iro_Sub:
739                 ent    = &i_ents[iro_Sub];
740                 mapper = map_Sub;
741                 break;
742         case iro_Shl:
743                 ent    = &i_ents[iro_Shl];
744                 mapper = map_Shl;
745                 break;
746         case iro_Shr:
747                 ent    = &i_ents[iro_Shr];
748                 mapper = map_Shr;
749                 break;
750         case iro_Shrs:
751                 ent    = &i_ents[iro_Shrs];
752                 mapper = map_Shrs;
753                 break;
754         case iro_Mul:
755                 ent    = &i_ents[iro_Mul];
756                 mapper = map_Mul;
757                 break;
758         case iro_Minus:
759                 ent    = &i_ents[iro_Minus];
760                 mapper = map_Minus;
761                 break;
762         case iro_Abs:
763                 ent    = &i_ents[iro_Abs];
764                 mapper = map_Abs;
765                 break;
766         case iro_Div:
767                 ent    = &i_ents[iro_Div];
768                 mapper = map_Div;
769                 break;
770         case iro_Mod:
771                 ent    = &i_ents[iro_Mod];
772                 mapper = map_Mod;
773                 break;
774         case iro_Conv:
775                 ent    = &i_ents[iro_Conv];
776                 mapper = map_Conv;
777                 break;
778         default:
779                 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
780                 return def_create_intrinsic_fkt(method, op, imode, omode, context);
781         }
782
783         if (ent && ! *ent) {
784 #define IDENT(s)  new_id_from_chars(s, sizeof(s)-1)
785
786                 ident *id = mangle(IDENT("L"), get_op_ident(op));
787                 *ent = new_entity(get_glob_type(), id, method);
788         }
789
790         elt.i_call.kind     = INTRINSIC_CALL;
791         elt.i_call.i_ent    = *ent;
792         elt.i_call.i_mapper = mapper;
793         elt.i_call.ctx      = context;
794         elt.i_call.link     = NULL;
795
796         ARR_APP1(i_record, intrinsics, elt);
797         return *ent;
798 }