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