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