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