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