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