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) {
70 ir_node *bad = get_irg_bad(irg);
71 ir_node *nomem = get_irg_no_mem(irg);
75 res = new_r_Tuple(irg, block, h_res == NULL ? 1 : 2, in);
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);
91 * Map an Add (a_l, a_h, b_l, b_h)
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;
110 /* l_res = a_l + b_l */
111 /* h_res = a_h + b_h + carry */
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);
117 l_res = new_r_Proj(irg, block, add_low, l_mode, pn_ia32_res);
120 resolve_call(call, l_res, h_res, irg, block);
125 * Map a Sub (a_l, a_h, b_l, b_h)
127 static int map_Sub(ir_node *call, void *ctx)
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;
145 /* l_res = a_l - b_l */
146 /* h_res = a_h - b_h - carry */
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);
152 l_res = new_r_Proj(irg, block, sub_low, l_mode, pn_ia32_res);
155 resolve_call(call, l_res, h_res, irg, block);
160 * Map a Shl (a_l, a_h, count)
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));
174 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
178 /* the shift count is a const, create better code */
179 tarval *tv = get_Const_tarval(cnt);
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));
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);
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);
196 resolve_call(call, l_res, h_res, irg, block);
201 upper = get_nodes_block(call);
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);
206 /* l_res = SHL a_l, cnt */
207 l1 = new_rd_ia32_l_ShlDep(dbg, irg, upper, a_l, cnt, h1, l_mode);
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);
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);
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);
225 set_irn_in(block, 2, in);
229 l_res = new_r_Phi(irg, block, 2, in, l_mode);
230 set_irn_link(block, l_res);
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);
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);
243 resolve_call(call, l_res, h_res, irg, block);
248 * Map a Shr (a_l, a_h, count)
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));
262 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
266 /* the shift count is a const, create better code */
267 tarval *tv = get_Const_tarval(cnt);
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);
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);
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);
282 resolve_call(call, l_res, h_res, irg, block);
287 upper = get_nodes_block(call);
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);
292 /* h_res = SHR a_h, cnt */
293 h1 = new_rd_ia32_l_ShrDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
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);
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);
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);
311 set_irn_in(block, 2, in);
315 l_res = new_r_Phi(irg, block, 2, in, l_mode);
316 set_irn_link(block, l_res);
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);
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);
329 resolve_call(call, l_res, h_res, irg, block);
334 * Map a Shrs (a_l, a_h, count)
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));
348 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
352 /* the shift count is a const, create better code */
353 tarval *tv = get_Const_tarval(cnt);
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);
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);
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);
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);
370 resolve_call(call, l_res, h_res, irg, block);
375 upper = get_nodes_block(call);
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);
380 /* h_res = SAR a_h, cnt */
381 h1 = new_rd_ia32_l_SarDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
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);
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);
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);
399 set_irn_in(block, 2, in);
403 l_res = new_r_Phi(irg, block, 2, in, l_mode);
404 set_irn_link(block, l_res);
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);
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);
417 resolve_call(call, l_res, h_res, irg, block);
421 static int is_sign_extend(ir_node *low, ir_node *high)
428 high_r = get_Shrs_right(high);
429 if (!is_Const(high_r)) return 0;
431 shift_count = get_Const_tarval(high_r);
432 if (!tarval_is_long(shift_count)) return 0;
433 if (get_tarval_long(shift_count) != 31) return 0;
435 high_l = get_Shrs_left(high);
437 if (is_Conv(low) && get_Conv_op(low) == high_l) return 1;
438 if (is_Conv(high_l) && get_Conv_op(high_l) == low) return 1;
439 } else if (is_Const(low) && is_Const(high)) {
440 tarval *tl = get_Const_tarval(low);
441 tarval *th = get_Const_tarval(high);
443 if (tarval_is_long(th) && tarval_is_long(tl)) {
444 long l = get_tarval_long(tl);
445 long h = get_tarval_long(th);
447 return (h == 0 && l >= 0) || (h == -1 && l < 0);
455 * Map a Mul (a_l, a_h, b_l, b_h)
457 static int map_Mul(ir_node *call, void *ctx) {
458 ir_graph *irg = current_ir_graph;
459 dbg_info *dbg = get_irn_dbg_info(call);
460 ir_node *block = get_nodes_block(call);
461 ir_node **params = get_Call_param_arr(call);
462 ir_type *method = get_Call_type(call);
463 ir_node *a_l = params[BINOP_Left_Low];
464 ir_node *a_h = params[BINOP_Left_High];
465 ir_node *b_l = params[BINOP_Right_Low];
466 ir_node *b_h = params[BINOP_Right_High];
467 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
468 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
469 ir_node *l_res, *h_res, *mul, *pEDX, *add;
482 /* handle the often used case of 32x32=64 mul */
483 if (is_sign_extend(a_l, a_h) && is_sign_extend(b_l, b_h)) {
484 mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
485 h_res = 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);
491 mul = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
492 pEDX = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
493 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
495 b_l = new_rd_Conv(dbg, irg, block, b_l, h_mode);
496 mul = new_rd_Mul( dbg, irg, block, a_h, b_l, h_mode);
497 add = new_rd_Add( dbg, irg, block, mul, pEDX, h_mode);
498 a_l = new_rd_Conv(dbg, irg, block, a_l, h_mode);
499 mul = new_rd_Mul( dbg, irg, block, a_l, b_h, h_mode);
500 h_res = new_rd_Add( dbg, irg, block, add, mul, h_mode);
503 resolve_call(call, l_res, h_res, irg, block);
509 * Map a Minus (a_l, a_h)
511 static int map_Minus(ir_node *call, void *ctx) {
512 ir_graph *irg = current_ir_graph;
513 dbg_info *dbg = get_irn_dbg_info(call);
514 ir_node *block = get_nodes_block(call);
515 ir_node **params = get_Call_param_arr(call);
516 ir_type *method = get_Call_type(call);
517 ir_node *a_l = params[BINOP_Left_Low];
518 ir_node *a_h = params[BINOP_Left_High];
519 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
520 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
521 ir_node *l_res, *h_res, *res;
524 res = new_rd_ia32_Minus64Bit(dbg, irg, block, a_l, a_h);
525 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
526 h_res = new_r_Proj(irg, block, res, h_mode, pn_ia32_Minus64Bit_high_res);
528 resolve_call(call, l_res, h_res, irg, block);
534 * Map a Abs (a_l, a_h)
536 static int map_Abs(ir_node *call, void *ctx) {
537 ir_graph *irg = current_ir_graph;
538 dbg_info *dbg = get_irn_dbg_info(call);
539 ir_node *block = get_nodes_block(call);
540 ir_node **params = get_Call_param_arr(call);
541 ir_type *method = get_Call_type(call);
542 ir_node *a_l = params[BINOP_Left_Low];
543 ir_node *a_h = params[BINOP_Left_High];
544 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
545 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
546 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
547 ir_node *l_res, *h_res, *sign, *sub_l, *sub_h;
554 Code inspired by gcc output :) (although gcc doubles the
555 operation for t1 as t2 and uses t1 for operations with low part
556 and t2 for operations with high part which is actually unnecessary
557 because t1 and t2 represent the same value)
563 h_res = t3 - t1 - carry
567 /* TODO: give a hint to the backend somehow to not create a cltd here... */
568 sign = new_rd_Shrs(dbg, irg, block, a_h, new_Const_long(l_mode, 31), h_mode);
569 sign_l = new_rd_Conv(dbg, irg, block, sign, l_mode);
570 sub_l = new_rd_Eor(dbg, irg, block, a_l, sign_l, l_mode);
571 sub_h = new_rd_Eor(dbg, irg, block, a_h, sign, h_mode);
573 l_sub = new_rd_ia32_l_Sub(dbg, irg, block, sub_l, sign_l, mode_T);
574 l_res = new_r_Proj(irg, block, l_sub, l_mode, pn_ia32_res);
575 flags = new_r_Proj(irg, block, l_sub, mode_flags, pn_ia32_flags);
576 h_res = new_rd_ia32_l_Sbb(dbg, irg, block, sub_h, sign, flags, h_mode);
578 resolve_call(call, l_res, h_res, irg, block);
583 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
586 * Maps a Div. Change into a library call
588 static int map_Div(ir_node *call, void *ctx) {
589 ia32_intrinsic_env_t *env = ctx;
590 ir_type *method = get_Call_type(call);
591 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
596 if (mode_is_signed(h_mode)) {
597 /* 64bit signed Division */
600 /* create library entity */
601 ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
602 set_entity_visibility(ent, visibility_external_allocated);
603 set_entity_ld_ident(ent, ID("__divdi3"));
606 /* 64bit unsigned Division */
609 /* create library entity */
610 ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
611 set_entity_visibility(ent, visibility_external_allocated);
612 set_entity_ld_ident(ent, ID("__udivdi3"));
616 ptr = get_Call_ptr(call);
617 set_SymConst_symbol(ptr, sym);
622 * Maps a Mod. Change into a library call
624 static int map_Mod(ir_node *call, void *ctx) {
625 ia32_intrinsic_env_t *env = ctx;
626 ir_type *method = get_Call_type(call);
627 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 0));
632 if (mode_is_signed(h_mode)) {
633 /* 64bit signed Modulo */
636 /* create library entity */
637 ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
638 set_entity_visibility(ent, visibility_external_allocated);
639 set_entity_ld_ident(ent, ID("__moddi3"));
642 /* 64bit signed Modulo */
645 /* create library entity */
646 ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
647 set_entity_visibility(ent, visibility_external_allocated);
648 set_entity_ld_ident(ent, ID("__umoddi3"));
652 ptr = get_Call_ptr(call);
653 set_SymConst_symbol(ptr, sym);
660 static int map_Conv(ir_node *call, void *ctx) {
661 ia32_intrinsic_env_t *env = ctx;
662 ir_graph *irg = current_ir_graph;
663 dbg_info *dbg = get_irn_dbg_info(call);
664 ir_node *block = get_nodes_block(call);
665 ir_node **params = get_Call_param_arr(call);
666 ir_type *method = get_Call_type(call);
667 int n = get_Call_n_params(call);
668 int gp_bytes = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
670 ir_node *l_res, *h_res, *frame, *fres;
671 ir_node *store_l, *store_h;
672 ir_node *op_mem[2], *mem;
675 /* We have a Conv float -> long long here */
676 ir_node *a_f = params[0];
677 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
678 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
680 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
682 /* allocate memory on frame to store args */
683 ent = env->irg == irg ? env->d_ll_conv : NULL;
685 ent = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
690 frame = get_irg_frame(irg);
693 Now we create a node to move the value from a XMM register into
694 x87 FPU because it is unknown here, which FPU is used.
695 This node is killed in transformation phase when not needed.
696 Otherwise it is split up into a movsd + fld
698 a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
699 set_ia32_frame_ent(a_f, ent);
700 set_ia32_use_frame(a_f);
701 set_ia32_ls_mode(a_f, mode_D);
703 /* store from FPU as Int */
704 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
705 set_ia32_frame_ent(a_f, ent);
706 set_ia32_use_frame(a_f);
707 set_ia32_ls_mode(a_f, mode_Ls);
710 /* load low part of the result */
711 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
712 set_ia32_frame_ent(l_res, ent);
713 set_ia32_use_frame(l_res);
714 set_ia32_ls_mode(l_res, l_res_mode);
715 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
717 /* load hight part of the result */
718 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
719 set_ia32_frame_ent(h_res, ent);
720 add_ia32_am_offs_int(h_res, gp_bytes);
721 set_ia32_use_frame(h_res);
722 set_ia32_ls_mode(h_res, h_res_mode);
723 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
726 resolve_call(call, l_res, h_res, irg, block);
729 /* We have a Conv long long -> float here */
730 ir_node *a_l = params[BINOP_Left_Low];
731 ir_node *a_h = params[BINOP_Left_High];
732 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
734 assert(! mode_is_float(get_irn_mode(a_l))
735 && ! mode_is_float(get_irn_mode(a_h)));
737 /* allocate memory on frame to store args */
738 ent = env->irg == irg ? env->ll_d_conv : NULL;
740 ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
745 frame = get_irg_frame(irg);
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));
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));
762 mem = new_r_Sync(irg, block, 2, op_mem);
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);
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
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);
784 resolve_call(call, fres, NULL, irg, block);
787 assert(0 && "unexpected Conv call");
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,
799 ir_entity **ent = NULL;
800 i_mapper_func mapper;
803 intrinsics = NEW_ARR_F(i_record, 0);
805 switch (get_op_code(op)) {
807 ent = &i_ents[iro_Add];
811 ent = &i_ents[iro_Sub];
815 ent = &i_ents[iro_Shl];
819 ent = &i_ents[iro_Shr];
823 ent = &i_ents[iro_Shrs];
827 ent = &i_ents[iro_Mul];
831 ent = &i_ents[iro_Minus];
835 ent = &i_ents[iro_Abs];
839 ent = &i_ents[iro_Div];
843 ent = &i_ents[iro_Mod];
847 ent = &i_ents[iro_Conv];
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);
856 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
858 ident *id = mangle(IDENT("L"), get_op_ident(op));
859 *ent = new_entity(get_glob_type(), id, method);
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;
868 ARR_APP1(i_record, intrinsics, elt);