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