fixed map_Mul; cleaned up a bit
[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_res_mode = get_type_mode(get_method_res_type(method, 0));
97         ir_mode  *h_res_mode = get_type_mode(get_method_res_type(method, 1));
98         ir_node  *l_res, *h_res, *add;
99         (void) ctx;
100
101         /* l_res = a_l + b_l */
102         /* h_res = a_h + b_h + carry */
103
104         add   = new_rd_ia32_Add64Bit(dbg, irg, block, a_l, a_h, b_l, b_h);
105         l_res = new_r_Proj(irg, block, add, l_res_mode, pn_ia32_Add64Bit_low_res);
106         h_res = new_r_Proj(irg, block, add, h_res_mode, pn_ia32_Add64Bit_high_res);
107
108         resolve_call(call, l_res, h_res, irg, block);
109         return 1;
110 }
111
112 /**
113  * Map a Sub (a_l, a_h, b_l, b_h)
114  */
115 static int map_Sub(ir_node *call, void *ctx) {
116         ir_graph *irg        = current_ir_graph;
117         dbg_info *dbg        = get_irn_dbg_info(call);
118         ir_node  *block      = get_nodes_block(call);
119         ir_node  **params    = get_Call_param_arr(call);
120         ir_type  *method     = get_Call_type(call);
121         ir_node  *a_l        = params[BINOP_Left_Low];
122         ir_node  *a_h        = params[BINOP_Left_High];
123         ir_node  *b_l        = params[BINOP_Right_Low];
124         ir_node  *b_h        = params[BINOP_Right_High];
125         ir_mode  *l_res_mode = get_type_mode(get_method_res_type(method, 0));
126         ir_mode  *h_res_mode = get_type_mode(get_method_res_type(method, 1));
127         ir_node  *l_res, *h_res, *res;
128         (void) ctx;
129
130         /* l_res = a_l - b_l */
131         /* h_res = a_h - b_h - carry */
132
133         res   = new_rd_ia32_Sub64Bit(dbg, irg, block, a_l, a_h, b_l, b_h);
134         l_res = new_r_Proj(irg, block, res, l_res_mode, pn_ia32_Sub64Bit_low_res);
135         h_res = new_r_Proj(irg, block, res, h_res_mode, pn_ia32_Sub64Bit_high_res);
136
137         resolve_call(call, l_res, h_res, irg, block);
138         return 1;
139 }
140
141 /**
142  * Map a Shl (a_l, a_h, count)
143  */
144 static int map_Shl(ir_node *call, void *ctx) {
145         ir_graph *irg        = current_ir_graph;
146         dbg_info *dbg        = get_irn_dbg_info(call);
147         ir_node  *block      = get_nodes_block(call);
148         ir_node  **params    = get_Call_param_arr(call);
149         ir_type  *method     = get_Call_type(call);
150         ir_node  *a_l        = params[BINOP_Left_Low];
151         ir_node  *a_h        = params[BINOP_Left_High];
152         ir_node  *cnt        = params[BINOP_Right_Low];
153         ir_mode  *l_res_mode = get_type_mode(get_method_res_type(method, 0));
154         ir_mode  *h_res_mode = get_type_mode(get_method_res_type(method, 1));
155         ir_node  *l_res, *h_res;
156         (void) ctx;
157
158         /* h_res = SHLD a_h, a_l, cnt */
159         h_res = new_rd_ia32_l_ShlD(dbg, irg, block, a_h, a_l, cnt, l_res_mode);
160
161         /* l_res = SHL a_l, cnt */
162         l_res = new_rd_ia32_l_Shl(dbg, irg, block, a_l, cnt, h_res_mode);
163
164         //add_irn_dep(l_res, h_res);
165
166         resolve_call(call, l_res, h_res, irg, block);
167         return 1;
168 }
169
170 /**
171  * Map a Shr (a_l, a_h, count)
172  */
173 static int map_Shr(ir_node *call, void *ctx) {
174         ir_graph *irg        = current_ir_graph;
175         dbg_info *dbg        = get_irn_dbg_info(call);
176         ir_node  *block      = get_nodes_block(call);
177         ir_node  **params    = get_Call_param_arr(call);
178         ir_type  *method     = get_Call_type(call);
179         ir_node  *a_l        = params[BINOP_Left_Low];
180         ir_node  *a_h        = params[BINOP_Left_High];
181         ir_node  *cnt        = params[BINOP_Right_Low];
182         ir_mode  *l_res_mode = get_type_mode(get_method_res_type(method, 0));
183         ir_mode  *h_res_mode = get_type_mode(get_method_res_type(method, 1));
184         ir_node  *l_res, *h_res;
185         (void) ctx;
186
187         /* l_res = SHRD a_l, a_h, cnt */
188         l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_res_mode);
189
190         /* h_res = SHR a_h, cnt */
191         h_res = new_rd_ia32_l_Shr(dbg, irg, block, a_h, cnt, h_res_mode);
192
193         //add_irn_dep(h_res, l_res);
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_l, a_h, 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_Sar(dbg, irg, block, a_h, cnt, l_mode);
222
223         //add_irn_dep(h_res, l_res);
224
225         resolve_call(call, l_res, h_res, irg, block);
226         return 1;
227 }
228
229 /**
230  * Map a Mul (a_l, a_h, b_l, b_h)
231  */
232 static int map_Mul(ir_node *call, void *ctx) {
233         ir_graph *irg     = current_ir_graph;
234         dbg_info *dbg     = get_irn_dbg_info(call);
235         ir_node  *block   = get_nodes_block(call);
236         ir_node  **params = get_Call_param_arr(call);
237         ir_type  *method  = get_Call_type(call);
238         ir_node  *a_l     = params[BINOP_Left_Low];
239         ir_node  *a_h     = params[BINOP_Left_High];
240         ir_node  *b_l     = params[BINOP_Right_Low];
241         ir_node  *b_h     = params[BINOP_Right_High];
242         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
243         ir_node  *l_res, *h_res, *mul, *pEDX, *add;
244         (void) ctx;
245
246         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
247         /*
248                 EDX:EAX = a_l * b_l
249                 l_res   = EAX
250
251                 t1 = b_l * a_h
252                 t2 = t1 + EDX
253                 t3 = a_l * b_h
254                 h_res = t2 + t3
255         */
256
257         mul   = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
258         pEDX  = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
259         l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
260
261         mul   = new_rd_Mul(dbg, irg, block, a_h, b_l, l_mode);
262         add   = new_rd_Add(dbg, irg, block, mul, pEDX, l_mode);
263         mul   = new_rd_Mul(dbg, irg, block, a_l, b_h, l_mode);
264         h_res = new_rd_Add(dbg, irg, block, add, mul, l_mode);
265
266         resolve_call(call, l_res, h_res, irg, block);
267
268         return 1;
269 }
270
271 /**
272  * Map a Minus (a_l, a_h)
273  */
274 static int map_Minus(ir_node *call, void *ctx) {
275         ir_graph *irg     = current_ir_graph;
276         dbg_info *dbg     = get_irn_dbg_info(call);
277         ir_node  *block   = get_nodes_block(call);
278         ir_node  **params = get_Call_param_arr(call);
279         ir_type  *method  = get_Call_type(call);
280         ir_node  *a_l     = params[BINOP_Left_Low];
281         ir_node  *a_h     = params[BINOP_Left_High];
282         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
283         ir_node  *l_res, *h_res, *cnst, *res;
284         (void) ctx;
285
286         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
287
288         /* too bad: we need 0 in a register here */
289         cnst  = new_Const_long(l_mode, 0);
290
291         /* l_res = 0 - a_l */
292         /* h_res = 0 - a_h - carry */
293
294         res   = new_rd_ia32_Minus64Bit(dbg, irg, block, cnst, a_l, a_h);
295         l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
296         h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_high_res);
297
298         resolve_call(call, l_res, h_res, irg, block);
299
300         return 1;
301 }
302
303 /**
304  * Map a Abs (a_l, a_h)
305  */
306 static int map_Abs(ir_node *call, void *ctx) {
307         ir_graph *irg     = current_ir_graph;
308         dbg_info *dbg     = get_irn_dbg_info(call);
309         ir_node  *block   = get_nodes_block(call);
310         ir_node  **params = get_Call_param_arr(call);
311         ir_type  *method  = get_Call_type(call);
312         ir_node  *a_l     = params[BINOP_Left_Low];
313         ir_node  *a_h     = params[BINOP_Left_High];
314         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
315         ir_node  *l_res, *h_res, *sign, *sub_l, *sub_h, *res;
316         (void) ctx;
317
318         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
319
320         /*
321                 Code inspired by gcc output :) (although gcc doubles the
322                 operation for t1 as t2 and uses t1 for operations with low part
323                 and t2 for operations with high part which is actually unnecessary
324                 because t1 and t2 represent the same value)
325
326                 t1    = SHRS a_h, 31
327                 t2    = a_l ^ t1
328                 t3    = a_h ^ t1
329                 l_res = t2 - t1
330                 h_res = t3 - t1 - carry
331
332         */
333
334         sign  = new_rd_ia32_l_Sar(dbg, irg, block, a_h, new_Const_long(l_mode, 31), l_mode);
335         sub_l = new_rd_ia32_l_Xor(dbg, irg, block, a_l, sign, l_mode);
336         sub_h = new_rd_ia32_l_Xor(dbg, irg, block, a_h, sign, l_mode);
337         res   = new_rd_ia32_Sub64Bit(dbg, irg, block, sub_l, sub_h, sign, sign);
338         l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
339         h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);
340
341         resolve_call(call, l_res, h_res, irg, block);
342
343         return 1;
344 }
345
346 typedef enum {
347         IA32_INTRINSIC_DIV,
348         IA32_INTRINSIC_MOD,
349 } ia32_intrinsic_divmod_t;
350
351 /**
352  * Maps a Div/Mod (a_l, a_h, b_l, b_h)
353  */
354 static int DivMod_mapper(ir_node *call, void *ctx, ia32_intrinsic_divmod_t dmtp) {
355         ia32_intrinsic_env_t *env = ctx;
356         ir_graph  *irg       = current_ir_graph;
357         dbg_info  *dbg       = get_irn_dbg_info(call);
358         ir_node   *block     = get_nodes_block(call);
359         ir_node   **params   = get_Call_param_arr(call);
360         ir_type   *method    = get_Call_type(call);
361         ir_node   *a_l       = params[BINOP_Left_Low];
362         ir_node   *a_h       = params[BINOP_Left_High];
363         ir_node   *b_l       = params[BINOP_Right_Low];
364         ir_node   *b_h       = params[BINOP_Right_High];
365         ir_mode   *l_mode    = get_type_mode(get_method_res_type(method, 0));
366         int       mode_bytes = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
367         ir_entity *ent_a     = env->irg == irg ? env->ll_div_op1 : NULL;
368         ir_entity *ent_b     = env->irg == irg ? env->ll_div_op2 : NULL;
369         ir_node   *l_res, *h_res, *frame;
370         ir_node   *store_l, *store_h;
371         ir_node   *op_mem[2], *mem, *fa_mem, *fb_mem;
372         ir_node   *fa, *fb, *fres;
373
374         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
375
376         /* allocate memory on frame to store args */
377         if (! ent_a) {
378                 ent_a = env->ll_div_op1 =
379                         frame_alloc_area(get_irg_frame_type(irg), 2 * mode_bytes, 16, 0);
380                 env->irg = irg;
381         }
382
383         if (! ent_b) {
384                 ent_b = env->ll_div_op2 =
385                         frame_alloc_area(get_irg_frame_type(irg), 2 * mode_bytes, 16, 0);
386                 env->irg = irg;
387         }
388
389         frame = get_irg_frame(irg);
390
391         /* store first arg */
392         store_l   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
393         set_ia32_frame_ent(store_l, ent_a);
394         set_ia32_use_frame(store_l);
395         set_ia32_ls_mode(store_l, get_irn_mode(a_l));
396         op_mem[0] = store_l;
397
398         store_h   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
399         set_ia32_frame_ent(store_h, ent_a);
400         add_ia32_am_offs_int(store_h, mode_bytes);
401         set_ia32_use_frame(store_h);
402         set_ia32_ls_mode(store_h, get_irn_mode(a_h));
403         op_mem[1] = store_h;
404
405         mem = new_r_Sync(irg, block, 2, op_mem);
406
407         /* load first arg into FPU */
408         fa = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
409         set_ia32_frame_ent(fa, ent_a);
410         set_ia32_use_frame(fa);
411         set_ia32_ls_mode(fa, mode_D);
412         fa_mem = new_r_Proj(irg, block, fa, mode_M, pn_ia32_l_vfild_M);
413         fa     = new_r_Proj(irg, block, fa, mode_E, pn_ia32_l_vfild_res);
414
415         /* store second arg */
416         store_l   = new_rd_ia32_l_Store(dbg, irg, block, frame, b_l, get_irg_no_mem(irg));
417         set_ia32_frame_ent(store_l, ent_b);
418         set_ia32_use_frame(store_l);
419         set_ia32_ls_mode(store_l, get_irn_mode(b_l));
420         op_mem[0] = store_l;
421
422         store_h   = new_rd_ia32_l_Store(dbg, irg, block, frame, b_h, get_irg_no_mem(irg));
423         set_ia32_frame_ent(store_h, ent_b);
424         add_ia32_am_offs_int(store_h, mode_bytes);
425         set_ia32_use_frame(store_h);
426         set_ia32_ls_mode(store_h, get_irn_mode(b_h));
427         op_mem[1] = store_h;
428
429         mem = new_r_Sync(irg, block, 2, op_mem);
430
431         /* load second arg into FPU */
432         fb = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
433         set_ia32_frame_ent(fb, ent_b);
434         set_ia32_use_frame(fb);
435         set_ia32_ls_mode(fb, mode_D);
436         fb_mem = new_r_Proj(irg, block, fb, mode_M, pn_ia32_l_vfild_M);
437         fb     = new_r_Proj(irg, block, fb, mode_E, pn_ia32_l_vfild_res);
438
439         op_mem[0] = fa_mem;
440         op_mem[1] = fb_mem;
441
442         mem = new_r_Sync(irg, block, 2, op_mem);
443
444         /* perform division */
445         switch (dmtp) {
446                 case IA32_INTRINSIC_DIV:
447                         fres = new_rd_ia32_l_vfdiv(dbg, irg, block, fa, fb);
448                         fres = new_rd_Proj(dbg, irg, block, fres, mode_E, pn_ia32_l_vfdiv_res);
449                         break;
450                 case IA32_INTRINSIC_MOD:
451                         fres = new_rd_ia32_l_vfprem(dbg, irg, block, fa, fb, mode_E);
452                         break;
453                 default:
454                         assert(0);
455         }
456
457         /* store back result, we use ent_a here */
458         fres = new_rd_ia32_l_vfist(dbg, irg, block, frame, fres, mem);
459         set_ia32_frame_ent(fres, ent_a);
460         set_ia32_use_frame(fres);
461         set_ia32_ls_mode(fres, mode_D);
462         mem = fres;
463
464         /* load low part of the result */
465         l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
466         set_ia32_frame_ent(l_res, ent_a);
467         set_ia32_use_frame(l_res);
468         set_ia32_ls_mode(l_res, l_mode);
469         l_res = new_r_Proj(irg, block, l_res, l_mode, pn_ia32_l_Load_res);
470
471         /* load hight part of the result */
472         h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
473         set_ia32_frame_ent(h_res, ent_a);
474         add_ia32_am_offs_int(h_res, mode_bytes);
475         set_ia32_use_frame(h_res);
476         set_ia32_ls_mode(h_res, l_mode);
477         h_res = new_r_Proj(irg, block, h_res, l_mode, pn_ia32_l_Load_res);
478
479         /* lower the call */
480         resolve_call(call, l_res, h_res, irg, block);
481
482         return 1;
483 }
484
485 static int map_Div(ir_node *call, void *ctx) {
486         return DivMod_mapper(call, ctx, IA32_INTRINSIC_DIV);
487 }
488
489 static int map_Mod(ir_node *call, void *ctx) {
490         return DivMod_mapper(call, ctx, IA32_INTRINSIC_MOD);
491 }
492
493 /**
494  * Maps a Conv (a_l, a_h)
495  */
496 static int map_Conv(ir_node *call, void *ctx) {
497         ia32_intrinsic_env_t *env = ctx;
498         ir_graph  *irg        = current_ir_graph;
499         dbg_info  *dbg        = get_irn_dbg_info(call);
500         ir_node   *block      = get_nodes_block(call);
501         ir_node   **params    = get_Call_param_arr(call);
502         ir_type   *method     = get_Call_type(call);
503         int       n           = get_Call_n_params(call);
504         int       gp_bytes    = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
505         ir_entity *ent;
506         ir_node   *l_res, *h_res, *frame, *fres;
507         ir_node   *store_l, *store_h;
508         ir_node   *op_mem[2], *mem;
509
510         if (n == 1) {
511                 /* We have a Conv float -> long long here */
512                 ir_node *a_f        = params[0];
513                 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
514                 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
515
516                 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
517
518                 /* allocate memory on frame to store args */
519                 ent = env->irg == irg ? env->d_ll_conv : NULL;
520                 if (! ent) {
521                         ent      = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
522                         env->irg = irg;
523                 }
524
525                 /* Store arg */
526                 frame = get_irg_frame(irg);
527
528                 /*
529                         Now we create a node to move the value from a XMM register into
530                         x87 FPU because it is unknown here, which FPU is used.
531                         This node is killed in transformation phase when not needed.
532                         Otherwise it is split up into a movsd + fld
533                 */
534                 a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
535                 set_ia32_frame_ent(a_f, ent);
536                 set_ia32_use_frame(a_f);
537                 set_ia32_ls_mode(a_f, mode_D);
538
539                 /* store from FPU as Int */
540                 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
541                 set_ia32_frame_ent(a_f, ent);
542                 set_ia32_use_frame(a_f);
543                 set_ia32_ls_mode(a_f, mode_D);
544                 mem = a_f;
545
546                 /* load low part of the result */
547                 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
548                 set_ia32_frame_ent(l_res, ent);
549                 set_ia32_use_frame(l_res);
550                 set_ia32_ls_mode(l_res, l_res_mode);
551                 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
552
553                 /* load hight part of the result */
554                 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
555                 set_ia32_frame_ent(h_res, ent);
556                 add_ia32_am_offs_int(h_res, gp_bytes);
557                 set_ia32_use_frame(h_res);
558                 set_ia32_ls_mode(h_res, h_res_mode);
559                 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
560
561                 /* lower the call */
562                 resolve_call(call, l_res, h_res, irg, block);
563         }
564         else if (n == 2) {
565                 /* We have a Conv long long -> float here */
566                 ir_node *a_l       = params[BINOP_Left_Low];
567                 ir_node *a_h       = params[BINOP_Left_High];
568                 ir_mode *mode_a_l  = get_irn_mode(a_l);
569                 ir_mode *mode_a_h  = get_irn_mode(a_h);
570                 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
571
572                 assert(! mode_is_float(mode_a_l) && ! mode_is_float(mode_a_h) && "unexpected Conv call");
573
574                 /* allocate memory on frame to store args */
575                 ent = env->irg == irg ? env->ll_d_conv : NULL;
576                 if (! ent) {
577                         ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
578                         env->irg = irg;
579                 }
580
581                 /* Store arg */
582                 frame = get_irg_frame(irg);
583
584                 /* store first arg (low part) */
585                 store_l   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
586                 set_ia32_frame_ent(store_l, ent);
587                 set_ia32_use_frame(store_l);
588                 set_ia32_ls_mode(store_l, get_irn_mode(a_l));
589                 op_mem[0] = store_l;
590
591                 /* store second arg (high part) */
592                 store_h   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
593                 set_ia32_frame_ent(store_h, ent);
594                 add_ia32_am_offs_int(store_h, gp_bytes);
595                 set_ia32_use_frame(store_h);
596                 set_ia32_ls_mode(store_h, get_irn_mode(a_h));
597                 op_mem[1] = store_h;
598
599                 mem = new_r_Sync(irg, block, 2, op_mem);
600
601                 /* Load arg into x87 FPU (implicit convert) */
602                 fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
603                 set_ia32_frame_ent(fres, ent);
604                 set_ia32_use_frame(fres);
605                 set_ia32_ls_mode(fres, mode_D);
606                 mem  = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
607                 fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);
608
609                 /*
610                         Now we create a node to move the loaded value into a XMM
611                         register because it is unknown here, which FPU is used.
612                         This node is killed in transformation phase when not needed.
613                         Otherwise it is split up into a fst + movsd
614                 */
615                 fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
616                 set_ia32_frame_ent(fres, ent);
617                 set_ia32_use_frame(fres);
618                 set_ia32_ls_mode(fres, fres_mode);
619
620                 /* lower the call */
621                 resolve_call(call, fres, NULL, irg, block);
622         }
623         else {
624                 assert(0 && "unexpected Conv call");
625         }
626
627         return 1;
628 }
629
630 /* Ia32 implementation of intrinsic mapping. */
631 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
632                                      const ir_mode *imode, const ir_mode *omode,
633                                      void *context)
634 {
635         i_record      elt;
636         ir_entity     **ent = NULL;
637         i_mapper_func mapper;
638
639         if (! intrinsics)
640                 intrinsics = NEW_ARR_F(i_record, 0);
641
642         switch (get_op_code(op)) {
643         case iro_Add:
644                 ent    = &i_ents[iro_Add];
645                 mapper = map_Add;
646                 break;
647         case iro_Sub:
648                 ent    = &i_ents[iro_Sub];
649                 mapper = map_Sub;
650                 break;
651         case iro_Shl:
652                 ent    = &i_ents[iro_Shl];
653                 mapper = map_Shl;
654                 break;
655         case iro_Shr:
656                 ent    = &i_ents[iro_Shr];
657                 mapper = map_Shr;
658                 break;
659         case iro_Shrs:
660                 ent    = &i_ents[iro_Shrs];
661                 mapper = map_Shrs;
662                 break;
663         case iro_Mul:
664                 ent    = &i_ents[iro_Mul];
665                 mapper = map_Mul;
666                 break;
667         case iro_Minus:
668                 ent    = &i_ents[iro_Minus];
669                 mapper = map_Minus;
670                 break;
671         case iro_Abs:
672                 ent    = &i_ents[iro_Abs];
673                 mapper = map_Abs;
674                 break;
675         case iro_Div:
676                 ent    = &i_ents[iro_Div];
677                 mapper = map_Div;
678                 break;
679         case iro_Mod:
680                 ent    = &i_ents[iro_Mod];
681                 mapper = map_Mod;
682                 break;
683         case iro_Conv:
684                 ent    = &i_ents[iro_Conv];
685                 mapper = map_Conv;
686                 break;
687         default:
688                 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
689                 return def_create_intrinsic_fkt(method, op, imode, omode, context);
690         }
691
692         if (ent && ! *ent) {
693 #define IDENT(s)  new_id_from_chars(s, sizeof(s)-1)
694
695                 ident *id = mangle(IDENT("L"), get_op_ident(op));
696                 *ent = new_entity(get_glob_type(), id, method);
697         }
698
699         elt.i_call.kind     = INTRINSIC_CALL;
700         elt.i_call.i_ent    = *ent;
701         elt.i_call.i_mapper = mapper;
702         elt.i_call.ctx      = context;
703         elt.i_call.link     = NULL;
704
705         ARR_APP1(i_record, intrinsics, elt);
706         return *ent;
707 }