fixed 64bit instrinsics for Div/Mod/Shr/Shl/Shrs
[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));
57 }
58
59 #define BINOP_Left_Low   0
60 #define BINOP_Left_High  1
61 #define BINOP_Right_Low  2
62 #define BINOP_Right_High 3
63
64 /**
65  * Replace a call be a tuple of l_res, h_res.
66  */
67 static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block) {
68         ir_node *res, *in[2];
69
70         in[0] = l_res;
71         in[1] = h_res;
72         res = new_r_Tuple(irg, block, h_res == NULL ? 1 : 2, in);
73
74         turn_into_tuple(call, pn_Call_max);
75         set_Tuple_pred(call, pn_Call_M_regular,        get_irg_no_mem(irg));
76         set_Tuple_pred(call, pn_Call_X_regular,        new_r_Jmp(irg, block));
77         set_Tuple_pred(call, pn_Call_X_except,         get_irg_bad(irg));
78         set_Tuple_pred(call, pn_Call_T_result,         res);
79         set_Tuple_pred(call, pn_Call_M_except,         get_irg_no_mem(irg));
80         set_Tuple_pred(call, pn_Call_P_value_res_base, get_irg_bad(irg));
81 }
82
83 /**
84  * Map an Add (a_l, a_h, b_l, b_h)
85  */
86 static int map_Add(ir_node *call, void *ctx) {
87         ir_graph *irg     = current_ir_graph;
88         dbg_info *dbg     = get_irn_dbg_info(call);
89         ir_node  *block   = get_nodes_block(call);
90         ir_node  **params = get_Call_param_arr(call);
91         ir_type  *method  = get_Call_type(call);
92         ir_node  *a_l     = params[BINOP_Left_Low];
93         ir_node  *a_h     = params[BINOP_Left_High];
94         ir_node  *b_l     = params[BINOP_Right_Low];
95         ir_node  *b_h     = params[BINOP_Right_High];
96         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
97         ir_node  *l_res, *h_res, *add;
98         (void) ctx;
99
100         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
101
102         /* l_res = a_l + b_l */
103         /* h_res = a_h + b_h + carry */
104
105         add   = new_rd_ia32_Add64Bit(dbg, irg, block, a_l, a_h, b_l, b_h);
106         l_res = new_r_Proj(irg, block, add, l_mode, pn_ia32_Add64Bit_low_res);
107         h_res = new_r_Proj(irg, block, add, l_mode, pn_ia32_Add64Bit_high_res);
108
109         resolve_call(call, l_res, h_res, irg, block);
110         return 1;
111 }
112
113 /**
114  * Map a Sub (a_l, a_h, b_l, b_h)
115  */
116 static int map_Sub(ir_node *call, void *ctx) {
117         ir_graph *irg     = current_ir_graph;
118         dbg_info *dbg     = get_irn_dbg_info(call);
119         ir_node  *block   = get_nodes_block(call);
120         ir_node  **params = get_Call_param_arr(call);
121         ir_type  *method  = get_Call_type(call);
122         ir_node  *a_l     = params[BINOP_Left_Low];
123         ir_node  *a_h     = params[BINOP_Left_High];
124         ir_node  *b_l     = params[BINOP_Right_Low];
125         ir_node  *b_h     = params[BINOP_Right_High];
126         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
127         ir_node  *l_res, *h_res, *res;
128         (void) ctx;
129
130         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
131
132         /* l_res = a_l - b_l */
133         /* h_res = a_h - b_h - carry */
134
135         res   = new_rd_ia32_Sub64Bit(dbg, irg, block, a_l, a_h, b_l, b_h);
136         l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
137         h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);
138
139         resolve_call(call, l_res, h_res, irg, block);
140         return 1;
141 }
142
143 /**
144  * Map a Shl (a_l, a_h, count)
145  */
146 static int map_Shl(ir_node *call, void *ctx) {
147         ir_graph *irg     = current_ir_graph;
148         dbg_info *dbg     = get_irn_dbg_info(call);
149         ir_node  *block   = get_nodes_block(call);
150         ir_node  **params = get_Call_param_arr(call);
151         ir_type  *method  = get_Call_type(call);
152         ir_node  *a_l     = params[BINOP_Left_Low];
153         ir_node  *a_h     = params[BINOP_Left_High];
154         ir_node  *cnt     = params[BINOP_Right_Low];
155         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
156         ir_node  *l_res, *h_res;
157         (void) ctx;
158
159         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
160
161         /* h_res = SHLD a_h, a_l, cnt */
162         h_res = new_rd_ia32_l_ShlD(dbg, irg, block, a_h, a_l, cnt, l_mode);
163
164         /* l_res = SHL a_l, cnt */
165         l_res = new_rd_ia32_l_ShlDep(dbg, irg, block, a_l, cnt, h_res, l_mode);
166
167         resolve_call(call, l_res, h_res, irg, block);
168         return 1;
169 }
170
171 /**
172  * Map a Shr (a_l, a_h, count)
173  */
174 static int map_Shr(ir_node *call, void *ctx) {
175         ir_graph *irg     = current_ir_graph;
176         dbg_info *dbg     = get_irn_dbg_info(call);
177         ir_node  *block   = get_nodes_block(call);
178         ir_node  **params = get_Call_param_arr(call);
179         ir_type  *method  = get_Call_type(call);
180         ir_node  *a_l     = params[BINOP_Left_Low];
181         ir_node  *a_h     = params[BINOP_Left_High];
182         ir_node  *cnt     = params[BINOP_Right_Low];
183         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
184         ir_node  *l_res, *h_res;
185         (void) ctx;
186
187         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
188
189         /* l_res = SHRD a_h:a_l, cnt */
190         l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
191
192         /* h_res = SHR a_h, cnt */
193         h_res = new_rd_ia32_l_ShrDep(dbg, irg, block, a_h, cnt, l_res, l_mode);
194
195         resolve_call(call, l_res, h_res, irg, block);
196         return 1;
197 }
198
199 /**
200  * Map a Shrs (a_l, a_h, count)
201  */
202 static int map_Shrs(ir_node *call, void *ctx) {
203         ir_graph *irg     = current_ir_graph;
204         dbg_info *dbg     = get_irn_dbg_info(call);
205         ir_node  *block   = get_nodes_block(call);
206         ir_node  **params = get_Call_param_arr(call);
207         ir_type  *method  = get_Call_type(call);
208         ir_node  *a_l     = params[BINOP_Left_Low];
209         ir_node  *a_h     = params[BINOP_Left_High];
210         ir_node  *cnt     = params[BINOP_Right_Low];
211         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
212         ir_node  *l_res, *h_res;
213         (void) ctx;
214
215         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
216
217         /* l_res = SHRD a_h:a_l, cnt */
218         l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
219
220         /* h_res = SAR a_h, cnt */
221         h_res = new_rd_ia32_l_SarDep(dbg, irg, block, a_h, cnt, l_res, l_mode);
222
223         resolve_call(call, l_res, h_res, irg, block);
224         return 1;
225 }
226
227 /**
228  * Map a Mul (a_l, a_h, b_l, b_h)
229  */
230 static int map_Mul(ir_node *call, void *ctx) {
231         ir_graph *irg     = current_ir_graph;
232         dbg_info *dbg     = get_irn_dbg_info(call);
233         ir_node  *block   = get_nodes_block(call);
234         ir_node  **params = get_Call_param_arr(call);
235         ir_type  *method  = get_Call_type(call);
236         ir_node  *a_l     = params[BINOP_Left_Low];
237         ir_node  *a_h     = params[BINOP_Left_High];
238         ir_node  *b_l     = params[BINOP_Right_Low];
239         ir_node  *b_h     = params[BINOP_Right_High];
240         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
241         ir_node  *l_res, *h_res, *mul, *pEDX, *add;
242         (void) ctx;
243
244         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
245         /*
246                 EDX:EAX = a_l * b_l
247                 l_res   = EAX
248
249                 t1 = b_l * a_h
250                 t2 = t1 + EDX
251                 t3 = a_l * b_h
252                 h_res = t2 + t3
253         */
254
255         mul   = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
256         pEDX  = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
257         l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
258
259         mul   = new_rd_Mul(dbg, irg, block, a_h, b_l, l_mode);
260         add   = new_rd_Add(dbg, irg, block, mul, pEDX, l_mode);
261         mul   = new_rd_Mul(dbg, irg, block, a_l, b_h, l_mode);
262         h_res = new_rd_Add(dbg, irg, block, add, mul, l_mode);
263
264         resolve_call(call, l_res, h_res, irg, block);
265
266         return 1;
267 }
268
269 /**
270  * Map a Minus (a_l, a_h)
271  */
272 static int map_Minus(ir_node *call, void *ctx) {
273         ir_graph *irg     = current_ir_graph;
274         dbg_info *dbg     = get_irn_dbg_info(call);
275         ir_node  *block   = get_nodes_block(call);
276         ir_node  **params = get_Call_param_arr(call);
277         ir_type  *method  = get_Call_type(call);
278         ir_node  *a_l     = params[BINOP_Left_Low];
279         ir_node  *a_h     = params[BINOP_Left_High];
280         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
281         ir_node  *l_res, *h_res, *cnst, *res;
282         (void) ctx;
283
284         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
285
286         /* too bad: we need 0 in a register here */
287         cnst  = new_Const_long(l_mode, 0);
288
289         /* l_res = 0 - a_l */
290         /* h_res = 0 - a_h - carry */
291
292         res   = new_rd_ia32_Minus64Bit(dbg, irg, block, cnst, a_l, a_h);
293         l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
294         h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_high_res);
295
296         resolve_call(call, l_res, h_res, irg, block);
297
298         return 1;
299 }
300
301 /**
302  * Map a Abs (a_l, a_h)
303  */
304 static int map_Abs(ir_node *call, void *ctx) {
305         ir_graph *irg     = current_ir_graph;
306         dbg_info *dbg     = get_irn_dbg_info(call);
307         ir_node  *block   = get_nodes_block(call);
308         ir_node  **params = get_Call_param_arr(call);
309         ir_type  *method  = get_Call_type(call);
310         ir_node  *a_l     = params[BINOP_Left_Low];
311         ir_node  *a_h     = params[BINOP_Left_High];
312         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
313         ir_node  *l_res, *h_res, *sign, *sub_l, *sub_h, *res;
314         (void) ctx;
315
316         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
317
318         /*
319                 Code inspired by gcc output :) (although gcc doubles the
320                 operation for t1 as t2 and uses t1 for operations with low part
321                 and t2 for operations with high part which is actually unnecessary
322                 because t1 and t2 represent the same value)
323
324                 t1    = SHRS a_h, 31
325                 t2    = a_l ^ t1
326                 t3    = a_h ^ t1
327                 l_res = t2 - t1
328                 h_res = t3 - t1 - carry
329
330         */
331
332         sign  = new_rd_ia32_l_Sar(dbg, irg, block, a_h, new_Const_long(l_mode, 31), l_mode);
333         sub_l = new_rd_ia32_l_Xor(dbg, irg, block, a_l, sign, l_mode);
334         sub_h = new_rd_ia32_l_Xor(dbg, irg, block, a_h, sign, l_mode);
335         res   = new_rd_ia32_Sub64Bit(dbg, irg, block, sub_l, sub_h, sign, sign);
336         l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
337         h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);
338
339         resolve_call(call, l_res, h_res, irg, block);
340
341         return 1;
342 }
343
344 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
345
346 /**
347  * Maps a Div. Change into a library call
348  */
349 static int map_Div(ir_node *call, void *ctx) {
350         ia32_intrinsic_env_t *env = ctx;
351         ir_type   *method    = get_Call_type(call);
352         ir_mode   *l_mode    = get_type_mode(get_method_res_type(method, 0));
353         ir_node   *ptr;
354         ir_entity *ent;
355         symconst_symbol sym;
356
357         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
358
359         if (mode_is_signed(l_mode)) {
360                 /* 64bit signed Division */
361                 ent = env->divdi3;
362                 if (ent == NULL) {
363                         /* create library entity */
364                         ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
365                         set_entity_visibility(ent, visibility_external_allocated);
366                         set_entity_ld_ident(ent, ID("__divdi3"));
367                 }
368         } else {
369                 /* 64bit signed Division */
370                 ent = env->udivdi3;
371                 if (ent == NULL) {
372                         /* create library entity */
373                         ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
374                         set_entity_visibility(ent, visibility_external_allocated);
375                         set_entity_ld_ident(ent, ID("__udivdi3"));
376                 }
377         }
378         sym.entity_p = ent;
379         ptr = get_Call_ptr(call);
380         set_SymConst_symbol(ptr, sym);
381         return 1;
382 }
383
384 /**
385  * Maps a Mod. Change into a library call
386  */
387 static int map_Mod(ir_node *call, void *ctx) {
388         ia32_intrinsic_env_t *env = ctx;
389         ir_type   *method    = get_Call_type(call);
390         ir_mode   *l_mode    = get_type_mode(get_method_res_type(method, 0));
391         ir_node   *ptr;
392         ir_entity *ent;
393         symconst_symbol sym;
394
395         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
396
397         if (mode_is_signed(l_mode)) {
398                 /* 64bit signed Modulo */
399                 ent = env->moddi3;
400                 if (ent == NULL) {
401                         /* create library entity */
402                         ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
403                         set_entity_visibility(ent, visibility_external_allocated);
404                         set_entity_ld_ident(ent, ID("__moddi3"));
405                 }
406         } else {
407                 /* 64bit signed Modulo */
408                 ent = env->umoddi3;
409                 if (ent == NULL) {
410                         /* create library entity */
411                         ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
412                         set_entity_visibility(ent, visibility_external_allocated);
413                         set_entity_ld_ident(ent, ID("__umoddi3"));
414                 }
415         }
416         sym.entity_p = ent;
417         ptr = get_Call_ptr(call);
418         set_SymConst_symbol(ptr, sym);
419         return 1;
420 }
421
422 /**
423  * Maps a Conv.
424  */
425 static int map_Conv(ir_node *call, void *ctx) {
426         ia32_intrinsic_env_t *env = ctx;
427         ir_graph  *irg        = current_ir_graph;
428         dbg_info  *dbg        = get_irn_dbg_info(call);
429         ir_node   *block      = get_nodes_block(call);
430         ir_node   **params    = get_Call_param_arr(call);
431         ir_type   *method     = get_Call_type(call);
432         int       n           = get_Call_n_params(call);
433         int       gp_bytes    = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
434         ir_entity *ent;
435         ir_node   *l_res, *h_res, *frame, *fres;
436         ir_node   *store_l, *store_h;
437         ir_node   *op_mem[2], *mem;
438
439         if (n == 1) {
440                 /* We have a Conv float -> long long here */
441                 ir_node *a_f        = params[0];
442                 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
443                 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
444
445                 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
446
447                 /* allocate memory on frame to store args */
448                 ent = env->irg == irg ? env->d_ll_conv : NULL;
449                 if (! ent) {
450                         ent      = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
451                         env->irg = irg;
452                 }
453
454                 /* Store arg */
455                 frame = get_irg_frame(irg);
456
457                 /*
458                         Now we create a node to move the value from a XMM register into
459                         x87 FPU because it is unknown here, which FPU is used.
460                         This node is killed in transformation phase when not needed.
461                         Otherwise it is split up into a movsd + fld
462                 */
463                 a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
464                 set_ia32_frame_ent(a_f, ent);
465                 set_ia32_use_frame(a_f);
466                 set_ia32_ls_mode(a_f, mode_D);
467
468                 /* store from FPU as Int */
469                 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
470                 set_ia32_frame_ent(a_f, ent);
471                 set_ia32_use_frame(a_f);
472                 set_ia32_ls_mode(a_f, mode_D);
473                 mem = a_f;
474
475                 /* load low part of the result */
476                 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
477                 set_ia32_frame_ent(l_res, ent);
478                 set_ia32_use_frame(l_res);
479                 set_ia32_ls_mode(l_res, l_res_mode);
480                 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
481
482                 /* load hight part of the result */
483                 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
484                 set_ia32_frame_ent(h_res, ent);
485                 add_ia32_am_offs_int(h_res, gp_bytes);
486                 set_ia32_use_frame(h_res);
487                 set_ia32_ls_mode(h_res, h_res_mode);
488                 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
489
490                 /* lower the call */
491                 resolve_call(call, l_res, h_res, irg, block);
492         }
493         else if (n == 2) {
494                 /* We have a Conv long long -> float here */
495                 ir_node *a_l       = params[BINOP_Left_Low];
496                 ir_node *a_h       = params[BINOP_Left_High];
497                 ir_mode *mode_a_l  = get_irn_mode(a_l);
498                 ir_mode *mode_a_h  = get_irn_mode(a_h);
499                 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
500
501                 assert(! mode_is_float(mode_a_l) && ! mode_is_float(mode_a_h) && "unexpected Conv call");
502
503                 /* allocate memory on frame to store args */
504                 ent = env->irg == irg ? env->ll_d_conv : NULL;
505                 if (! ent) {
506                         ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
507                         env->irg = irg;
508                 }
509
510                 /* Store arg */
511                 frame = get_irg_frame(irg);
512
513                 /* store first arg (low part) */
514                 store_l   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
515                 set_ia32_frame_ent(store_l, ent);
516                 set_ia32_use_frame(store_l);
517                 set_ia32_ls_mode(store_l, get_irn_mode(a_l));
518                 op_mem[0] = store_l;
519
520                 /* store second arg (high part) */
521                 store_h   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
522                 set_ia32_frame_ent(store_h, ent);
523                 add_ia32_am_offs_int(store_h, gp_bytes);
524                 set_ia32_use_frame(store_h);
525                 set_ia32_ls_mode(store_h, get_irn_mode(a_h));
526                 op_mem[1] = store_h;
527
528                 mem = new_r_Sync(irg, block, 2, op_mem);
529
530                 /* Load arg into x87 FPU (implicit convert) */
531                 fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
532                 set_ia32_frame_ent(fres, ent);
533                 set_ia32_use_frame(fres);
534                 set_ia32_ls_mode(fres, mode_D);
535                 mem  = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
536                 fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);
537
538                 /*
539                         Now we create a node to move the loaded value into a XMM
540                         register because it is unknown here, which FPU is used.
541                         This node is killed in transformation phase when not needed.
542                         Otherwise it is split up into a fst + movsd
543                 */
544                 fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
545                 set_ia32_frame_ent(fres, ent);
546                 set_ia32_use_frame(fres);
547                 set_ia32_ls_mode(fres, fres_mode);
548
549                 /* lower the call */
550                 resolve_call(call, fres, NULL, irg, block);
551         }
552         else {
553                 assert(0 && "unexpected Conv call");
554         }
555
556         return 1;
557 }
558
559 /* Ia32 implementation of intrinsic mapping. */
560 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
561                                      const ir_mode *imode, const ir_mode *omode,
562                                      void *context)
563 {
564         i_record      elt;
565         ir_entity     **ent = NULL;
566         i_mapper_func mapper;
567
568         if (! intrinsics)
569                 intrinsics = NEW_ARR_F(i_record, 0);
570
571         switch (get_op_code(op)) {
572         case iro_Add:
573                 ent    = &i_ents[iro_Add];
574                 mapper = map_Add;
575                 break;
576         case iro_Sub:
577                 ent    = &i_ents[iro_Sub];
578                 mapper = map_Sub;
579                 break;
580         case iro_Shl:
581                 ent    = &i_ents[iro_Shl];
582                 mapper = map_Shl;
583                 break;
584         case iro_Shr:
585                 ent    = &i_ents[iro_Shr];
586                 mapper = map_Shr;
587                 break;
588         case iro_Shrs:
589                 ent    = &i_ents[iro_Shrs];
590                 mapper = map_Shrs;
591                 break;
592         case iro_Mul:
593                 ent    = &i_ents[iro_Mul];
594                 mapper = map_Mul;
595                 break;
596         case iro_Minus:
597                 ent    = &i_ents[iro_Minus];
598                 mapper = map_Minus;
599                 break;
600         case iro_Abs:
601                 ent    = &i_ents[iro_Abs];
602                 mapper = map_Abs;
603                 break;
604         case iro_Div:
605                 ent    = &i_ents[iro_Div];
606                 mapper = map_Div;
607                 break;
608         case iro_Mod:
609                 ent    = &i_ents[iro_Mod];
610                 mapper = map_Mod;
611                 break;
612         case iro_Conv:
613                 ent    = &i_ents[iro_Conv];
614                 mapper = map_Conv;
615                 break;
616         default:
617                 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
618                 return def_create_intrinsic_fkt(method, op, imode, omode, context);
619         }
620
621         if (ent && ! *ent) {
622 #define IDENT(s)  new_id_from_chars(s, sizeof(s)-1)
623
624                 ident *id = mangle(IDENT("L"), get_op_ident(op));
625                 *ent = new_entity(get_glob_type(), id, method);
626         }
627
628         elt.i_call.kind     = INTRINSIC_CALL;
629         elt.i_call.i_ent    = *ent;
630         elt.i_call.i_mapper = mapper;
631         elt.i_call.ctx      = context;
632         elt.i_call.link     = NULL;
633
634         ARR_APP1(i_record, intrinsics, elt);
635         return *ent;
636 }