Better detection of sign extension for generating 32x32=64bit multiplication.
[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                 /* store from FPU as Int */
704                 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
705                 set_ia32_frame_ent(a_f, ent);
706                 set_ia32_use_frame(a_f);
707                 set_ia32_ls_mode(a_f, mode_Ls);
708                 mem = a_f;
709
710                 /* load low part of the result */
711                 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
712                 set_ia32_frame_ent(l_res, ent);
713                 set_ia32_use_frame(l_res);
714                 set_ia32_ls_mode(l_res, l_res_mode);
715                 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
716
717                 /* load hight part of the result */
718                 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
719                 set_ia32_frame_ent(h_res, ent);
720                 add_ia32_am_offs_int(h_res, gp_bytes);
721                 set_ia32_use_frame(h_res);
722                 set_ia32_ls_mode(h_res, h_res_mode);
723                 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
724
725                 /* lower the call */
726                 resolve_call(call, l_res, h_res, irg, block);
727         }
728         else if (n == 2) {
729                 /* We have a Conv long long -> float here */
730                 ir_node *a_l       = params[BINOP_Left_Low];
731                 ir_node *a_h       = params[BINOP_Left_High];
732                 ir_mode *mode_a_l  = get_irn_mode(a_l);
733                 ir_mode *mode_a_h  = get_irn_mode(a_h);
734                 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
735
736                 assert(! mode_is_float(mode_a_l) && ! mode_is_float(mode_a_h) && "unexpected Conv call");
737
738                 /* allocate memory on frame to store args */
739                 ent = env->irg == irg ? env->ll_d_conv : NULL;
740                 if (! ent) {
741                         ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
742                         env->irg = irg;
743                 }
744
745                 /* Store arg */
746                 frame = get_irg_frame(irg);
747
748                 /* store first arg (low part) */
749                 store_l   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
750                 set_ia32_frame_ent(store_l, ent);
751                 set_ia32_use_frame(store_l);
752                 set_ia32_ls_mode(store_l, get_irn_mode(a_l));
753                 op_mem[0] = store_l;
754
755                 /* store second arg (high part) */
756                 store_h   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
757                 set_ia32_frame_ent(store_h, ent);
758                 add_ia32_am_offs_int(store_h, gp_bytes);
759                 set_ia32_use_frame(store_h);
760                 set_ia32_ls_mode(store_h, get_irn_mode(a_h));
761                 op_mem[1] = store_h;
762
763                 mem = new_r_Sync(irg, block, 2, op_mem);
764
765                 /* Load arg into x87 FPU (implicit convert) */
766                 fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
767                 set_ia32_frame_ent(fres, ent);
768                 set_ia32_use_frame(fres);
769                 set_ia32_ls_mode(fres, mode_D);
770                 mem  = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
771                 fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);
772
773                 /*
774                         Now we create a node to move the loaded value into a XMM
775                         register because it is unknown here, which FPU is used.
776                         This node is killed in transformation phase when not needed.
777                         Otherwise it is split up into a fst + movsd
778                 */
779                 fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
780                 set_ia32_frame_ent(fres, ent);
781                 set_ia32_use_frame(fres);
782                 set_ia32_ls_mode(fres, fres_mode);
783
784                 /* lower the call */
785                 resolve_call(call, fres, NULL, irg, block);
786         }
787         else {
788                 assert(0 && "unexpected Conv call");
789         }
790
791         return 1;
792 }
793
794 /* Ia32 implementation of intrinsic mapping. */
795 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
796                                      const ir_mode *imode, const ir_mode *omode,
797                                      void *context)
798 {
799         i_record      elt;
800         ir_entity     **ent = NULL;
801         i_mapper_func mapper;
802
803         if (! intrinsics)
804                 intrinsics = NEW_ARR_F(i_record, 0);
805
806         switch (get_op_code(op)) {
807         case iro_Add:
808                 ent    = &i_ents[iro_Add];
809                 mapper = map_Add;
810                 break;
811         case iro_Sub:
812                 ent    = &i_ents[iro_Sub];
813                 mapper = map_Sub;
814                 break;
815         case iro_Shl:
816                 ent    = &i_ents[iro_Shl];
817                 mapper = map_Shl;
818                 break;
819         case iro_Shr:
820                 ent    = &i_ents[iro_Shr];
821                 mapper = map_Shr;
822                 break;
823         case iro_Shrs:
824                 ent    = &i_ents[iro_Shrs];
825                 mapper = map_Shrs;
826                 break;
827         case iro_Mul:
828                 ent    = &i_ents[iro_Mul];
829                 mapper = map_Mul;
830                 break;
831         case iro_Minus:
832                 ent    = &i_ents[iro_Minus];
833                 mapper = map_Minus;
834                 break;
835         case iro_Abs:
836                 ent    = &i_ents[iro_Abs];
837                 mapper = map_Abs;
838                 break;
839         case iro_Div:
840                 ent    = &i_ents[iro_Div];
841                 mapper = map_Div;
842                 break;
843         case iro_Mod:
844                 ent    = &i_ents[iro_Mod];
845                 mapper = map_Mod;
846                 break;
847         case iro_Conv:
848                 ent    = &i_ents[iro_Conv];
849                 mapper = map_Conv;
850                 break;
851         default:
852                 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
853                 return def_create_intrinsic_fkt(method, op, imode, omode, context);
854         }
855
856         if (ent && ! *ent) {
857 #define IDENT(s)  new_id_from_chars(s, sizeof(s)-1)
858
859                 ident *id = mangle(IDENT("L"), get_op_ident(op));
860                 *ent = new_entity(get_glob_type(), id, method);
861         }
862
863         elt.i_call.kind     = INTRINSIC_CALL;
864         elt.i_call.i_ent    = *ent;
865         elt.i_call.i_mapper = mapper;
866         elt.i_call.ctx      = context;
867         elt.i_call.link     = NULL;
868
869         ARR_APP1(i_record, intrinsics, elt);
870         return *ent;
871 }