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
40 #include "ia32_new_nodes.h"
41 #include "bearch_ia32_t.h"
42 #include "gen_ia32_regalloc_if.h"
44 /** The array of all intrinsics that must be mapped. */
45 static i_record *intrinsics;
47 /** An array to cache all entities */
48 static ir_entity *i_ents[iro_MaxOpcode];
51 * Maps all intrinsic calls that the backend support
52 * and map all instructions the backend did not support
55 void ia32_handle_intrinsics(void) {
56 if (intrinsics && ARR_LEN(intrinsics) > 0) {
57 lower_intrinsics(intrinsics, ARR_LEN(intrinsics), /*part_block_used=*/1);
61 #define BINOP_Left_Low 0
62 #define BINOP_Left_High 1
63 #define BINOP_Right_Low 2
64 #define BINOP_Right_High 3
67 * Replace a call be a tuple of l_res, h_res.
69 static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block) {
71 ir_node *bad = get_irg_bad(irg);
72 ir_node *nomem = get_irg_no_mem(irg);
76 res = new_r_Tuple(irg, block, h_res == NULL ? 1 : 2, in);
78 turn_into_tuple(call, pn_Call_max);
79 set_Tuple_pred(call, pn_Call_M_regular, nomem);
80 /* Matze: the new_r_Jmp here sometimes CSEs and then bad things happen
81 * (in movgen.c from 186.crafty for example) I don't know why it is here
82 * and if this fix is correct... */
83 /*set_Tuple_pred(call, pn_Call_X_regular, new_r_Jmp(irg, block));*/
84 set_Tuple_pred(call, pn_Call_X_regular, bad);
85 set_Tuple_pred(call, pn_Call_X_except, bad);
86 set_Tuple_pred(call, pn_Call_T_result, res);
87 set_Tuple_pred(call, pn_Call_M_except, nomem);
88 set_Tuple_pred(call, pn_Call_P_value_res_base, bad);
92 * Map an Add (a_l, a_h, b_l, b_h)
94 static int map_Add(ir_node *call, void *ctx) {
95 ir_graph *irg = current_ir_graph;
96 dbg_info *dbg = get_irn_dbg_info(call);
97 ir_node *block = get_nodes_block(call);
98 ir_node **params = get_Call_param_arr(call);
99 ir_type *method = get_Call_type(call);
100 ir_node *a_l = params[BINOP_Left_Low];
101 ir_node *a_h = params[BINOP_Left_High];
102 ir_node *b_l = params[BINOP_Right_Low];
103 ir_node *b_h = params[BINOP_Right_High];
104 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
105 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
106 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
107 ir_node *add_low, *add_high, *flags;
108 ir_node *l_res, *h_res;
111 /* l_res = a_l + b_l */
112 /* h_res = a_h + b_h + carry */
114 add_low = new_rd_ia32_l_Add(dbg, irg, block, a_l, b_l, mode_T);
115 flags = new_r_Proj(irg, block, add_low, mode_flags, pn_ia32_flags);
116 add_high = new_rd_ia32_l_Adc(dbg, irg, block, a_h, b_h, flags, h_mode);
118 l_res = new_r_Proj(irg, block, add_low, l_mode, pn_ia32_res);
121 resolve_call(call, l_res, h_res, irg, block);
126 * Map a Sub (a_l, a_h, b_l, b_h)
128 static int map_Sub(ir_node *call, void *ctx)
130 ir_graph *irg = current_ir_graph;
131 dbg_info *dbg = get_irn_dbg_info(call);
132 ir_node *block = get_nodes_block(call);
133 ir_node **params = get_Call_param_arr(call);
134 ir_type *method = get_Call_type(call);
135 ir_node *a_l = params[BINOP_Left_Low];
136 ir_node *a_h = params[BINOP_Left_High];
137 ir_node *b_l = params[BINOP_Right_Low];
138 ir_node *b_h = params[BINOP_Right_High];
139 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
140 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
141 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
142 ir_node *sub_low, *sub_high, *flags;
143 ir_node *l_res, *h_res;
146 /* l_res = a_l - b_l */
147 /* h_res = a_h - b_h - carry */
149 sub_low = new_rd_ia32_l_Sub(dbg, irg, block, a_l, b_l, mode_T);
150 flags = new_r_Proj(irg, block, sub_low, mode_flags, pn_ia32_flags);
151 sub_high = new_rd_ia32_l_Sbb(dbg, irg, block, a_h, b_h, flags, h_mode);
153 l_res = new_r_Proj(irg, block, sub_low, l_mode, pn_ia32_res);
156 resolve_call(call, l_res, h_res, irg, block);
161 * Map a Shl (a_l, a_h, count)
163 static int map_Shl(ir_node *call, void *ctx) {
164 ir_graph *irg = current_ir_graph;
165 dbg_info *dbg = get_irn_dbg_info(call);
166 ir_node *block = get_nodes_block(call);
167 ir_node **params = get_Call_param_arr(call);
168 ir_type *method = get_Call_type(call);
169 ir_node *a_l = params[BINOP_Left_Low];
170 ir_node *a_h = params[BINOP_Left_High];
171 ir_node *cnt = params[BINOP_Right_Low];
172 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
173 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
175 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
179 /* the shift count is a const, create better code */
180 tarval *tv = get_Const_tarval(cnt);
182 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
183 /* simplest case: shift only the lower bits. Note that there is no
184 need to reduce the constant here, this is done by the hardware. */
185 ir_node *conv = new_rd_Conv(dbg, irg, block, a_l, h_mode);
186 h_res = new_rd_Shl(dbg, irg, block, conv, cnt, h_mode);
187 l_res = new_rd_Const(dbg, irg, block, l_mode, get_mode_null(l_mode));
190 /* h_res = SHLD a_h, a_l, cnt */
191 h_res = new_rd_ia32_l_ShlD(dbg, irg, block, a_h, a_l, cnt, h_mode);
193 /* l_res = SHL a_l, cnt */
194 l_res = new_rd_ia32_l_ShlDep(dbg, irg, block, a_l, cnt, h_res, l_mode);
197 resolve_call(call, l_res, h_res, irg, block);
202 upper = get_nodes_block(call);
204 /* h_res = SHLD a_h, a_l, cnt */
205 h1 = new_rd_ia32_l_ShlD(dbg, irg, upper, a_h, a_l, cnt, h_mode);
207 /* l_res = SHL a_l, cnt */
208 l1 = new_rd_ia32_l_ShlDep(dbg, irg, upper, a_l, cnt, h1, l_mode);
210 c_mode = get_irn_mode(cnt);
211 irn = new_r_Const_long(irg, upper, c_mode, 32);
212 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
213 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
214 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
215 cond = new_rd_Cond(dbg, irg, upper, irn);
217 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
218 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
220 /* the block for cnt >= 32 */
221 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
222 h2 = new_rd_Conv(dbg, irg, n_block, l1, h_mode);
223 l2 = new_r_Const(irg, n_block, l_mode, get_mode_null(l_mode));
224 in[1] = new_r_Jmp(irg, n_block);
226 set_irn_in(block, 2, in);
230 l_res = new_r_Phi(irg, block, 2, in, l_mode);
231 set_irn_link(block, l_res);
235 h_res = new_r_Phi(irg, block, 2, in, h_mode);
236 set_irn_link(l_res, h_res);
237 set_irn_link(h_res, NULL);
240 set_nodes_block(call, block);
241 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
242 set_nodes_block(irn, block);
244 resolve_call(call, l_res, h_res, irg, block);
249 * Map a Shr (a_l, a_h, count)
251 static int map_Shr(ir_node *call, void *ctx) {
252 ir_graph *irg = current_ir_graph;
253 dbg_info *dbg = get_irn_dbg_info(call);
254 ir_node *block = get_nodes_block(call);
255 ir_node **params = get_Call_param_arr(call);
256 ir_type *method = get_Call_type(call);
257 ir_node *a_l = params[BINOP_Left_Low];
258 ir_node *a_h = params[BINOP_Left_High];
259 ir_node *cnt = params[BINOP_Right_Low];
260 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
261 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
263 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
267 /* the shift count is a const, create better code */
268 tarval *tv = get_Const_tarval(cnt);
270 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
271 /* simplest case: shift only the higher bits. Note that there is no
272 need to reduce the constant here, this is done by the hardware. */
273 ir_node *conv = new_rd_Conv(dbg, irg, block, a_h, l_mode);
274 h_res = new_rd_Const(dbg, irg, block, h_mode, get_mode_null(h_mode));
275 l_res = new_rd_Shr(dbg, irg, block, conv, cnt, l_mode);
277 /* l_res = SHRD a_h:a_l, cnt */
278 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
280 /* h_res = SHR a_h, cnt */
281 h_res = new_rd_ia32_l_ShrDep(dbg, irg, block, a_h, cnt, l_res, h_mode);
283 resolve_call(call, l_res, h_res, irg, block);
288 upper = get_nodes_block(call);
290 /* l_res = SHRD a_h:a_l, cnt */
291 l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
293 /* h_res = SHR a_h, cnt */
294 h1 = new_rd_ia32_l_ShrDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
296 c_mode = get_irn_mode(cnt);
297 irn = new_r_Const_long(irg, upper, c_mode, 32);
298 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
299 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
300 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
301 cond = new_rd_Cond(dbg, irg, upper, irn);
303 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
304 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
306 /* the block for cnt >= 32 */
307 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
308 l2 = new_rd_Conv(dbg, irg, n_block, h1, l_mode);
309 h2 = new_r_Const(irg, n_block, l_mode, get_mode_null(h_mode));
310 in[1] = new_r_Jmp(irg, n_block);
312 set_irn_in(block, 2, in);
316 l_res = new_r_Phi(irg, block, 2, in, l_mode);
317 set_irn_link(block, l_res);
321 h_res = new_r_Phi(irg, block, 2, in, h_mode);
322 set_irn_link(l_res, h_res);
323 set_irn_link(h_res, NULL);
326 set_nodes_block(call, block);
327 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
328 set_nodes_block(irn, block);
330 resolve_call(call, l_res, h_res, irg, block);
335 * Map a Shrs (a_l, a_h, count)
337 static int map_Shrs(ir_node *call, void *ctx) {
338 ir_graph *irg = current_ir_graph;
339 dbg_info *dbg = get_irn_dbg_info(call);
340 ir_node *block = get_nodes_block(call);
341 ir_node **params = get_Call_param_arr(call);
342 ir_type *method = get_Call_type(call);
343 ir_node *a_l = params[BINOP_Left_Low];
344 ir_node *a_h = params[BINOP_Left_High];
345 ir_node *cnt = params[BINOP_Right_Low];
346 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
347 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
349 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
353 /* the shift count is a const, create better code */
354 tarval *tv = get_Const_tarval(cnt);
356 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
357 /* simplest case: shift only the higher bits. Note that there is no
358 need to reduce the constant here, this is done by the hardware. */
359 ir_node *conv = new_rd_Conv(dbg, irg, block, a_h, l_mode);
360 ir_mode *c_mode = get_irn_mode(cnt);
362 h_res = new_rd_Shrs(dbg, irg, block, a_h, new_r_Const_long(irg, block, c_mode, 31), h_mode);
363 l_res = new_rd_Shrs(dbg, irg, block, conv, cnt, l_mode);
365 /* l_res = SHRD a_h:a_l, cnt */
366 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
368 /* h_res = SAR a_h, cnt */
369 h_res = new_rd_ia32_l_SarDep(dbg, irg, block, a_h, cnt, l_res, h_mode);
371 resolve_call(call, l_res, h_res, irg, block);
376 upper = get_nodes_block(call);
378 /* l_res = SHRD a_h:a_l, cnt */
379 l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
381 /* h_res = SAR a_h, cnt */
382 h1 = new_rd_ia32_l_SarDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
384 c_mode = get_irn_mode(cnt);
385 irn = new_r_Const_long(irg, upper, c_mode, 32);
386 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
387 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
388 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
389 cond = new_rd_Cond(dbg, irg, upper, irn);
391 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
392 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
394 /* the block for cnt >= 32 */
395 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
396 l2 = new_rd_Conv(dbg, irg, n_block, h1, l_mode);
397 h2 = new_rd_Shrs(dbg, irg, n_block, a_h, new_r_Const_long(irg, block, c_mode, 31), h_mode);
398 in[1] = new_r_Jmp(irg, n_block);
400 set_irn_in(block, 2, in);
404 l_res = new_r_Phi(irg, block, 2, in, l_mode);
405 set_irn_link(block, l_res);
409 h_res = new_r_Phi(irg, block, 2, in, h_mode);
410 set_irn_link(l_res, h_res);
411 set_irn_link(h_res, NULL);
414 set_nodes_block(call, block);
415 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
416 set_nodes_block(irn, block);
418 resolve_call(call, l_res, h_res, irg, block);
422 static int is_sign_extend(ir_node *low, ir_node *high)
429 high_r = get_Shrs_right(high);
430 if (!is_Const(high_r)) return 0;
432 shift_count = get_Const_tarval(high_r);
433 if (!tarval_is_long(shift_count)) return 0;
434 if (get_tarval_long(shift_count) != 31) return 0;
436 high_l = get_Shrs_left(high);
438 if (is_Conv(low) && get_Conv_op(low) == high_l) return 1;
439 if (is_Conv(high_l) && get_Conv_op(high_l) == low) return 1;
440 } else if (is_Const(low) && is_Const(high)) {
441 tarval *tl = get_Const_tarval(low);
442 tarval *th = get_Const_tarval(high);
444 if (tarval_is_long(th) && tarval_is_long(tl)) {
445 long l = get_tarval_long(tl);
446 long h = get_tarval_long(th);
448 return (h == 0 && l >= 0) || (h == -1 && l < 0);
456 * Map a Mul (a_l, a_h, b_l, b_h)
458 static int map_Mul(ir_node *call, void *ctx) {
459 ir_graph *irg = current_ir_graph;
460 dbg_info *dbg = get_irn_dbg_info(call);
461 ir_node *block = get_nodes_block(call);
462 ir_node **params = get_Call_param_arr(call);
463 ir_type *method = get_Call_type(call);
464 ir_node *a_l = params[BINOP_Left_Low];
465 ir_node *a_h = params[BINOP_Left_High];
466 ir_node *b_l = params[BINOP_Right_Low];
467 ir_node *b_h = params[BINOP_Right_High];
468 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
469 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
470 ir_node *l_res, *h_res, *mul, *pEDX, *add;
483 /* handle the often used case of 32x32=64 mul */
484 if (is_sign_extend(a_l, a_h) && is_sign_extend(b_l, b_h)) {
485 mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
486 h_res = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
487 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
492 mul = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
493 pEDX = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
494 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
496 b_l = new_rd_Conv(dbg, irg, block, b_l, h_mode);
497 mul = new_rd_Mul( dbg, irg, block, a_h, b_l, h_mode);
498 add = new_rd_Add( dbg, irg, block, mul, pEDX, h_mode);
499 a_l = new_rd_Conv(dbg, irg, block, a_l, h_mode);
500 mul = new_rd_Mul( dbg, irg, block, a_l, b_h, h_mode);
501 h_res = new_rd_Add( dbg, irg, block, add, mul, h_mode);
504 resolve_call(call, l_res, h_res, irg, block);
510 * Map a Minus (a_l, a_h)
512 static int map_Minus(ir_node *call, void *ctx) {
513 ir_graph *irg = current_ir_graph;
514 dbg_info *dbg = get_irn_dbg_info(call);
515 ir_node *block = get_nodes_block(call);
516 ir_node **params = get_Call_param_arr(call);
517 ir_type *method = get_Call_type(call);
518 ir_node *a_l = params[BINOP_Left_Low];
519 ir_node *a_h = params[BINOP_Left_High];
520 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
521 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
522 ir_node *l_res, *h_res, *res;
525 res = new_rd_ia32_Minus64Bit(dbg, irg, block, a_l, a_h);
526 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
527 h_res = new_r_Proj(irg, block, res, h_mode, pn_ia32_Minus64Bit_high_res);
529 resolve_call(call, l_res, h_res, irg, block);
535 * Map a Abs (a_l, a_h)
537 static int map_Abs(ir_node *call, void *ctx) {
538 ir_graph *irg = current_ir_graph;
539 dbg_info *dbg = get_irn_dbg_info(call);
540 ir_node *block = get_nodes_block(call);
541 ir_node **params = get_Call_param_arr(call);
542 ir_type *method = get_Call_type(call);
543 ir_node *a_l = params[BINOP_Left_Low];
544 ir_node *a_h = params[BINOP_Left_High];
545 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
546 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
547 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
548 ir_node *l_res, *h_res, *sign, *sub_l, *sub_h;
555 Code inspired by gcc output :) (although gcc doubles the
556 operation for t1 as t2 and uses t1 for operations with low part
557 and t2 for operations with high part which is actually unnecessary
558 because t1 and t2 represent the same value)
564 h_res = t3 - t1 - carry
568 /* TODO: give a hint to the backend somehow to not create a cltd here... */
569 sign = new_rd_Shrs(dbg, irg, block, a_h, new_Const_long(l_mode, 31), h_mode);
570 sign_l = new_rd_Conv(dbg, irg, block, sign, l_mode);
571 sub_l = new_rd_Eor(dbg, irg, block, a_l, sign_l, l_mode);
572 sub_h = new_rd_Eor(dbg, irg, block, a_h, sign, h_mode);
574 l_sub = new_rd_ia32_l_Sub(dbg, irg, block, sub_l, sign_l, mode_T);
575 l_res = new_r_Proj(irg, block, l_sub, l_mode, pn_ia32_res);
576 flags = new_r_Proj(irg, block, l_sub, mode_flags, pn_ia32_flags);
577 h_res = new_rd_ia32_l_Sbb(dbg, irg, block, sub_h, sign, flags, h_mode);
579 resolve_call(call, l_res, h_res, irg, block);
584 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
587 * Maps a Div. Change into a library call
589 static int map_Div(ir_node *call, void *ctx) {
590 ia32_intrinsic_env_t *env = ctx;
591 ir_type *method = get_Call_type(call);
592 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
597 if (mode_is_signed(h_mode)) {
598 /* 64bit signed Division */
601 /* create library entity */
602 ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
603 set_entity_visibility(ent, visibility_external_allocated);
604 set_entity_ld_ident(ent, ID("__divdi3"));
607 /* 64bit unsigned Division */
610 /* create library entity */
611 ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
612 set_entity_visibility(ent, visibility_external_allocated);
613 set_entity_ld_ident(ent, ID("__udivdi3"));
617 ptr = get_Call_ptr(call);
618 set_SymConst_symbol(ptr, sym);
623 * Maps a Mod. Change into a library call
625 static int map_Mod(ir_node *call, void *ctx) {
626 ia32_intrinsic_env_t *env = ctx;
627 ir_type *method = get_Call_type(call);
628 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 0));
633 if (mode_is_signed(h_mode)) {
634 /* 64bit signed Modulo */
637 /* create library entity */
638 ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
639 set_entity_visibility(ent, visibility_external_allocated);
640 set_entity_ld_ident(ent, ID("__moddi3"));
643 /* 64bit signed Modulo */
646 /* create library entity */
647 ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
648 set_entity_visibility(ent, visibility_external_allocated);
649 set_entity_ld_ident(ent, ID("__umoddi3"));
653 ptr = get_Call_ptr(call);
654 set_SymConst_symbol(ptr, sym);
661 static int map_Conv(ir_node *call, void *ctx) {
662 ia32_intrinsic_env_t *env = ctx;
663 ir_graph *irg = current_ir_graph;
664 dbg_info *dbg = get_irn_dbg_info(call);
665 ir_node *block = get_nodes_block(call);
666 ir_node **params = get_Call_param_arr(call);
667 ir_type *method = get_Call_type(call);
668 int n = get_Call_n_params(call);
669 int gp_bytes = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
671 ir_node *l_res, *h_res, *frame, *fres;
672 ir_node *store_l, *store_h;
673 ir_node *op_mem[2], *mem;
676 /* We have a Conv float -> long long here */
677 ir_node *a_f = params[0];
678 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
679 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
681 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
683 /* allocate memory on frame to store args */
684 ent = env->irg == irg ? env->d_ll_conv : NULL;
686 ent = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
691 frame = get_irg_frame(irg);
694 Now we create a node to move the value from a XMM register into
695 x87 FPU because it is unknown here, which FPU is used.
696 This node is killed in transformation phase when not needed.
697 Otherwise it is split up into a movsd + fld
699 a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
700 set_ia32_frame_ent(a_f, ent);
701 set_ia32_use_frame(a_f);
702 set_ia32_ls_mode(a_f, mode_D);
704 if (mode_is_signed(h_res_mode)) {
705 /* a float to signed conv, the simple case */
707 /* store from FPU as Int */
708 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
709 set_ia32_frame_ent(a_f, ent);
710 set_ia32_use_frame(a_f);
711 set_ia32_ls_mode(a_f, mode_Ls);
714 /* load low part of the result */
715 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
716 set_ia32_frame_ent(l_res, ent);
717 set_ia32_use_frame(l_res);
718 set_ia32_ls_mode(l_res, l_res_mode);
719 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
721 /* load hight part of the result */
722 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
723 set_ia32_frame_ent(h_res, ent);
724 add_ia32_am_offs_int(h_res, gp_bytes);
725 set_ia32_use_frame(h_res);
726 set_ia32_ls_mode(h_res, h_res_mode);
727 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
729 /* a float to unsigned conv, more complicated */
730 panic("Float->unsigned64 NYI\n");
734 resolve_call(call, l_res, h_res, irg, block);
737 /* We have a Conv long long -> float here */
738 ir_node *a_l = params[BINOP_Left_Low];
739 ir_node *a_h = params[BINOP_Left_High];
740 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
742 assert(! mode_is_float(get_irn_mode(a_l))
743 && ! mode_is_float(get_irn_mode(a_h)));
745 /* allocate memory on frame to store args */
746 ent = env->irg == irg ? env->ll_d_conv : NULL;
748 ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
753 frame = get_irg_frame(irg);
755 /* store first arg (low part) */
756 store_l = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
757 set_ia32_frame_ent(store_l, ent);
758 set_ia32_use_frame(store_l);
759 set_ia32_ls_mode(store_l, get_irn_mode(a_l));
762 /* store second arg (high part) */
763 store_h = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
764 set_ia32_frame_ent(store_h, ent);
765 add_ia32_am_offs_int(store_h, gp_bytes);
766 set_ia32_use_frame(store_h);
767 set_ia32_ls_mode(store_h, get_irn_mode(a_h));
770 mem = new_r_Sync(irg, block, 2, op_mem);
772 /* Load arg into x87 FPU (implicit convert) */
773 fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
774 set_ia32_frame_ent(fres, ent);
775 set_ia32_use_frame(fres);
776 set_ia32_ls_mode(fres, mode_D);
777 mem = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
778 fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);
781 Now we create a node to move the loaded value into a XMM
782 register because it is unknown here, which FPU is used.
783 This node is killed in transformation phase when not needed.
784 Otherwise it is split up into a fst + movsd
786 fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
787 set_ia32_frame_ent(fres, ent);
788 set_ia32_use_frame(fres);
789 set_ia32_ls_mode(fres, fres_mode);
792 resolve_call(call, fres, NULL, irg, block);
795 assert(0 && "unexpected Conv call");
801 /* Ia32 implementation of intrinsic mapping. */
802 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
803 const ir_mode *imode, const ir_mode *omode,
807 ir_entity **ent = NULL;
808 i_mapper_func mapper;
811 intrinsics = NEW_ARR_F(i_record, 0);
813 switch (get_op_code(op)) {
815 ent = &i_ents[iro_Add];
819 ent = &i_ents[iro_Sub];
823 ent = &i_ents[iro_Shl];
827 ent = &i_ents[iro_Shr];
831 ent = &i_ents[iro_Shrs];
835 ent = &i_ents[iro_Mul];
839 ent = &i_ents[iro_Minus];
843 ent = &i_ents[iro_Abs];
847 ent = &i_ents[iro_Div];
851 ent = &i_ents[iro_Mod];
855 ent = &i_ents[iro_Conv];
859 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
860 return def_create_intrinsic_fkt(method, op, imode, omode, context);
864 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
866 ident *id = mangle(IDENT("L"), get_op_ident(op));
867 *ent = new_entity(get_glob_type(), id, method);
870 elt.i_call.kind = INTRINSIC_CALL;
871 elt.i_call.i_ent = *ent;
872 elt.i_call.i_mapper = mapper;
873 elt.i_call.ctx = context;
874 elt.i_call.link = NULL;
876 ARR_APP1(i_record, intrinsics, elt);