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