2 * Copyright (C) 1995-2007 University of Karlsruhe. All right reserved.
4 * This file is part of libFirm.
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.
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.
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
22 * @brief This file implements the mapping of 64Bit intrinsic
23 * functions to code or library calls.
24 * @author Michael Beck
39 #include "ia32_new_nodes.h"
40 #include "bearch_ia32_t.h"
41 #include "gen_ia32_regalloc_if.h"
43 /** The array of all intrinsics that must be mapped. */
44 static i_record *intrinsics;
46 /** An array to cache all entities */
47 static ir_entity *i_ents[iro_MaxOpcode];
50 * Maps all intrinsic calls that the backend support
51 * and map all instructions the backend did not support
54 void ia32_handle_intrinsics(void) {
55 if (intrinsics && ARR_LEN(intrinsics) > 0) {
56 lower_intrinsics(intrinsics, ARR_LEN(intrinsics), /*part_block_used=*/1);
60 #define BINOP_Left_Low 0
61 #define BINOP_Left_High 1
62 #define BINOP_Right_Low 2
63 #define BINOP_Right_High 3
66 * Replace a call be a tuple of l_res, h_res.
68 static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block) {
73 res = new_r_Tuple(irg, block, h_res == NULL ? 1 : 2, in);
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));
85 * Map an Add (a_l, a_h, b_l, b_h)
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;
104 /* l_res = a_l + b_l */
105 /* h_res = a_h + b_h + carry */
107 add_low = new_rd_ia32_l_Add(dbg, irg, block, a_l, b_l, mode_T);
108 flags = new_r_Proj(irg, block, add_low, mode_flags, pn_ia32_flags);
109 add_high = new_rd_ia32_l_Adc(dbg, irg, block, a_h, b_h, flags, h_mode);
111 l_res = new_r_Proj(irg, block, add_low, l_mode, pn_ia32_res);
114 resolve_call(call, l_res, h_res, irg, block);
119 * Map a Sub (a_l, a_h, b_l, b_h)
121 static int map_Sub(ir_node *call, void *ctx)
123 ir_graph *irg = current_ir_graph;
124 dbg_info *dbg = get_irn_dbg_info(call);
125 ir_node *block = get_nodes_block(call);
126 ir_node **params = get_Call_param_arr(call);
127 ir_type *method = get_Call_type(call);
128 ir_node *a_l = params[BINOP_Left_Low];
129 ir_node *a_h = params[BINOP_Left_High];
130 ir_node *b_l = params[BINOP_Right_Low];
131 ir_node *b_h = params[BINOP_Right_High];
132 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
133 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
134 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
135 ir_node *sub_low, *sub_high, *flags;
136 ir_node *l_res, *h_res;
139 /* l_res = a_l - b_l */
140 /* h_res = a_h - b_h - carry */
142 sub_low = new_rd_ia32_l_Sub(dbg, irg, block, a_l, b_l, mode_T);
143 flags = new_r_Proj(irg, block, sub_low, mode_flags, pn_ia32_flags);
144 sub_high = new_rd_ia32_l_Sbb(dbg, irg, block, a_h, b_h, flags, h_mode);
146 l_res = new_r_Proj(irg, block, sub_low, l_mode, pn_ia32_res);
149 resolve_call(call, l_res, h_res, irg, block);
154 * Map a Shl (a_l, a_h, count)
156 static int map_Shl(ir_node *call, void *ctx) {
157 ir_graph *irg = current_ir_graph;
158 dbg_info *dbg = get_irn_dbg_info(call);
159 ir_node *block = get_nodes_block(call);
160 ir_node **params = get_Call_param_arr(call);
161 ir_type *method = get_Call_type(call);
162 ir_node *a_l = params[BINOP_Left_Low];
163 ir_node *a_h = params[BINOP_Left_High];
164 ir_node *cnt = params[BINOP_Right_Low];
165 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
166 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
168 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
172 /* the shift count is a const, create better code */
173 tarval *tv = get_Const_tarval(cnt);
175 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
176 /* simplest case: shift only the lower bits. Note that there is no
177 need to reduce the constant here, this is done by the hardware. */
178 ir_node *conv = new_rd_Conv(dbg, irg, block, a_l, h_mode);
179 h_res = new_rd_Shl(dbg, irg, block, conv, cnt, h_mode);
180 l_res = new_rd_Const(dbg, irg, block, l_mode, get_mode_null(l_mode));
183 /* h_res = SHLD a_h, a_l, cnt */
184 h_res = new_rd_ia32_l_ShlD(dbg, irg, block, a_h, a_l, cnt, h_mode);
186 /* l_res = SHL a_l, cnt */
187 l_res = new_rd_ia32_l_ShlDep(dbg, irg, block, a_l, cnt, h_res, l_mode);
190 resolve_call(call, l_res, h_res, irg, block);
195 upper = get_nodes_block(call);
197 /* h_res = SHLD a_h, a_l, cnt */
198 h1 = new_rd_ia32_l_ShlD(dbg, irg, upper, a_h, a_l, cnt, h_mode);
200 /* l_res = SHL a_l, cnt */
201 l1 = new_rd_ia32_l_ShlDep(dbg, irg, upper, a_l, cnt, h1, l_mode);
203 c_mode = get_irn_mode(cnt);
204 irn = new_r_Const_long(irg, upper, c_mode, 32);
205 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
206 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
207 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
208 cond = new_rd_Cond(dbg, irg, upper, irn);
210 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
211 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
213 /* the block for cnt >= 32 */
214 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
215 h2 = new_rd_Conv(dbg, irg, n_block, l1, h_mode);
216 l2 = new_r_Const(irg, n_block, l_mode, get_mode_null(l_mode));
217 in[1] = new_r_Jmp(irg, n_block);
219 set_irn_in(block, 2, in);
223 l_res = new_r_Phi(irg, block, 2, in, l_mode);
224 set_irn_link(block, l_res);
228 h_res = new_r_Phi(irg, block, 2, in, h_mode);
229 set_irn_link(l_res, h_res);
230 set_irn_link(h_res, NULL);
233 set_nodes_block(call, block);
234 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
235 set_nodes_block(irn, block);
237 resolve_call(call, l_res, h_res, irg, block);
242 * Map a Shr (a_l, a_h, count)
244 static int map_Shr(ir_node *call, void *ctx) {
245 ir_graph *irg = current_ir_graph;
246 dbg_info *dbg = get_irn_dbg_info(call);
247 ir_node *block = get_nodes_block(call);
248 ir_node **params = get_Call_param_arr(call);
249 ir_type *method = get_Call_type(call);
250 ir_node *a_l = params[BINOP_Left_Low];
251 ir_node *a_h = params[BINOP_Left_High];
252 ir_node *cnt = params[BINOP_Right_Low];
253 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
254 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
256 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
260 /* the shift count is a const, create better code */
261 tarval *tv = get_Const_tarval(cnt);
263 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
264 /* simplest case: shift only the higher bits. Note that there is no
265 need to reduce the constant here, this is done by the hardware. */
266 ir_node *conv = new_rd_Conv(dbg, irg, block, a_h, l_mode);
267 h_res = new_rd_Const(dbg, irg, block, h_mode, get_mode_null(h_mode));
268 l_res = new_rd_Shr(dbg, irg, block, conv, cnt, l_mode);
270 /* l_res = SHRD a_h:a_l, cnt */
271 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
273 /* h_res = SHR a_h, cnt */
274 h_res = new_rd_ia32_l_ShrDep(dbg, irg, block, a_h, cnt, l_res, h_mode);
276 resolve_call(call, l_res, h_res, irg, block);
281 upper = get_nodes_block(call);
283 /* l_res = SHRD a_h:a_l, cnt */
284 l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
286 /* h_res = SHR a_h, cnt */
287 h1 = new_rd_ia32_l_ShrDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
289 c_mode = get_irn_mode(cnt);
290 irn = new_r_Const_long(irg, upper, c_mode, 32);
291 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
292 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
293 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
294 cond = new_rd_Cond(dbg, irg, upper, irn);
296 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
297 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
299 /* the block for cnt >= 32 */
300 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
301 l2 = new_rd_Conv(dbg, irg, n_block, h1, l_mode);
302 h2 = new_r_Const(irg, n_block, l_mode, get_mode_null(h_mode));
303 in[1] = new_r_Jmp(irg, n_block);
305 set_irn_in(block, 2, in);
309 l_res = new_r_Phi(irg, block, 2, in, l_mode);
310 set_irn_link(block, l_res);
314 h_res = new_r_Phi(irg, block, 2, in, h_mode);
315 set_irn_link(l_res, h_res);
316 set_irn_link(h_res, NULL);
319 set_nodes_block(call, block);
320 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
321 set_nodes_block(irn, block);
323 resolve_call(call, l_res, h_res, irg, block);
328 * Map a Shrs (a_l, a_h, count)
330 static int map_Shrs(ir_node *call, void *ctx) {
331 ir_graph *irg = current_ir_graph;
332 dbg_info *dbg = get_irn_dbg_info(call);
333 ir_node *block = get_nodes_block(call);
334 ir_node **params = get_Call_param_arr(call);
335 ir_type *method = get_Call_type(call);
336 ir_node *a_l = params[BINOP_Left_Low];
337 ir_node *a_h = params[BINOP_Left_High];
338 ir_node *cnt = params[BINOP_Right_Low];
339 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
340 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
342 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
346 /* the shift count is a const, create better code */
347 tarval *tv = get_Const_tarval(cnt);
349 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
350 /* simplest case: shift only the higher bits. Note that there is no
351 need to reduce the constant here, this is done by the hardware. */
352 ir_node *conv = new_rd_Conv(dbg, irg, block, a_h, l_mode);
353 ir_mode *c_mode = get_irn_mode(cnt);
355 h_res = new_rd_Shrs(dbg, irg, block, a_h, new_r_Const_long(irg, block, c_mode, 31), h_mode);
356 l_res = new_rd_Shrs(dbg, irg, block, conv, cnt, l_mode);
358 /* l_res = SHRD a_h:a_l, cnt */
359 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
361 /* h_res = SAR a_h, cnt */
362 h_res = new_rd_ia32_l_SarDep(dbg, irg, block, a_h, cnt, l_res, h_mode);
364 resolve_call(call, l_res, h_res, irg, block);
369 upper = get_nodes_block(call);
371 /* l_res = SHRD a_h:a_l, cnt */
372 l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
374 /* h_res = SAR a_h, cnt */
375 h1 = new_rd_ia32_l_SarDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
377 c_mode = get_irn_mode(cnt);
378 irn = new_r_Const_long(irg, upper, c_mode, 32);
379 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
380 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
381 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
382 cond = new_rd_Cond(dbg, irg, upper, irn);
384 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
385 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
387 /* the block for cnt >= 32 */
388 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
389 l2 = new_rd_Conv(dbg, irg, n_block, h1, l_mode);
390 h2 = new_rd_Shrs(dbg, irg, n_block, a_h, new_r_Const_long(irg, block, c_mode, 31), h_mode);
391 in[1] = new_r_Jmp(irg, n_block);
393 set_irn_in(block, 2, in);
397 l_res = new_r_Phi(irg, block, 2, in, l_mode);
398 set_irn_link(block, l_res);
402 h_res = new_r_Phi(irg, block, 2, in, h_mode);
403 set_irn_link(l_res, h_res);
404 set_irn_link(h_res, NULL);
407 set_nodes_block(call, block);
408 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
409 set_nodes_block(irn, block);
411 resolve_call(call, l_res, h_res, irg, block);
416 * Map a Mul (a_l, a_h, b_l, b_h)
418 static int map_Mul(ir_node *call, void *ctx) {
419 ir_graph *irg = current_ir_graph;
420 dbg_info *dbg = get_irn_dbg_info(call);
421 ir_node *block = get_nodes_block(call);
422 ir_node **params = get_Call_param_arr(call);
423 ir_type *method = get_Call_type(call);
424 ir_node *a_l = params[BINOP_Left_Low];
425 ir_node *a_h = params[BINOP_Left_High];
426 ir_node *b_l = params[BINOP_Right_Low];
427 ir_node *b_h = params[BINOP_Right_High];
428 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
429 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
430 ir_node *l_res, *h_res, *mul, *pEDX, *add;
443 /* handle the often used case of 32x32=64 mul */
444 if (is_Shrs(a_h) && get_Shrs_left(a_h) == a_l) {
445 ir_node *c1 = get_Shrs_right(a_h);
448 tarval *tv = get_Const_tarval(c1);
450 if (tarval_is_long(tv) && get_tarval_long(tv) == 31) {
451 /* a is a sign extend */
453 if (is_Shrs(b_h) && get_Shrs_left(b_h) == b_l && c1 == get_Shrs_right(b_h)) {
454 /* b is a sign extend: it's a 32 * 32 = 64 signed multiplication */
455 mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
456 h_res = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
457 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
461 /* we rely here on Consts being on the right side */
462 if (is_Const(b_h) && is_Const(b_l)) {
463 tarval *th = get_Const_tarval(b_h);
464 tarval *tl = get_Const_tarval(b_l);
466 if (tarval_is_long(th) && tarval_is_long(tl)) {
467 long h = get_tarval_long(th);
468 long l = get_tarval_long(tl);
470 if ((h == 0 && l >= 0) || (h == -1 && l < 0)) {
471 /* b is a sign extended const */
472 mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
473 h_res = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
474 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
484 mul = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
485 pEDX = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
486 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
488 b_l = new_rd_Conv(dbg, irg, block, b_l, h_mode);
489 mul = new_rd_Mul( dbg, irg, block, a_h, b_l, h_mode);
490 add = new_rd_Add( dbg, irg, block, mul, pEDX, h_mode);
491 a_l = new_rd_Conv(dbg, irg, block, a_l, h_mode);
492 mul = new_rd_Mul( dbg, irg, block, a_l, b_h, h_mode);
493 h_res = new_rd_Add( dbg, irg, block, add, mul, h_mode);
496 resolve_call(call, l_res, h_res, irg, block);
502 * Map a Minus (a_l, a_h)
504 static int map_Minus(ir_node *call, void *ctx) {
505 ir_graph *irg = current_ir_graph;
506 dbg_info *dbg = get_irn_dbg_info(call);
507 ir_node *block = get_nodes_block(call);
508 ir_node **params = get_Call_param_arr(call);
509 ir_type *method = get_Call_type(call);
510 ir_node *a_l = params[BINOP_Left_Low];
511 ir_node *a_h = params[BINOP_Left_High];
512 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
513 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
514 ir_node *l_res, *h_res, *res;
517 res = new_rd_ia32_Minus64Bit(dbg, irg, block, a_l, a_h);
518 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
519 h_res = new_r_Proj(irg, block, res, h_mode, pn_ia32_Minus64Bit_high_res);
521 resolve_call(call, l_res, h_res, irg, block);
527 * Map a Abs (a_l, a_h)
529 static int map_Abs(ir_node *call, void *ctx) {
530 ir_graph *irg = current_ir_graph;
531 dbg_info *dbg = get_irn_dbg_info(call);
532 ir_node *block = get_nodes_block(call);
533 ir_node **params = get_Call_param_arr(call);
534 ir_type *method = get_Call_type(call);
535 ir_node *a_l = params[BINOP_Left_Low];
536 ir_node *a_h = params[BINOP_Left_High];
537 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
538 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
539 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
540 ir_node *l_res, *h_res, *sign, *sub_l, *sub_h;
547 Code inspired by gcc output :) (although gcc doubles the
548 operation for t1 as t2 and uses t1 for operations with low part
549 and t2 for operations with high part which is actually unnecessary
550 because t1 and t2 represent the same value)
556 h_res = t3 - t1 - carry
560 /* TODO: give a hint to the backend somehow to not create a cltd here... */
561 sign = new_rd_Shrs(dbg, irg, block, a_h, new_Const_long(l_mode, 31), h_mode);
562 sign_l = new_rd_Conv(dbg, irg, block, sign, l_mode);
563 sub_l = new_rd_Eor(dbg, irg, block, a_l, sign_l, l_mode);
564 sub_h = new_rd_Eor(dbg, irg, block, a_h, sign, h_mode);
566 l_sub = new_rd_ia32_l_Sub(dbg, irg, block, sub_l, sign_l, mode_T);
567 l_res = new_r_Proj(irg, block, l_sub, l_mode, pn_ia32_res);
568 flags = new_r_Proj(irg, block, l_sub, mode_flags, pn_ia32_flags);
569 h_res = new_rd_ia32_l_Sbb(dbg, irg, block, sub_h, sign, flags, h_mode);
571 resolve_call(call, l_res, h_res, irg, block);
576 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
579 * Maps a Div. Change into a library call
581 static int map_Div(ir_node *call, void *ctx) {
582 ia32_intrinsic_env_t *env = ctx;
583 ir_type *method = get_Call_type(call);
584 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
589 if (mode_is_signed(h_mode)) {
590 /* 64bit signed Division */
593 /* create library entity */
594 ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
595 set_entity_visibility(ent, visibility_external_allocated);
596 set_entity_ld_ident(ent, ID("__divdi3"));
599 /* 64bit unsigned Division */
602 /* create library entity */
603 ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
604 set_entity_visibility(ent, visibility_external_allocated);
605 set_entity_ld_ident(ent, ID("__udivdi3"));
609 ptr = get_Call_ptr(call);
610 set_SymConst_symbol(ptr, sym);
615 * Maps a Mod. Change into a library call
617 static int map_Mod(ir_node *call, void *ctx) {
618 ia32_intrinsic_env_t *env = ctx;
619 ir_type *method = get_Call_type(call);
620 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 0));
625 if (mode_is_signed(h_mode)) {
626 /* 64bit signed Modulo */
629 /* create library entity */
630 ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
631 set_entity_visibility(ent, visibility_external_allocated);
632 set_entity_ld_ident(ent, ID("__moddi3"));
635 /* 64bit signed Modulo */
638 /* create library entity */
639 ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
640 set_entity_visibility(ent, visibility_external_allocated);
641 set_entity_ld_ident(ent, ID("__umoddi3"));
645 ptr = get_Call_ptr(call);
646 set_SymConst_symbol(ptr, sym);
653 static int map_Conv(ir_node *call, void *ctx) {
654 ia32_intrinsic_env_t *env = ctx;
655 ir_graph *irg = current_ir_graph;
656 dbg_info *dbg = get_irn_dbg_info(call);
657 ir_node *block = get_nodes_block(call);
658 ir_node **params = get_Call_param_arr(call);
659 ir_type *method = get_Call_type(call);
660 int n = get_Call_n_params(call);
661 int gp_bytes = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
663 ir_node *l_res, *h_res, *frame, *fres;
664 ir_node *store_l, *store_h;
665 ir_node *op_mem[2], *mem;
668 /* We have a Conv float -> long long here */
669 ir_node *a_f = params[0];
670 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
671 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
673 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
675 /* allocate memory on frame to store args */
676 ent = env->irg == irg ? env->d_ll_conv : NULL;
678 ent = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
683 frame = get_irg_frame(irg);
686 Now we create a node to move the value from a XMM register into
687 x87 FPU because it is unknown here, which FPU is used.
688 This node is killed in transformation phase when not needed.
689 Otherwise it is split up into a movsd + fld
691 a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
692 set_ia32_frame_ent(a_f, ent);
693 set_ia32_use_frame(a_f);
694 set_ia32_ls_mode(a_f, mode_D);
696 /* store from FPU as Int */
697 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
698 set_ia32_frame_ent(a_f, ent);
699 set_ia32_use_frame(a_f);
700 set_ia32_ls_mode(a_f, mode_Ls);
703 /* load low part of the result */
704 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
705 set_ia32_frame_ent(l_res, ent);
706 set_ia32_use_frame(l_res);
707 set_ia32_ls_mode(l_res, l_res_mode);
708 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
710 /* load hight part of the result */
711 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
712 set_ia32_frame_ent(h_res, ent);
713 add_ia32_am_offs_int(h_res, gp_bytes);
714 set_ia32_use_frame(h_res);
715 set_ia32_ls_mode(h_res, h_res_mode);
716 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
719 resolve_call(call, l_res, h_res, irg, block);
722 /* We have a Conv long long -> float here */
723 ir_node *a_l = params[BINOP_Left_Low];
724 ir_node *a_h = params[BINOP_Left_High];
725 ir_mode *mode_a_l = get_irn_mode(a_l);
726 ir_mode *mode_a_h = get_irn_mode(a_h);
727 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
729 assert(! mode_is_float(mode_a_l) && ! mode_is_float(mode_a_h) && "unexpected Conv call");
731 /* allocate memory on frame to store args */
732 ent = env->irg == irg ? env->ll_d_conv : NULL;
734 ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
739 frame = get_irg_frame(irg);
741 /* store first arg (low part) */
742 store_l = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
743 set_ia32_frame_ent(store_l, ent);
744 set_ia32_use_frame(store_l);
745 set_ia32_ls_mode(store_l, get_irn_mode(a_l));
748 /* store second arg (high part) */
749 store_h = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
750 set_ia32_frame_ent(store_h, ent);
751 add_ia32_am_offs_int(store_h, gp_bytes);
752 set_ia32_use_frame(store_h);
753 set_ia32_ls_mode(store_h, get_irn_mode(a_h));
756 mem = new_r_Sync(irg, block, 2, op_mem);
758 /* Load arg into x87 FPU (implicit convert) */
759 fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
760 set_ia32_frame_ent(fres, ent);
761 set_ia32_use_frame(fres);
762 set_ia32_ls_mode(fres, mode_D);
763 mem = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
764 fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);
767 Now we create a node to move the loaded value into a XMM
768 register because it is unknown here, which FPU is used.
769 This node is killed in transformation phase when not needed.
770 Otherwise it is split up into a fst + movsd
772 fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
773 set_ia32_frame_ent(fres, ent);
774 set_ia32_use_frame(fres);
775 set_ia32_ls_mode(fres, fres_mode);
778 resolve_call(call, fres, NULL, irg, block);
781 assert(0 && "unexpected Conv call");
787 /* Ia32 implementation of intrinsic mapping. */
788 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
789 const ir_mode *imode, const ir_mode *omode,
793 ir_entity **ent = NULL;
794 i_mapper_func mapper;
797 intrinsics = NEW_ARR_F(i_record, 0);
799 switch (get_op_code(op)) {
801 ent = &i_ents[iro_Add];
805 ent = &i_ents[iro_Sub];
809 ent = &i_ents[iro_Shl];
813 ent = &i_ents[iro_Shr];
817 ent = &i_ents[iro_Shrs];
821 ent = &i_ents[iro_Mul];
825 ent = &i_ents[iro_Minus];
829 ent = &i_ents[iro_Abs];
833 ent = &i_ents[iro_Div];
837 ent = &i_ents[iro_Mod];
841 ent = &i_ents[iro_Conv];
845 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
846 return def_create_intrinsic_fkt(method, op, imode, omode, context);
850 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
852 ident *id = mangle(IDENT("L"), get_op_ident(op));
853 *ent = new_entity(get_glob_type(), id, method);
856 elt.i_call.kind = INTRINSIC_CALL;
857 elt.i_call.i_ent = *ent;
858 elt.i_call.i_mapper = mapper;
859 elt.i_call.ctx = context;
860 elt.i_call.link = NULL;
862 ARR_APP1(i_record, intrinsics, elt);