fix cltd
[libfirm] / ir / be / ia32 / ia32_intrinsics.c
1 /*
2  * Copyright (C) 1995-2008 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 #include "config.h"
28
29 #include "iredges.h"
30 #include "irgmod.h"
31 #include "irop.h"
32 #include "irnode_t.h"
33 #include "ircons.h"
34 #include "irprog_t.h"
35 #include "lowering.h"
36 #include "array.h"
37 #include "error.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_Last + 1];
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  * Reroute edges from the pn_Call_T_result proj of a call.
67  *
68  * @param proj   the pn_Call_T_result Proj
69  * @param l_res  the lower 32 bit result
70  * @param h_res  the upper 32 bit result or NULL
71  * @param irg    the graph to replace on
72  */
73 static void reroute_result(ir_node *proj, ir_node *l_res, ir_node *h_res, ir_graph *irg) {
74         const ir_edge_t *edge, *next;
75
76         foreach_out_edge_safe(proj, edge, next) {
77                 ir_node *proj = get_edge_src_irn(edge);
78                 long    pn    = get_Proj_proj(proj);
79
80                 if (pn == 0) {
81                         edges_reroute(proj, l_res, irg);
82                 } else if (pn == 1 && h_res != NULL) {
83                         edges_reroute(proj, h_res, irg);
84                 } else {
85                         panic("Unsupported Result-Proj from Call found");
86                 }
87         }
88 }
89
90 /**
91  * Replace a call be a tuple of l_res, h_res.
92  *
93  * @param call   the call node to replace
94  * @param l_res  the lower 32 bit result
95  * @param h_res  the upper 32 bit result or NULL
96  * @param irg    the graph to replace on
97  * @param block  the block to replace on (always the call block)
98  */
99 static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block) {
100         ir_node *jmp, *res, *in[2];
101         ir_node *bad   = get_irg_bad(irg);
102         ir_node *nomem = get_irg_no_mem(irg);
103         int     old_cse;
104
105         if (edges_activated(irg)) {
106                 /* use rerouting to prevent some warning in the backend */
107                 const ir_edge_t *edge, *next;
108
109                 foreach_out_edge_safe(call, edge, next) {
110                         ir_node *proj = get_edge_src_irn(edge);
111                         pn_Call pn    = get_Proj_proj(proj);
112
113                         switch (pn) {
114                         case pn_Call_X_regular:
115                                 /* Beware:
116                                  * We do not check here if this call really has exception and regular Proj's.
117                                  * new_r_Jmp might than be CSEd with the real exit jmp and then bad things happen
118                                  * (in movgen.c from 186.crafty for example).
119                                  * So be sure the newly created Jmp cannot CSE.
120                                  */
121                                 old_cse = get_opt_cse();
122                                 set_opt_cse(0);
123                                 jmp = new_r_Jmp(block);
124                                 set_opt_cse(old_cse);
125                                 edges_reroute(proj, jmp, irg);
126                                 break;
127
128                         case pn_Call_X_except:
129                         case pn_Call_P_value_res_base:
130                                 /* should not happen here */
131                                 edges_reroute(proj, bad, irg);
132                                 break;
133                         case pn_Call_M_except:
134                                 /* should not happen here */
135                                 edges_reroute(proj, nomem, irg);
136                                 break;
137                         case pn_Call_T_result:
138                                 reroute_result(proj, l_res, h_res, irg);
139                                 break;
140                         default:
141                                 panic("Wrong Proj from Call");
142                         }
143                         kill_node(proj);
144                 }
145                 kill_node(call);
146         } else {
147                 /* no edges, build Tuple */
148                 if (h_res == NULL)
149                         res = l_res;
150                 else {
151                         in[0] = l_res;
152                         in[1] = h_res;
153                         res = new_r_Tuple(block, 2, in);
154                 }
155
156                 turn_into_tuple(call, pn_Call_max);
157                 set_Tuple_pred(call, pn_Call_M_regular,        nomem);
158                 /*
159                  * Beware:
160                  * We do not check here if this call really has exception and regular Proj's.
161                  * new_r_Jmp might than be CSEd with the real exit jmp and then bad things happen
162                  * (in movgen.c from 186.crafty for example).
163                  * So be sure the newly created Jmp cannot CSE.
164                  */
165                 old_cse = get_opt_cse();
166                 set_opt_cse(0);
167                 jmp = new_r_Jmp(block);
168                 set_opt_cse(old_cse);
169
170                 set_Tuple_pred(call, pn_Call_X_regular,        jmp);
171                 set_Tuple_pred(call, pn_Call_X_except,         bad);
172                 set_Tuple_pred(call, pn_Call_T_result,         res);
173                 set_Tuple_pred(call, pn_Call_M_except,         nomem);
174                 set_Tuple_pred(call, pn_Call_P_value_res_base, bad);
175         }
176 }
177
178 /**
179  * Map an Add (a_l, a_h, b_l, b_h)
180  */
181 static int map_Add(ir_node *call, void *ctx) {
182         dbg_info *dbg        = get_irn_dbg_info(call);
183         ir_node  *block      = get_nodes_block(call);
184         ir_node  **params    = get_Call_param_arr(call);
185         ir_type  *method     = get_Call_type(call);
186         ir_node  *a_l        = params[BINOP_Left_Low];
187         ir_node  *a_h        = params[BINOP_Left_High];
188         ir_node  *b_l        = params[BINOP_Right_Low];
189         ir_node  *b_h        = params[BINOP_Right_High];
190         ir_mode  *l_mode     = get_type_mode(get_method_res_type(method, 0));
191         ir_mode  *h_mode     = get_type_mode(get_method_res_type(method, 1));
192         ir_mode  *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
193         ir_node  *add_low, *add_high, *flags;
194         ir_node  *l_res, *h_res;
195         (void) ctx;
196
197         /* l_res = a_l + b_l */
198         /* h_res = a_h + b_h + carry */
199
200         add_low  = new_bd_ia32_l_Add(dbg, block, a_l, b_l, mode_T);
201         flags    = new_r_Proj(block, add_low, mode_flags, pn_ia32_flags);
202         add_high = new_bd_ia32_l_Adc(dbg, block, a_h, b_h, flags, h_mode);
203
204         l_res = new_r_Proj(block, add_low, l_mode, pn_ia32_res);
205         h_res = add_high;
206
207         resolve_call(call, l_res, h_res, current_ir_graph, block);
208         return 1;
209 }
210
211 /**
212  * Map a Sub (a_l, a_h, b_l, b_h)
213  */
214 static int map_Sub(ir_node *call, void *ctx)
215 {
216         dbg_info *dbg        = get_irn_dbg_info(call);
217         ir_node  *block      = get_nodes_block(call);
218         ir_node  **params    = get_Call_param_arr(call);
219         ir_type  *method     = get_Call_type(call);
220         ir_node  *a_l        = params[BINOP_Left_Low];
221         ir_node  *a_h        = params[BINOP_Left_High];
222         ir_node  *b_l        = params[BINOP_Right_Low];
223         ir_node  *b_h        = params[BINOP_Right_High];
224         ir_mode  *l_mode     = get_type_mode(get_method_res_type(method, 0));
225         ir_mode  *h_mode     = get_type_mode(get_method_res_type(method, 1));
226         ir_mode  *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
227         ir_node  *sub_low, *sub_high, *flags;
228         ir_node  *l_res, *h_res;
229         (void) ctx;
230
231         /* l_res = a_l - b_l */
232         /* h_res = a_h - b_h - carry */
233
234         sub_low  = new_bd_ia32_l_Sub(dbg, block, a_l, b_l, mode_T);
235         flags    = new_r_Proj(block, sub_low, mode_flags, pn_ia32_flags);
236         sub_high = new_bd_ia32_l_Sbb(dbg, block, a_h, b_h, flags, h_mode);
237
238         l_res = new_r_Proj( block, sub_low, l_mode, pn_ia32_res);
239         h_res = sub_high;
240
241         resolve_call(call, l_res, h_res, current_ir_graph, block);
242         return 1;
243 }
244
245 /**
246  * Map a Shl (a_l, a_h, count)
247  */
248 static int map_Shl(ir_node *call, void *ctx) {
249         ir_graph *irg     = current_ir_graph;
250         dbg_info *dbg     = get_irn_dbg_info(call);
251         ir_node  *block   = get_nodes_block(call);
252         ir_node  **params = get_Call_param_arr(call);
253         ir_type  *method  = get_Call_type(call);
254         ir_node  *a_l     = params[BINOP_Left_Low];
255         ir_node  *a_h     = params[BINOP_Left_High];
256         ir_node  *cnt     = params[BINOP_Right_Low];
257         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
258         ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
259         ir_mode  *c_mode;
260         ir_node  *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
261         (void) ctx;
262
263         if (is_Const(cnt)) {
264                 /* the shift count is a const, create better code */
265                 tarval *tv = get_Const_tarval(cnt);
266
267                 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
268                         /* simplest case: shift only the lower bits. Note that there is no
269                            need to reduce the constant here, this is done by the hardware.  */
270                         ir_node *conv = new_rd_Conv(dbg, block, a_l, h_mode);
271                         h_res = new_rd_Shl(dbg, block, conv, cnt, h_mode);
272                         l_res = new_rd_Const(dbg, irg, get_mode_null(l_mode));
273
274                 } else {
275                         /* h_res = SHLD a_h, a_l, cnt */
276                         h_res = new_bd_ia32_l_ShlD(dbg, block, a_h, a_l, cnt, h_mode);
277
278                         /* l_res = SHL a_l, cnt */
279                         l_res = new_bd_ia32_l_ShlDep(dbg, block, a_l, cnt, h_res, l_mode);
280                 }
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         /* h_res = SHLD a_h, a_l, cnt */
290         h1 = new_bd_ia32_l_ShlD(dbg, upper, a_h, a_l, cnt, h_mode);
291
292         /* l_res = SHL a_l, cnt */
293         l1 = new_bd_ia32_l_ShlDep(dbg, upper, a_l, cnt, h1, l_mode);
294
295         c_mode = get_irn_mode(cnt);
296         irn    = new_r_Const_long(irg, c_mode, 32);
297         irn    = new_rd_And(dbg, upper, cnt, irn, c_mode);
298         irn    = new_rd_Cmp(dbg, upper, irn, new_r_Const(irg, get_mode_null(c_mode)));
299         irn    = new_r_Proj(upper, irn, mode_b, pn_Cmp_Eq);
300         cond   = new_rd_Cond(dbg, upper, irn);
301
302         in[0]  = new_r_Proj(upper, cond, mode_X, pn_Cond_true);
303         in[1]  = new_r_Proj(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         h2      = new_rd_Conv(dbg, n_block, l1, h_mode);
308         l2      = new_r_Const(irg, get_mode_null(l_mode));
309         in[1]   = new_r_Jmp(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(block, 2, in, l_mode);
316         set_Block_phis(block, l_res);
317
318         in[0] = h1;
319         in[1] = h2;
320         h_res = new_r_Phi(block, 2, in, h_mode);
321         set_Phi_next(l_res, h_res);
322         set_Phi_next(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 Shr (a_l, a_h, count)
335  */
336 static int map_Shr(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, block, a_h, l_mode);
359                         h_res = new_rd_Const(dbg, irg, get_mode_null(h_mode));
360                         l_res = new_rd_Shr(dbg, block, conv, cnt, l_mode);
361                 } else {
362                         /* l_res = SHRD a_h:a_l, cnt */
363                         l_res = new_bd_ia32_l_ShrD(dbg, block, a_l, a_h, cnt, l_mode);
364
365                         /* h_res = SHR a_h, cnt */
366                         h_res = new_bd_ia32_l_ShrDep(dbg, block, a_h, cnt, l_res, h_mode);
367                 }
368                 resolve_call(call, l_res, h_res, irg, block);
369                 return 1;
370         }
371
372         part_block(call);
373         upper = get_nodes_block(call);
374
375         /* l_res = SHRD a_h:a_l, cnt */
376         l1 = new_bd_ia32_l_ShrD(dbg, upper, a_l, a_h, cnt, l_mode);
377
378         /* h_res = SHR a_h, cnt */
379         h1 = new_bd_ia32_l_ShrDep(dbg, upper, a_h, cnt, l1, h_mode);
380
381         c_mode = get_irn_mode(cnt);
382         irn    = new_r_Const_long(irg, c_mode, 32);
383         irn    = new_rd_And(dbg, upper, cnt, irn, c_mode);
384         irn    = new_rd_Cmp(dbg, upper, irn, new_r_Const(irg, get_mode_null(c_mode)));
385         irn    = new_r_Proj(upper, irn, mode_b, pn_Cmp_Eq);
386         cond   = new_rd_Cond(dbg, upper, irn);
387
388         in[0]  = new_r_Proj(upper, cond, mode_X, pn_Cond_true);
389         in[1]  = new_r_Proj(upper, cond, mode_X, pn_Cond_false);
390
391         /* the block for cnt >= 32 */
392         n_block = new_rd_Block(dbg, irg, 1, &in[1]);
393         l2      = new_rd_Conv(dbg, n_block, h1, l_mode);
394         h2      = new_r_Const(irg, get_mode_null(h_mode));
395         in[1]   = new_r_Jmp(n_block);
396
397         set_irn_in(block, 2, in);
398
399         in[0] = l1;
400         in[1] = l2;
401         l_res = new_r_Phi(block, 2, in, l_mode);
402         set_Block_phis(block, l_res);
403
404         in[0] = h1;
405         in[1] = h2;
406         h_res = new_r_Phi(block, 2, in, h_mode);
407         set_Phi_next(l_res, h_res);
408         set_Phi_next(h_res, NULL);
409
410         /* move it down */
411         set_nodes_block(call, block);
412         for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
413                 set_nodes_block(irn, block);
414
415         resolve_call(call, l_res, h_res, irg, block);
416         return 1;
417 }
418
419 /**
420  * Map a Shrs (a_l, a_h, count)
421  */
422 static int map_Shrs(ir_node *call, void *ctx) {
423         ir_graph *irg     = current_ir_graph;
424         dbg_info *dbg     = get_irn_dbg_info(call);
425         ir_node  *block   = get_nodes_block(call);
426         ir_node  **params = get_Call_param_arr(call);
427         ir_type  *method  = get_Call_type(call);
428         ir_node  *a_l     = params[BINOP_Left_Low];
429         ir_node  *a_h     = params[BINOP_Left_High];
430         ir_node  *cnt     = params[BINOP_Right_Low];
431         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
432         ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
433         ir_mode  *c_mode;
434         ir_node  *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
435         (void) ctx;
436
437         if (is_Const(cnt)) {
438                 /* the shift count is a const, create better code */
439                 tarval *tv = get_Const_tarval(cnt);
440
441                 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
442                         /* simplest case: shift only the higher bits. Note that there is no
443                            need to reduce the constant here, this is done by the hardware.  */
444                         ir_node *conv    = new_rd_Conv(dbg, block, a_h, l_mode);
445                         ir_mode *c_mode  = get_irn_mode(cnt);
446
447                         h_res = new_rd_Shrs(dbg, block, a_h, new_r_Const_long(irg, c_mode, 31), h_mode);
448                         l_res = new_rd_Shrs(dbg, block, conv, cnt, l_mode);
449                 } else {
450                         /* l_res = SHRD a_h:a_l, cnt */
451                         l_res = new_bd_ia32_l_ShrD(dbg, block, a_l, a_h, cnt, l_mode);
452
453                         /* h_res = SAR a_h, cnt */
454                         h_res = new_bd_ia32_l_SarDep(dbg, block, a_h, cnt, l_res, h_mode);
455                 }
456                 resolve_call(call, l_res, h_res, irg, block);
457                 return 1;
458         }
459
460         part_block(call);
461         upper = get_nodes_block(call);
462
463         /* l_res = SHRD a_h:a_l, cnt */
464         l1 = new_bd_ia32_l_ShrD(dbg, upper, a_l, a_h, cnt, l_mode);
465
466         /* h_res = SAR a_h, cnt */
467         h1 = new_bd_ia32_l_SarDep(dbg, upper, a_h, cnt, l1, h_mode);
468
469         c_mode = get_irn_mode(cnt);
470         irn    = new_r_Const_long(irg, c_mode, 32);
471         irn    = new_rd_And(dbg, upper, cnt, irn, c_mode);
472         irn    = new_rd_Cmp(dbg, upper, irn, new_r_Const(irg, get_mode_null(c_mode)));
473         irn    = new_r_Proj(upper, irn, mode_b, pn_Cmp_Eq);
474         cond   = new_rd_Cond(dbg, upper, irn);
475
476         in[0]  = new_r_Proj(upper, cond, mode_X, pn_Cond_true);
477         in[1]  = new_r_Proj(upper, cond, mode_X, pn_Cond_false);
478
479         /* the block for cnt >= 32 */
480         n_block = new_rd_Block(dbg, irg, 1, &in[1]);
481         l2      = new_rd_Conv(dbg, n_block, h1, l_mode);
482         h2      = new_rd_Shrs(dbg, n_block, a_h, new_r_Const_long(irg, c_mode, 31), h_mode);
483         in[1]   = new_r_Jmp(n_block);
484
485         set_irn_in(block, 2, in);
486
487         in[0] = l1;
488         in[1] = l2;
489         l_res = new_r_Phi(block, 2, in, l_mode);
490         set_Block_phis(block, l_res);
491
492         in[0] = h1;
493         in[1] = h2;
494         h_res = new_r_Phi(block, 2, in, h_mode);
495         set_Phi_next(l_res, h_res);
496         set_Phi_next(h_res, NULL);
497
498         /* move it down */
499         set_nodes_block(call, block);
500         for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
501                 set_nodes_block(irn, block);
502
503         resolve_call(call, l_res, h_res, irg, block);
504         return 1;
505 }
506
507 /**
508  * Checks where node high is a sign extension of low.
509  */
510 static int is_sign_extend(ir_node *low, ir_node *high)
511 {
512         if (is_Shrs(high)) {
513                 ir_node *high_l;
514                 ir_node *high_r;
515                 tarval  *shift_count;
516
517                 high_r = get_Shrs_right(high);
518                 if (!is_Const(high_r)) return 0;
519
520                 shift_count = get_Const_tarval(high_r);
521                 if (!tarval_is_long(shift_count))       return 0;
522                 if (get_tarval_long(shift_count) != 31) return 0;
523
524                 high_l = get_Shrs_left(high);
525
526                 if (is_Conv(low)    && get_Conv_op(low)    == high_l) return 1;
527                 if (is_Conv(high_l) && get_Conv_op(high_l) == low)    return 1;
528         } else if (is_Const(low) && is_Const(high)) {
529                 tarval *tl = get_Const_tarval(low);
530                 tarval *th = get_Const_tarval(high);
531
532                 if (tarval_is_long(th) && tarval_is_long(tl)) {
533                         long l = get_tarval_long(tl);
534                         long h = get_tarval_long(th);
535
536                         return (h == 0  && l >= 0) || (h == -1 && l <  0);
537                 }
538         }
539
540         return 0;
541 }
542
543 /**
544  * Map a Mul (a_l, a_h, b_l, b_h)
545  */
546 static int map_Mul(ir_node *call, void *ctx) {
547         dbg_info *dbg     = get_irn_dbg_info(call);
548         ir_node  *block   = get_nodes_block(call);
549         ir_node  **params = get_Call_param_arr(call);
550         ir_type  *method  = get_Call_type(call);
551         ir_node  *a_l     = params[BINOP_Left_Low];
552         ir_node  *a_h     = params[BINOP_Left_High];
553         ir_node  *b_l     = params[BINOP_Right_Low];
554         ir_node  *b_h     = params[BINOP_Right_High];
555         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
556         ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
557         ir_node  *l_res, *h_res, *mul, *pEDX, *add;
558         (void) ctx;
559
560         /*
561                 EDX:EAX = a_l * b_l
562                 l_res   = EAX
563
564                 t1 = b_l * a_h
565                 t2 = t1 + EDX
566                 t3 = a_l * b_h
567                 h_res = t2 + t3
568         */
569
570         /* handle the often used case of 32x32=64 mul */
571         if (is_sign_extend(a_l, a_h) && is_sign_extend(b_l, b_h)) {
572                 mul   = new_bd_ia32_l_IMul(dbg, block, a_l, b_l);
573                 h_res = new_rd_Proj(dbg, block, mul, h_mode, pn_ia32_l_IMul_res_high);
574                 l_res = new_rd_Proj(dbg, block, mul, l_mode, pn_ia32_l_IMul_res_low);
575         } else {
576                 /* note that zero extension is handled hare efficiently */
577                 mul   = new_bd_ia32_l_Mul(dbg, block, a_l, b_l);
578                 pEDX  = new_rd_Proj(dbg, block, mul, h_mode, pn_ia32_l_Mul_res_high);
579                 l_res = new_rd_Proj(dbg, block, mul, l_mode, pn_ia32_l_Mul_res_low);
580
581                 b_l   = new_rd_Conv(dbg, block, b_l, h_mode);
582                 mul   = new_rd_Mul( dbg, block, a_h, b_l, h_mode);
583                 add   = new_rd_Add( dbg, block, mul, pEDX, h_mode);
584                 a_l   = new_rd_Conv(dbg, block, a_l, h_mode);
585                 mul   = new_rd_Mul( dbg, block, a_l, b_h, h_mode);
586                 h_res = new_rd_Add( dbg, block, add, mul, h_mode);
587         }
588         resolve_call(call, l_res, h_res, current_ir_graph, block);
589
590         return 1;
591 }
592
593 /**
594  * Map a Minus (a_l, a_h)
595  */
596 static int map_Minus(ir_node *call, void *ctx) {
597         dbg_info *dbg     = get_irn_dbg_info(call);
598         ir_node  *block   = get_nodes_block(call);
599         ir_node  **params = get_Call_param_arr(call);
600         ir_type  *method  = get_Call_type(call);
601         ir_node  *a_l     = params[BINOP_Left_Low];
602         ir_node  *a_h     = params[BINOP_Left_High];
603         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
604         ir_mode  *h_mode  = get_type_mode(get_method_res_type(method, 1));
605         ir_node  *l_res, *h_res, *res;
606         (void) ctx;
607
608         res   = new_bd_ia32_Minus64Bit(dbg, block, a_l, a_h);
609         l_res = new_r_Proj(block, res, l_mode, pn_ia32_Minus64Bit_low_res);
610         h_res = new_r_Proj(block, res, h_mode, pn_ia32_Minus64Bit_high_res);
611
612         resolve_call(call, l_res, h_res, current_ir_graph, block);
613
614         return 1;
615 }
616
617 /**
618  * Map a Abs (a_l, a_h)
619  */
620 static int map_Abs(ir_node *call, void *ctx) {
621         dbg_info *dbg        = get_irn_dbg_info(call);
622         ir_node  *block      = get_nodes_block(call);
623         ir_node  **params    = get_Call_param_arr(call);
624         ir_type  *method     = get_Call_type(call);
625         ir_node  *a_l        = params[BINOP_Left_Low];
626         ir_node  *a_h        = params[BINOP_Left_High];
627         ir_mode  *l_mode     = get_type_mode(get_method_res_type(method, 0));
628         ir_mode  *h_mode     = get_type_mode(get_method_res_type(method, 1));
629         ir_mode  *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
630         ir_node  *l_res, *h_res, *sign, *sub_l, *sub_h;
631         ir_node  *sign_l;
632         ir_node  *l_sub;
633         ir_node  *flags;
634         (void) ctx;
635
636         /*
637                 Code inspired by gcc output :) (although gcc doubles the
638                 operation for t1 as t2 and uses t1 for operations with low part
639                 and t2 for operations with high part which is actually unnecessary
640                 because t1 and t2 represent the same value)
641
642                 t1    = SHRS a_h, 31
643                 t2    = a_l ^ t1
644                 t3    = a_h ^ t1
645                 l_res = t2 - t1
646                 h_res = t3 - t1 - carry
647
648         */
649
650         /* TODO: give a hint to the backend somehow to not create a cltd here... */
651         sign   = new_rd_Shrs(dbg, block, a_h, new_Const_long(l_mode, 31), h_mode);
652         sign_l = new_rd_Conv(dbg, block, sign, l_mode);
653         sub_l  = new_rd_Eor(dbg, block, a_l, sign_l, l_mode);
654         sub_h  = new_rd_Eor(dbg, block, a_h, sign,   h_mode);
655
656         l_sub  = new_bd_ia32_l_Sub(dbg, block, sub_l, sign_l, mode_T);
657         l_res  = new_r_Proj(block, l_sub, l_mode,     pn_ia32_res);
658         flags  = new_r_Proj(block, l_sub, mode_flags, pn_ia32_flags);
659         h_res  = new_bd_ia32_l_Sbb(dbg, block, sub_h, sign, flags, h_mode);
660
661         resolve_call(call, l_res, h_res, current_ir_graph, block);
662
663         return 1;
664 }
665
666 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
667
668 /**
669  * Maps a Div. Change into a library call.
670  */
671 static int map_Div(ir_node *call, void *ctx) {
672         ia32_intrinsic_env_t *env = ctx;
673         ir_type   *method    = get_Call_type(call);
674         ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
675         ir_node   *ptr;
676         ir_entity *ent;
677         symconst_symbol sym;
678
679         if (mode_is_signed(h_mode)) {
680                 /* 64bit signed Division */
681                 ent = env->divdi3;
682                 if (ent == NULL) {
683                         /* create library entity */
684                         ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
685                         set_entity_visibility(ent, visibility_external_allocated);
686                         set_entity_ld_ident(ent, ID("__divdi3"));
687                 }
688         } else {
689                 /* 64bit unsigned Division */
690                 ent = env->udivdi3;
691                 if (ent == NULL) {
692                         /* create library entity */
693                         ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
694                         set_entity_visibility(ent, visibility_external_allocated);
695                         set_entity_ld_ident(ent, ID("__udivdi3"));
696                 }
697         }
698         sym.entity_p = ent;
699         ptr = get_Call_ptr(call);
700         set_SymConst_symbol(ptr, sym);
701         return 1;
702 }
703
704 /**
705  * Maps a Mod. Change into a library call
706  */
707 static int map_Mod(ir_node *call, void *ctx) {
708         ia32_intrinsic_env_t *env = ctx;
709         ir_type   *method    = get_Call_type(call);
710         ir_mode   *h_mode    = get_type_mode(get_method_res_type(method, 1));
711         ir_node   *ptr;
712         ir_entity *ent;
713         symconst_symbol sym;
714
715         if (mode_is_signed(h_mode)) {
716                 /* 64bit signed Modulo */
717                 ent = env->moddi3;
718                 if (ent == NULL) {
719                         /* create library entity */
720                         ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
721                         set_entity_visibility(ent, visibility_external_allocated);
722                         set_entity_ld_ident(ent, ID("__moddi3"));
723                 }
724         } else {
725                 /* 64bit signed Modulo */
726                 ent = env->umoddi3;
727                 if (ent == NULL) {
728                         /* create library entity */
729                         ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
730                         set_entity_visibility(ent, visibility_external_allocated);
731                         set_entity_ld_ident(ent, ID("__umoddi3"));
732                 }
733         }
734         sym.entity_p = ent;
735         ptr = get_Call_ptr(call);
736         set_SymConst_symbol(ptr, sym);
737         return 1;
738 }
739
740 /**
741  * Maps a Conv.
742  */
743 static int map_Conv(ir_node *call, void *ctx) {
744         ir_graph  *irg     = current_ir_graph;
745         dbg_info  *dbg     = get_irn_dbg_info(call);
746         ir_node   *block   = get_nodes_block(call);
747         ir_node   **params = get_Call_param_arr(call);
748         ir_type   *method  = get_Call_type(call);
749         int       n        = get_Call_n_params(call);
750         ir_node   *l_res, *h_res;
751         (void) ctx;
752
753         if (n == 1) {
754                 ir_node *float_to_ll;
755
756                 /* We have a Conv float -> long long here */
757                 ir_node *a_f        = params[0];
758                 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
759                 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
760
761                 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
762
763                 if (mode_is_signed(h_res_mode)) {
764                         /* convert from float to signed 64bit */
765                         float_to_ll = new_bd_ia32_l_FloattoLL(dbg, block, a_f);
766
767                         l_res = new_r_Proj(block, float_to_ll, l_res_mode,
768                                                            pn_ia32_l_FloattoLL_res_low);
769                         h_res = new_r_Proj(block, float_to_ll, h_res_mode,
770                                                            pn_ia32_l_FloattoLL_res_high);
771                 } else {
772                         /* convert from float to signed 64bit */
773                         ir_mode *flt_mode = get_irn_mode(a_f);
774                         tarval  *flt_tv   = new_tarval_from_str("9223372036854775808", 19, flt_mode);
775                         ir_node *flt_corr = new_Const(flt_tv);
776                         ir_node *lower_blk = block;
777                         ir_node *upper_blk;
778                         ir_node *cmp, *proj, *cond, *blk, *int_phi, *flt_phi;
779                         ir_node *in[2];
780
781                         part_block(call);
782                         upper_blk = get_nodes_block(call);
783
784                         cmp   = new_rd_Cmp(dbg, upper_blk, a_f, flt_corr);
785                         proj  = new_r_Proj(upper_blk, cmp, mode_b, pn_Cmp_Lt);
786                         cond  = new_rd_Cond(dbg, upper_blk, proj);
787                         in[0] = new_r_Proj(upper_blk, cond, mode_X, pn_Cond_true);
788                         in[1] = new_r_Proj(upper_blk, cond, mode_X, pn_Cond_false);
789                         blk   = new_r_Block(irg, 1, &in[1]);
790                         in[1] = new_r_Jmp(blk);
791
792                         set_irn_in(lower_blk, 2, in);
793
794                         /* create to Phis */
795                         in[0] = new_Const(get_mode_null(h_res_mode));
796                         in[1] = new_Const_long(h_res_mode, 0x80000000);
797
798                         int_phi = new_r_Phi(lower_blk, 2, in, h_res_mode);
799
800                         in[0] = a_f;
801                         in[1] = new_rd_Sub(dbg, upper_blk, a_f, flt_corr, flt_mode);
802
803                         flt_phi = new_r_Phi(lower_blk, 2, in, flt_mode);
804
805                         /* fix Phi links for next part_block() */
806                         set_Block_phis(lower_blk, int_phi);
807                         set_Phi_next(int_phi, flt_phi);
808                         set_Phi_next(flt_phi, NULL);
809
810                         float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);
811
812                         l_res = new_r_Proj(lower_blk, float_to_ll, l_res_mode,
813                                                            pn_ia32_l_FloattoLL_res_low);
814                         h_res = new_r_Proj(lower_blk, float_to_ll, h_res_mode,
815                                                            pn_ia32_l_FloattoLL_res_high);
816
817                         h_res = new_rd_Add(dbg, lower_blk, h_res, int_phi, h_res_mode);
818
819                         /* move the call and its Proj's to the lower block */
820                         set_nodes_block(call, lower_blk);
821
822                         for (proj = get_irn_link(call); proj != NULL; proj = get_irn_link(proj))
823                                 set_nodes_block(proj, lower_blk);
824                         block = lower_blk;
825                 }
826                 /* lower the call */
827                 resolve_call(call, l_res, h_res, irg, block);
828         } else if (n == 2) {
829                 ir_node *ll_to_float;
830
831                 /* We have a Conv long long -> float here */
832                 ir_node *a_l       = params[BINOP_Left_Low];
833                 ir_node *a_h       = params[BINOP_Left_High];
834                 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
835
836                 assert(! mode_is_float(get_irn_mode(a_l))
837                                 && ! mode_is_float(get_irn_mode(a_h)));
838
839                 ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
840
841                 /* lower the call */
842                 resolve_call(call, ll_to_float, NULL, irg, block);
843         } else {
844                 panic("unexpected Conv call %+F", call);
845         }
846
847         return 1;
848 }
849
850 /* Ia32 implementation of intrinsic mapping. */
851 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
852                                      const ir_mode *imode, const ir_mode *omode,
853                                      void *context)
854 {
855         i_record      elt;
856         ir_entity     **ent = NULL;
857         i_mapper_func mapper;
858
859         if (! intrinsics)
860                 intrinsics = NEW_ARR_F(i_record, 0);
861
862         switch (get_op_code(op)) {
863         case iro_Add:
864                 ent    = &i_ents[iro_Add];
865                 mapper = map_Add;
866                 break;
867         case iro_Sub:
868                 ent    = &i_ents[iro_Sub];
869                 mapper = map_Sub;
870                 break;
871         case iro_Shl:
872                 ent    = &i_ents[iro_Shl];
873                 mapper = map_Shl;
874                 break;
875         case iro_Shr:
876                 ent    = &i_ents[iro_Shr];
877                 mapper = map_Shr;
878                 break;
879         case iro_Shrs:
880                 ent    = &i_ents[iro_Shrs];
881                 mapper = map_Shrs;
882                 break;
883         case iro_Mul:
884                 ent    = &i_ents[iro_Mul];
885                 mapper = map_Mul;
886                 break;
887         case iro_Minus:
888                 ent    = &i_ents[iro_Minus];
889                 mapper = map_Minus;
890                 break;
891         case iro_Abs:
892                 ent    = &i_ents[iro_Abs];
893                 mapper = map_Abs;
894                 break;
895         case iro_Div:
896                 ent    = &i_ents[iro_Div];
897                 mapper = map_Div;
898                 break;
899         case iro_Mod:
900                 ent    = &i_ents[iro_Mod];
901                 mapper = map_Mod;
902                 break;
903         case iro_Conv:
904                 ent    = &i_ents[iro_Conv];
905                 mapper = map_Conv;
906                 break;
907         default:
908                 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
909                 return def_create_intrinsic_fkt(method, op, imode, omode, context);
910         }
911
912         if (ent && ! *ent) {
913 #define IDENT(s)  new_id_from_chars(s, sizeof(s)-1)
914
915                 ident *id = id_mangle(IDENT("L"), get_op_ident(op));
916                 *ent = new_entity(get_glob_type(), id, method);
917         }
918
919         elt.i_call.kind     = INTRINSIC_CALL;
920         elt.i_call.i_ent    = *ent;
921         elt.i_call.i_mapper = mapper;
922         elt.i_call.ctx      = context;
923         elt.i_call.link     = NULL;
924
925         ARR_APP1(i_record, intrinsics, elt);
926         return *ent;
927 }