bugfix for Conv Float>64 signed
[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, *cnst, *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         /* too bad: we need 0 in a register here */
486         cnst  = new_Const_long(l_mode, 0);
487
488         /* l_res = 0 - a_l */
489         /* h_res = 0 - a_h - carry */
490
491         res   = new_rd_ia32_Minus64Bit(dbg, irg, block, cnst, a_l, a_h);
492         l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
493         h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_high_res);
494
495         resolve_call(call, l_res, h_res, irg, block);
496
497         return 1;
498 }
499
500 /**
501  * Map a Abs (a_l, a_h)
502  */
503 static int map_Abs(ir_node *call, void *ctx) {
504         ir_graph *irg     = current_ir_graph;
505         dbg_info *dbg     = get_irn_dbg_info(call);
506         ir_node  *block   = get_nodes_block(call);
507         ir_node  **params = get_Call_param_arr(call);
508         ir_type  *method  = get_Call_type(call);
509         ir_node  *a_l     = params[BINOP_Left_Low];
510         ir_node  *a_h     = params[BINOP_Left_High];
511         ir_mode  *l_mode  = get_type_mode(get_method_res_type(method, 0));
512         ir_node  *l_res, *h_res, *sign, *sub_l, *sub_h, *res;
513         (void) ctx;
514
515         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
516
517         /*
518                 Code inspired by gcc output :) (although gcc doubles the
519                 operation for t1 as t2 and uses t1 for operations with low part
520                 and t2 for operations with high part which is actually unnecessary
521                 because t1 and t2 represent the same value)
522
523                 t1    = SHRS a_h, 31
524                 t2    = a_l ^ t1
525                 t3    = a_h ^ t1
526                 l_res = t2 - t1
527                 h_res = t3 - t1 - carry
528
529         */
530
531         sign  = new_rd_ia32_l_Sar(dbg, irg, block, a_h, new_Const_long(l_mode, 31), l_mode);
532         sub_l = new_rd_ia32_l_Xor(dbg, irg, block, a_l, sign, l_mode);
533         sub_h = new_rd_ia32_l_Xor(dbg, irg, block, a_h, sign, l_mode);
534         res   = new_rd_ia32_Sub64Bit(dbg, irg, block, sub_l, sub_h, sign, sign);
535         l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
536         h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);
537
538         resolve_call(call, l_res, h_res, irg, block);
539
540         return 1;
541 }
542
543 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
544
545 /**
546  * Maps a Div. Change into a library call
547  */
548 static int map_Div(ir_node *call, void *ctx) {
549         ia32_intrinsic_env_t *env = ctx;
550         ir_type   *method    = get_Call_type(call);
551         ir_mode   *l_mode    = get_type_mode(get_method_res_type(method, 0));
552         ir_node   *ptr;
553         ir_entity *ent;
554         symconst_symbol sym;
555
556         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
557
558         if (mode_is_signed(l_mode)) {
559                 /* 64bit signed Division */
560                 ent = env->divdi3;
561                 if (ent == NULL) {
562                         /* create library entity */
563                         ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
564                         set_entity_visibility(ent, visibility_external_allocated);
565                         set_entity_ld_ident(ent, ID("__divdi3"));
566                 }
567         } else {
568                 /* 64bit signed Division */
569                 ent = env->udivdi3;
570                 if (ent == NULL) {
571                         /* create library entity */
572                         ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
573                         set_entity_visibility(ent, visibility_external_allocated);
574                         set_entity_ld_ident(ent, ID("__udivdi3"));
575                 }
576         }
577         sym.entity_p = ent;
578         ptr = get_Call_ptr(call);
579         set_SymConst_symbol(ptr, sym);
580         return 1;
581 }
582
583 /**
584  * Maps a Mod. Change into a library call
585  */
586 static int map_Mod(ir_node *call, void *ctx) {
587         ia32_intrinsic_env_t *env = ctx;
588         ir_type   *method    = get_Call_type(call);
589         ir_mode   *l_mode    = get_type_mode(get_method_res_type(method, 0));
590         ir_node   *ptr;
591         ir_entity *ent;
592         symconst_symbol sym;
593
594         assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
595
596         if (mode_is_signed(l_mode)) {
597                 /* 64bit signed Modulo */
598                 ent = env->moddi3;
599                 if (ent == NULL) {
600                         /* create library entity */
601                         ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
602                         set_entity_visibility(ent, visibility_external_allocated);
603                         set_entity_ld_ident(ent, ID("__moddi3"));
604                 }
605         } else {
606                 /* 64bit signed Modulo */
607                 ent = env->umoddi3;
608                 if (ent == NULL) {
609                         /* create library entity */
610                         ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
611                         set_entity_visibility(ent, visibility_external_allocated);
612                         set_entity_ld_ident(ent, ID("__umoddi3"));
613                 }
614         }
615         sym.entity_p = ent;
616         ptr = get_Call_ptr(call);
617         set_SymConst_symbol(ptr, sym);
618         return 1;
619 }
620
621 /**
622  * Maps a Conv.
623  */
624 static int map_Conv(ir_node *call, void *ctx) {
625         ia32_intrinsic_env_t *env = ctx;
626         ir_graph  *irg        = current_ir_graph;
627         dbg_info  *dbg        = get_irn_dbg_info(call);
628         ir_node   *block      = get_nodes_block(call);
629         ir_node   **params    = get_Call_param_arr(call);
630         ir_type   *method     = get_Call_type(call);
631         int       n           = get_Call_n_params(call);
632         int       gp_bytes    = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
633         ir_entity *ent;
634         ir_node   *l_res, *h_res, *frame, *fres;
635         ir_node   *store_l, *store_h;
636         ir_node   *op_mem[2], *mem;
637
638         if (n == 1) {
639                 /* We have a Conv float -> long long here */
640                 ir_node *a_f        = params[0];
641                 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
642                 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
643
644                 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
645
646                 /* allocate memory on frame to store args */
647                 ent = env->irg == irg ? env->d_ll_conv : NULL;
648                 if (! ent) {
649                         ent      = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
650                         env->irg = irg;
651                 }
652
653                 /* Store arg */
654                 frame = get_irg_frame(irg);
655
656                 /*
657                         Now we create a node to move the value from a XMM register into
658                         x87 FPU because it is unknown here, which FPU is used.
659                         This node is killed in transformation phase when not needed.
660                         Otherwise it is split up into a movsd + fld
661                 */
662                 a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
663                 set_ia32_frame_ent(a_f, ent);
664                 set_ia32_use_frame(a_f);
665                 set_ia32_ls_mode(a_f, mode_D);
666
667                 /* store from FPU as Int */
668                 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
669                 set_ia32_frame_ent(a_f, ent);
670                 set_ia32_use_frame(a_f);
671                 set_ia32_ls_mode(a_f, mode_Ls);
672                 mem = a_f;
673
674                 /* load low part of the result */
675                 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
676                 set_ia32_frame_ent(l_res, ent);
677                 set_ia32_use_frame(l_res);
678                 set_ia32_ls_mode(l_res, l_res_mode);
679                 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
680
681                 /* load hight part of the result */
682                 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
683                 set_ia32_frame_ent(h_res, ent);
684                 add_ia32_am_offs_int(h_res, gp_bytes);
685                 set_ia32_use_frame(h_res);
686                 set_ia32_ls_mode(h_res, h_res_mode);
687                 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
688
689                 /* lower the call */
690                 resolve_call(call, l_res, h_res, irg, block);
691         }
692         else if (n == 2) {
693                 /* We have a Conv long long -> float here */
694                 ir_node *a_l       = params[BINOP_Left_Low];
695                 ir_node *a_h       = params[BINOP_Left_High];
696                 ir_mode *mode_a_l  = get_irn_mode(a_l);
697                 ir_mode *mode_a_h  = get_irn_mode(a_h);
698                 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
699
700                 assert(! mode_is_float(mode_a_l) && ! mode_is_float(mode_a_h) && "unexpected Conv call");
701
702                 /* allocate memory on frame to store args */
703                 ent = env->irg == irg ? env->ll_d_conv : NULL;
704                 if (! ent) {
705                         ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
706                         env->irg = irg;
707                 }
708
709                 /* Store arg */
710                 frame = get_irg_frame(irg);
711
712                 /* store first arg (low part) */
713                 store_l   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
714                 set_ia32_frame_ent(store_l, ent);
715                 set_ia32_use_frame(store_l);
716                 set_ia32_ls_mode(store_l, get_irn_mode(a_l));
717                 op_mem[0] = store_l;
718
719                 /* store second arg (high part) */
720                 store_h   = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
721                 set_ia32_frame_ent(store_h, ent);
722                 add_ia32_am_offs_int(store_h, gp_bytes);
723                 set_ia32_use_frame(store_h);
724                 set_ia32_ls_mode(store_h, get_irn_mode(a_h));
725                 op_mem[1] = store_h;
726
727                 mem = new_r_Sync(irg, block, 2, op_mem);
728
729                 /* Load arg into x87 FPU (implicit convert) */
730                 fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
731                 set_ia32_frame_ent(fres, ent);
732                 set_ia32_use_frame(fres);
733                 set_ia32_ls_mode(fres, mode_D);
734                 mem  = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
735                 fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);
736
737                 /*
738                         Now we create a node to move the loaded value into a XMM
739                         register because it is unknown here, which FPU is used.
740                         This node is killed in transformation phase when not needed.
741                         Otherwise it is split up into a fst + movsd
742                 */
743                 fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
744                 set_ia32_frame_ent(fres, ent);
745                 set_ia32_use_frame(fres);
746                 set_ia32_ls_mode(fres, fres_mode);
747
748                 /* lower the call */
749                 resolve_call(call, fres, NULL, irg, block);
750         }
751         else {
752                 assert(0 && "unexpected Conv call");
753         }
754
755         return 1;
756 }
757
758 /* Ia32 implementation of intrinsic mapping. */
759 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
760                                      const ir_mode *imode, const ir_mode *omode,
761                                      void *context)
762 {
763         i_record      elt;
764         ir_entity     **ent = NULL;
765         i_mapper_func mapper;
766
767         if (! intrinsics)
768                 intrinsics = NEW_ARR_F(i_record, 0);
769
770         switch (get_op_code(op)) {
771         case iro_Add:
772                 ent    = &i_ents[iro_Add];
773                 mapper = map_Add;
774                 break;
775         case iro_Sub:
776                 ent    = &i_ents[iro_Sub];
777                 mapper = map_Sub;
778                 break;
779         case iro_Shl:
780                 ent    = &i_ents[iro_Shl];
781                 mapper = map_Shl;
782                 break;
783         case iro_Shr:
784                 ent    = &i_ents[iro_Shr];
785                 mapper = map_Shr;
786                 break;
787         case iro_Shrs:
788                 ent    = &i_ents[iro_Shrs];
789                 mapper = map_Shrs;
790                 break;
791         case iro_Mul:
792                 ent    = &i_ents[iro_Mul];
793                 mapper = map_Mul;
794                 break;
795         case iro_Minus:
796                 ent    = &i_ents[iro_Minus];
797                 mapper = map_Minus;
798                 break;
799         case iro_Abs:
800                 ent    = &i_ents[iro_Abs];
801                 mapper = map_Abs;
802                 break;
803         case iro_Div:
804                 ent    = &i_ents[iro_Div];
805                 mapper = map_Div;
806                 break;
807         case iro_Mod:
808                 ent    = &i_ents[iro_Mod];
809                 mapper = map_Mod;
810                 break;
811         case iro_Conv:
812                 ent    = &i_ents[iro_Conv];
813                 mapper = map_Conv;
814                 break;
815         default:
816                 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
817                 return def_create_intrinsic_fkt(method, op, imode, omode, context);
818         }
819
820         if (ent && ! *ent) {
821 #define IDENT(s)  new_id_from_chars(s, sizeof(s)-1)
822
823                 ident *id = mangle(IDENT("L"), get_op_ident(op));
824                 *ent = new_entity(get_glob_type(), id, method);
825         }
826
827         elt.i_call.kind     = INTRINSIC_CALL;
828         elt.i_call.i_ent    = *ent;
829         elt.i_call.i_mapper = mapper;
830         elt.i_call.ctx      = context;
831         elt.i_call.link     = NULL;
832
833         ARR_APP1(i_record, intrinsics, elt);
834         return *ent;
835 }