- beo_* Opcodes are now defined in irop.h, and no more dynamically allocated
[libfirm] / ir / be / ia32 / ia32_intrinsics.c
1 /*
2  * Copyright (C) 1995-2008 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_Last];
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_Block_phis(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_Phi_next(l_res, h_res);
246         set_Phi_next(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, h_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_Block_phis(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_Phi_next(l_res, h_res);
332         set_Phi_next(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_Block_phis(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_Phi_next(l_res, h_res);
420         set_Phi_next(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, 1));
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         ir_graph  *irg     = current_ir_graph;
672         dbg_info  *dbg     = get_irn_dbg_info(call);
673         ir_node   *block   = get_nodes_block(call);
674         ir_node   **params = get_Call_param_arr(call);
675         ir_type   *method  = get_Call_type(call);
676         int       n        = get_Call_n_params(call);
677         ir_node   *l_res, *h_res;
678         (void) ctx;
679
680         if (n == 1) {
681                 ir_node *float_to_ll;
682
683                 /* We have a Conv float -> long long here */
684                 ir_node *a_f        = params[0];
685                 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
686                 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
687
688                 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
689
690                 float_to_ll = new_rd_ia32_l_FloattoLL(dbg, irg, block, a_f);
691
692                 l_res = new_r_Proj(irg, block, float_to_ll, l_res_mode,
693                                    pn_ia32_l_FloattoLL_res_low);
694                 h_res = new_r_Proj(irg, block, float_to_ll, h_res_mode,
695                                    pn_ia32_l_FloattoLL_res_high);
696
697                 /* lower the call */
698                 resolve_call(call, l_res, h_res, irg, block);
699         } else if (n == 2) {
700                 ir_node *ll_to_float;
701
702                 /* We have a Conv long long -> float here */
703                 ir_node *a_l       = params[BINOP_Left_Low];
704                 ir_node *a_h       = params[BINOP_Left_High];
705                 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
706
707                 assert(! mode_is_float(get_irn_mode(a_l))
708                                 && ! mode_is_float(get_irn_mode(a_h)));
709
710                 ll_to_float = new_rd_ia32_l_LLtoFloat(dbg, irg, block, a_h, a_l,
711                                                       fres_mode);
712
713                 /* lower the call */
714                 resolve_call(call, ll_to_float, NULL, irg, block);
715         } else {
716                 panic("unexpected Conv call %+F", call);
717         }
718
719         return 1;
720 }
721
722 /* Ia32 implementation of intrinsic mapping. */
723 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
724                                      const ir_mode *imode, const ir_mode *omode,
725                                      void *context)
726 {
727         i_record      elt;
728         ir_entity     **ent = NULL;
729         i_mapper_func mapper;
730
731         if (! intrinsics)
732                 intrinsics = NEW_ARR_F(i_record, 0);
733
734         switch (get_op_code(op)) {
735         case iro_Add:
736                 ent    = &i_ents[iro_Add];
737                 mapper = map_Add;
738                 break;
739         case iro_Sub:
740                 ent    = &i_ents[iro_Sub];
741                 mapper = map_Sub;
742                 break;
743         case iro_Shl:
744                 ent    = &i_ents[iro_Shl];
745                 mapper = map_Shl;
746                 break;
747         case iro_Shr:
748                 ent    = &i_ents[iro_Shr];
749                 mapper = map_Shr;
750                 break;
751         case iro_Shrs:
752                 ent    = &i_ents[iro_Shrs];
753                 mapper = map_Shrs;
754                 break;
755         case iro_Mul:
756                 ent    = &i_ents[iro_Mul];
757                 mapper = map_Mul;
758                 break;
759         case iro_Minus:
760                 ent    = &i_ents[iro_Minus];
761                 mapper = map_Minus;
762                 break;
763         case iro_Abs:
764                 ent    = &i_ents[iro_Abs];
765                 mapper = map_Abs;
766                 break;
767         case iro_Div:
768                 ent    = &i_ents[iro_Div];
769                 mapper = map_Div;
770                 break;
771         case iro_Mod:
772                 ent    = &i_ents[iro_Mod];
773                 mapper = map_Mod;
774                 break;
775         case iro_Conv:
776                 ent    = &i_ents[iro_Conv];
777                 mapper = map_Conv;
778                 break;
779         default:
780                 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
781                 return def_create_intrinsic_fkt(method, op, imode, omode, context);
782         }
783
784         if (ent && ! *ent) {
785 #define IDENT(s)  new_id_from_chars(s, sizeof(s)-1)
786
787                 ident *id = mangle(IDENT("L"), get_op_ident(op));
788                 *ent = new_entity(get_glob_type(), id, method);
789         }
790
791         elt.i_call.kind     = INTRINSIC_CALL;
792         elt.i_call.i_ent    = *ent;
793         elt.i_call.i_mapper = mapper;
794         elt.i_call.ctx      = context;
795         elt.i_call.link     = NULL;
796
797         ARR_APP1(i_record, intrinsics, elt);
798         return *ent;
799 }