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