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