2 * Copyright (C) 1995-2008 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
35 #include "iroptimize.h"
40 #include "ia32_new_nodes.h"
41 #include "bearch_ia32_t.h"
42 #include "gen_ia32_regalloc_if.h"
45 /** The array of all intrinsics that must be mapped. */
46 static i_record *intrinsics;
48 /** An array to cache all entities. */
49 static ir_entity *i_ents[iro_Last + 1];
52 * Maps all intrinsic calls that the backend support
53 * and map all instructions the backend did not support
56 void ia32_handle_intrinsics(void)
58 if (intrinsics && ARR_LEN(intrinsics) > 0) {
59 lower_intrinsics(intrinsics, ARR_LEN(intrinsics), /*part_block_used=*/1);
63 #define BINOP_Left_Low 0
64 #define BINOP_Left_High 1
65 #define BINOP_Right_Low 2
66 #define BINOP_Right_High 3
69 * Reroute edges from the pn_Call_T_result proj of a call.
71 * @param resproj the pn_Call_T_result Proj
72 * @param l_res the lower 32 bit result
73 * @param h_res the upper 32 bit result or NULL
75 static void reroute_result(ir_node *resproj, ir_node *l_res, ir_node *h_res)
77 const ir_edge_t *edge, *next;
79 foreach_out_edge_safe(resproj, edge, next) {
80 ir_node *proj = get_edge_src_irn(edge);
81 long pn = get_Proj_proj(proj);
84 edges_reroute(proj, l_res);
85 } else if (pn == 1 && h_res != NULL) {
86 edges_reroute(proj, h_res);
88 panic("Unsupported Result-Proj from Call found");
94 * Replace a call be a tuple of l_res, h_res.
96 * @param call the call node to replace
97 * @param l_res the lower 32 bit result
98 * @param h_res the upper 32 bit result or NULL
99 * @param irg the graph to replace on
100 * @param block the block to replace on (always the call block)
102 static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block)
104 ir_node *jmp, *res, *in[2];
105 ir_node *nomem = get_irg_no_mem(irg);
108 if (edges_activated(irg)) {
109 /* use rerouting to prevent some warning in the backend */
110 const ir_edge_t *edge, *next;
112 foreach_out_edge_safe(call, edge, next) {
113 ir_node *proj = get_edge_src_irn(edge);
114 pn_Call pn = (pn_Call)get_Proj_proj(proj);
117 case pn_Call_X_regular:
119 * We do not check here if this call really has exception and regular Proj's.
120 * new_r_Jmp might than be CSEd with the real exit jmp and then bad things happen
121 * (in movgen.c from 186.crafty for example).
122 * So be sure the newly created Jmp cannot CSE.
124 old_cse = get_opt_cse();
126 jmp = new_r_Jmp(block);
127 set_opt_cse(old_cse);
128 edges_reroute(proj, jmp);
131 case pn_Call_X_except:
132 /* should not happen here */
133 edges_reroute(proj, new_r_Bad(irg, mode_X));
136 /* should not happen here */
137 edges_reroute(proj, nomem);
139 case pn_Call_T_result:
140 reroute_result(proj, l_res, h_res);
143 panic("Wrong Proj from Call");
149 /* no edges, build Tuple */
155 res = new_r_Tuple(block, 2, in);
160 * We do not check here if this call really has exception and regular Proj's.
161 * new_r_Jmp might than be CSEd with the real exit jmp and then bad things happen
162 * (in movgen.c from 186.crafty for example).
163 * So be sure the newly created Jmp cannot CSE.
165 old_cse = get_opt_cse();
167 jmp = new_r_Jmp(block);
168 set_opt_cse(old_cse);
170 turn_into_tuple(call, pn_Call_max+1);
171 set_Tuple_pred(call, pn_Call_M, nomem);
172 set_Tuple_pred(call, pn_Call_X_regular, jmp);
173 set_Tuple_pred(call, pn_Call_X_except, new_r_Bad(irg, mode_X));
174 set_Tuple_pred(call, pn_Call_T_result, res);
179 * Map an Add (a_l, a_h, b_l, b_h)
181 static int map_Add(ir_node *call, void *ctx)
183 dbg_info *dbg = get_irn_dbg_info(call);
184 ir_node *block = get_nodes_block(call);
185 ir_node **params = get_Call_param_arr(call);
186 ir_type *method = get_Call_type(call);
187 ir_node *a_l = params[BINOP_Left_Low];
188 ir_node *a_h = params[BINOP_Left_High];
189 ir_node *b_l = params[BINOP_Right_Low];
190 ir_node *b_h = params[BINOP_Right_High];
191 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
192 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
193 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
194 ir_node *add_low, *add_high, *flags;
195 ir_node *l_res, *h_res;
198 /* l_res = a_l + b_l */
199 /* h_res = a_h + b_h + carry */
201 add_low = new_bd_ia32_l_Add(dbg, block, a_l, b_l, mode_T);
202 flags = new_r_Proj(add_low, mode_flags, pn_ia32_flags);
203 add_high = new_bd_ia32_l_Adc(dbg, block, a_h, b_h, flags, h_mode);
205 l_res = new_r_Proj(add_low, l_mode, pn_ia32_res);
208 resolve_call(call, l_res, h_res, current_ir_graph, block);
213 * Map a Sub (a_l, a_h, b_l, b_h)
215 static int map_Sub(ir_node *call, void *ctx)
217 dbg_info *dbg = get_irn_dbg_info(call);
218 ir_node *block = get_nodes_block(call);
219 ir_node **params = get_Call_param_arr(call);
220 ir_type *method = get_Call_type(call);
221 ir_node *a_l = params[BINOP_Left_Low];
222 ir_node *a_h = params[BINOP_Left_High];
223 ir_node *b_l = params[BINOP_Right_Low];
224 ir_node *b_h = params[BINOP_Right_High];
225 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
226 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
227 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
228 ir_node *sub_low, *sub_high, *flags;
229 ir_node *l_res, *h_res;
232 /* l_res = a_l - b_l */
233 /* h_res = a_h - b_h - carry */
235 sub_low = new_bd_ia32_l_Sub(dbg, block, a_l, b_l, mode_T);
236 flags = new_r_Proj(sub_low, mode_flags, pn_ia32_flags);
237 sub_high = new_bd_ia32_l_Sbb(dbg, block, a_h, b_h, flags, h_mode);
239 l_res = new_r_Proj(sub_low, l_mode, pn_ia32_res);
242 resolve_call(call, l_res, h_res, current_ir_graph, block);
247 * Checks where node high is a sign extension of low.
249 static int is_sign_extend(ir_node *low, ir_node *high)
254 ir_tarval *shift_count;
256 high_r = get_Shrs_right(high);
257 if (!is_Const(high_r)) return 0;
259 shift_count = get_Const_tarval(high_r);
260 if (!tarval_is_long(shift_count)) return 0;
261 if (get_tarval_long(shift_count) != 31) return 0;
263 high_l = get_Shrs_left(high);
265 if (is_Conv(low) && get_Conv_op(low) == high_l) return 1;
266 if (is_Conv(high_l) && get_Conv_op(high_l) == low) return 1;
267 } else if (is_Const(low) && is_Const(high)) {
268 ir_tarval *tl = get_Const_tarval(low);
269 ir_tarval *th = get_Const_tarval(high);
271 if (tarval_is_long(th) && tarval_is_long(tl)) {
272 long l = get_tarval_long(tl);
273 long h = get_tarval_long(th);
275 return (h == 0 && l >= 0) || (h == -1 && l < 0);
283 * Map a Mul (a_l, a_h, b_l, b_h)
285 static int map_Mul(ir_node *call, void *ctx)
287 dbg_info *dbg = get_irn_dbg_info(call);
288 ir_node *block = get_nodes_block(call);
289 ir_node **params = get_Call_param_arr(call);
290 ir_type *method = get_Call_type(call);
291 ir_node *a_l = params[BINOP_Left_Low];
292 ir_node *a_h = params[BINOP_Left_High];
293 ir_node *b_l = params[BINOP_Right_Low];
294 ir_node *b_h = params[BINOP_Right_High];
295 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
296 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
297 ir_node *l_res, *h_res, *mul, *pEDX, *add;
310 /* handle the often used case of 32x32=64 mul */
311 if (is_sign_extend(a_l, a_h) && is_sign_extend(b_l, b_h)) {
312 mul = new_bd_ia32_l_IMul(dbg, block, a_l, b_l);
313 h_res = new_rd_Proj(dbg, mul, h_mode, pn_ia32_l_IMul_res_high);
314 l_res = new_rd_Proj(dbg, mul, l_mode, pn_ia32_l_IMul_res_low);
316 /* note that zero extension is handled hare efficiently */
317 mul = new_bd_ia32_l_Mul(dbg, block, a_l, b_l);
318 pEDX = new_rd_Proj(dbg, mul, h_mode, pn_ia32_l_Mul_res_high);
319 l_res = new_rd_Proj(dbg, mul, l_mode, pn_ia32_l_Mul_res_low);
321 b_l = new_rd_Conv(dbg, block, b_l, h_mode);
322 mul = new_rd_Mul( dbg, block, a_h, b_l, h_mode);
323 add = new_rd_Add( dbg, block, mul, pEDX, h_mode);
324 a_l = new_rd_Conv(dbg, block, a_l, h_mode);
325 mul = new_rd_Mul( dbg, block, a_l, b_h, h_mode);
326 h_res = new_rd_Add( dbg, block, add, mul, h_mode);
328 resolve_call(call, l_res, h_res, current_ir_graph, block);
334 * Map a Minus (a_l, a_h)
336 static int map_Minus(ir_node *call, void *ctx)
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_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
345 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
346 ir_node *l_res, *h_res, *res;
349 res = new_bd_ia32_Minus64Bit(dbg, block, a_l, a_h);
350 l_res = new_r_Proj(res, l_mode, pn_ia32_Minus64Bit_low_res);
351 h_res = new_r_Proj(res, h_mode, pn_ia32_Minus64Bit_high_res);
353 resolve_call(call, l_res, h_res, current_ir_graph, block);
360 * Map a Abs (a_l, a_h)
362 static int map_Abs(ir_node *call, void *ctx)
364 dbg_info *dbg = get_irn_dbg_info(call);
365 ir_node *block = get_nodes_block(call);
366 ir_node **params = get_Call_param_arr(call);
367 ir_type *method = get_Call_type(call);
368 ir_node *a_l = params[BINOP_Left_Low];
369 ir_node *a_h = params[BINOP_Left_High];
370 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
371 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
372 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
373 ir_node *l_res, *h_res, *sign, *sub_l, *sub_h;
380 Code inspired by gcc output :) (although gcc doubles the
381 operation for t1 as t2 and uses t1 for operations with low part
382 and t2 for operations with high part which is actually unnecessary
383 because t1 and t2 represent the same value)
389 h_res = t3 - t1 - carry
393 /* TODO: give a hint to the backend somehow to not create a cltd here... */
394 sign = new_rd_Shrs(dbg, block, a_h, new_r_Const_long(irg, l_mode, 31), h_mode);
395 sign_l = new_rd_Conv(dbg, block, sign, l_mode);
396 sub_l = new_rd_Eor(dbg, block, a_l, sign_l, l_mode);
397 sub_h = new_rd_Eor(dbg, block, a_h, sign, h_mode);
399 l_sub = new_bd_ia32_l_Sub(dbg, block, sub_l, sign_l, mode_T);
400 l_res = new_r_Proj(l_sub, l_mode, pn_ia32_res);
401 flags = new_r_Proj(l_sub, mode_flags, pn_ia32_flags);
402 h_res = new_bd_ia32_l_Sbb(dbg, block, sub_h, sign, flags, h_mode);
404 resolve_call(call, l_res, h_res, current_ir_graph, block);
410 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
413 * Maps a Div. Change into a library call.
415 static int map_Div(ir_node *call, void *ctx)
417 ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
418 ir_type *method = get_Call_type(call);
419 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
422 ir_graph *irg = get_irn_irg(call);
425 if (mode_is_signed(h_mode)) {
426 /* 64bit signed Division */
429 /* create library entity */
430 ident *id = ID("__divdi3");
431 ent = env->divdi3 = create_compilerlib_entity(id, method);
434 /* 64bit unsigned Division */
437 /* create library entity */
438 ident *id = ID("__udivdi3");
439 ent = env->udivdi3 = create_compilerlib_entity(id, method);
443 ptr = get_Call_ptr(call);
445 ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
446 set_Call_ptr(call, ptr);
452 * Maps a Mod. Change into a library call
454 static int map_Mod(ir_node *call, void *ctx)
456 ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
457 ir_type *method = get_Call_type(call);
458 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
461 ir_graph *irg = get_irn_irg(call);
464 if (mode_is_signed(h_mode)) {
465 /* 64bit signed Modulo */
468 /* create library entity */
469 ident *id = ID("__moddi3");
470 ent = env->moddi3 = create_compilerlib_entity(id, method);
473 /* 64bit signed Modulo */
476 /* create library entity */
477 ident *id = ID("__umoddi3");
478 ent = env->umoddi3 = create_compilerlib_entity(id, method);
482 ptr = get_Call_ptr(call);
484 ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
485 set_Call_ptr(call, ptr);
493 static int map_Conv(ir_node *call, void *ctx)
495 ir_graph *irg = current_ir_graph;
496 dbg_info *dbg = get_irn_dbg_info(call);
497 ir_node *block = get_nodes_block(call);
498 ir_node **params = get_Call_param_arr(call);
499 ir_type *method = get_Call_type(call);
500 int n = get_Call_n_params(call);
501 ir_node *l_res, *h_res;
505 ir_node *float_to_ll;
507 /* We have a Conv float -> long long here */
508 ir_node *a_f = params[0];
509 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
510 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
512 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
514 if (mode_is_signed(h_res_mode)) {
515 /* convert from float to signed 64bit */
516 float_to_ll = new_bd_ia32_l_FloattoLL(dbg, block, a_f);
518 l_res = new_r_Proj(float_to_ll, l_res_mode,
519 pn_ia32_l_FloattoLL_res_low);
520 h_res = new_r_Proj(float_to_ll, h_res_mode,
521 pn_ia32_l_FloattoLL_res_high);
523 /* Convert from float to unsigned 64bit. */
524 ir_mode *flt_mode = get_irn_mode(a_f);
525 ir_tarval *flt_tv = new_tarval_from_str("9223372036854775808", 19, flt_mode);
526 ir_node *flt_corr = new_r_Const(irg, flt_tv);
527 ir_node *lower_blk = block;
529 ir_node *cmp, *proj, *cond, *blk, *int_phi, *flt_phi;
533 upper_blk = get_nodes_block(call);
535 cmp = new_rd_Cmp(dbg, upper_blk, a_f, flt_corr, ir_relation_less);
536 cond = new_rd_Cond(dbg, upper_blk, cmp);
537 in[0] = new_r_Proj(cond, mode_X, pn_Cond_true);
538 in[1] = new_r_Proj(cond, mode_X, pn_Cond_false);
539 blk = new_r_Block(irg, 1, &in[1]);
540 in[1] = new_r_Jmp(blk);
542 set_irn_in(lower_blk, 2, in);
545 in[0] = new_r_Const(irg, get_mode_null(h_res_mode));
546 in[1] = new_r_Const_long(irg, h_res_mode, 0x80000000);
548 int_phi = new_r_Phi(lower_blk, 2, in, h_res_mode);
551 in[1] = new_rd_Sub(dbg, upper_blk, a_f, flt_corr, flt_mode);
553 flt_phi = new_r_Phi(lower_blk, 2, in, flt_mode);
555 /* fix Phi links for next part_block() */
556 set_Block_phis(lower_blk, int_phi);
557 set_Phi_next(int_phi, flt_phi);
558 set_Phi_next(flt_phi, NULL);
560 float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);
562 l_res = new_r_Proj(float_to_ll, l_res_mode,
563 pn_ia32_l_FloattoLL_res_low);
564 h_res = new_r_Proj(float_to_ll, h_res_mode,
565 pn_ia32_l_FloattoLL_res_high);
567 h_res = new_rd_Add(dbg, lower_blk, h_res, int_phi, h_res_mode);
569 /* move the call and its Proj's to the lower block */
570 set_nodes_block(call, lower_blk);
572 for (proj = (ir_node*)get_irn_link(call); proj != NULL;
573 proj = (ir_node*)get_irn_link(proj)) {
574 set_nodes_block(proj, lower_blk);
579 resolve_call(call, l_res, h_res, irg, block);
581 ir_node *ll_to_float;
583 /* We have a Conv long long -> float here */
584 ir_node *a_l = params[BINOP_Left_Low];
585 ir_node *a_h = params[BINOP_Left_High];
586 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
588 assert(! mode_is_float(get_irn_mode(a_l))
589 && ! mode_is_float(get_irn_mode(a_h)));
591 ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
594 resolve_call(call, ll_to_float, NULL, irg, block);
596 panic("unexpected Conv call %+F", call);
602 /* Ia32 implementation of intrinsic mapping. */
603 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
604 const ir_mode *imode, const ir_mode *omode,
608 ir_entity **ent = NULL;
609 i_mapper_func mapper;
612 intrinsics = NEW_ARR_F(i_record, 0);
614 switch (get_op_code(op)) {
616 ent = &i_ents[iro_Add];
620 ent = &i_ents[iro_Sub];
624 ent = &i_ents[iro_Mul];
628 ent = &i_ents[iro_Minus];
632 ent = &i_ents[iro_Div];
636 ent = &i_ents[iro_Mod];
640 ent = &i_ents[iro_Conv];
644 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
645 return def_create_intrinsic_fkt(method, op, imode, omode, context);
649 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
651 ident *id = id_mangle(IDENT("L"), get_op_ident(op));
652 *ent = new_entity(get_glob_type(), id, method);
653 set_entity_visibility(*ent, ir_visibility_private);
656 elt.i_call.kind = INTRINSIC_CALL;
657 elt.i_call.i_ent = *ent;
658 elt.i_call.i_mapper = mapper;
659 elt.i_call.ctx = context;
660 elt.i_call.link = NULL;
662 ARR_APP1(i_record, intrinsics, elt);