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