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