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