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