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