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