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
34 #include "iroptimize.h"
39 #include "ia32_new_nodes.h"
40 #include "bearch_ia32_t.h"
41 #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_Last + 1];
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)
57 if (intrinsics && ARR_LEN(intrinsics) > 0) {
58 lower_intrinsics(intrinsics, ARR_LEN(intrinsics), /*part_block_used=*/1);
62 #define BINOP_Left_Low 0
63 #define BINOP_Left_High 1
64 #define BINOP_Right_Low 2
65 #define BINOP_Right_High 3
68 * Reroute edges from the pn_Call_T_result proj of a call.
70 * @param resproj the pn_Call_T_result Proj
71 * @param l_res the lower 32 bit result
72 * @param h_res the upper 32 bit result or NULL
74 static void reroute_result(ir_node *resproj, ir_node *l_res, ir_node *h_res)
76 const ir_edge_t *edge, *next;
78 foreach_out_edge_safe(resproj, edge, next) {
79 ir_node *proj = get_edge_src_irn(edge);
80 long pn = get_Proj_proj(proj);
83 edges_reroute(proj, l_res);
84 } else if (pn == 1 && h_res != NULL) {
85 edges_reroute(proj, h_res);
87 panic("Unsupported Result-Proj from Call found");
93 * Replace a call be a tuple of l_res, h_res.
95 * @param call the call node to replace
96 * @param l_res the lower 32 bit result
97 * @param h_res the upper 32 bit result or NULL
98 * @param irg the graph to replace on
99 * @param block the block to replace on (always the call block)
101 static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block)
103 ir_node *jmp, *res, *in[2];
104 ir_node *nomem = get_irg_no_mem(irg);
107 if (edges_activated(irg)) {
108 /* use rerouting to prevent some warning in the backend */
109 const ir_edge_t *edge, *next;
111 foreach_out_edge_safe(call, edge, next) {
112 ir_node *proj = get_edge_src_irn(edge);
113 pn_Call pn = (pn_Call)get_Proj_proj(proj);
116 case pn_Call_X_regular:
118 * We do not check here if this call really has exception and regular Proj's.
119 * new_r_Jmp might than be CSEd with the real exit jmp and then bad things happen
120 * (in movgen.c from 186.crafty for example).
121 * So be sure the newly created Jmp cannot CSE.
123 old_cse = get_opt_cse();
125 jmp = new_r_Jmp(block);
126 set_opt_cse(old_cse);
127 edges_reroute(proj, jmp);
130 case pn_Call_X_except:
131 /* should not happen here */
132 edges_reroute(proj, new_r_Bad(irg, mode_X));
135 /* should not happen here */
136 edges_reroute(proj, nomem);
138 case pn_Call_T_result:
139 reroute_result(proj, l_res, h_res);
142 panic("Wrong Proj from Call");
148 /* no edges, build Tuple */
154 res = new_r_Tuple(block, 2, in);
159 * We do not check here if this call really has exception and regular Proj's.
160 * new_r_Jmp might than be CSEd with the real exit jmp and then bad things happen
161 * (in movgen.c from 186.crafty for example).
162 * So be sure the newly created Jmp cannot CSE.
164 old_cse = get_opt_cse();
166 jmp = new_r_Jmp(block);
167 set_opt_cse(old_cse);
169 turn_into_tuple(call, pn_Call_max+1);
170 set_Tuple_pred(call, pn_Call_M, nomem);
171 set_Tuple_pred(call, pn_Call_X_regular, jmp);
172 set_Tuple_pred(call, pn_Call_X_except, new_r_Bad(irg, mode_X));
173 set_Tuple_pred(call, pn_Call_T_result, res);
178 * Map an Add (a_l, a_h, b_l, b_h)
180 static int map_Add(ir_node *call, void *ctx)
182 dbg_info *dbg = get_irn_dbg_info(call);
183 ir_node *block = get_nodes_block(call);
184 ir_node **params = get_Call_param_arr(call);
185 ir_type *method = get_Call_type(call);
186 ir_node *a_l = params[BINOP_Left_Low];
187 ir_node *a_h = params[BINOP_Left_High];
188 ir_node *b_l = params[BINOP_Right_Low];
189 ir_node *b_h = params[BINOP_Right_High];
190 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
191 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
192 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
193 ir_node *add_low, *add_high, *flags;
194 ir_node *l_res, *h_res;
197 /* l_res = a_l + b_l */
198 /* h_res = a_h + b_h + carry */
200 add_low = new_bd_ia32_l_Add(dbg, block, a_l, b_l, mode_T);
201 flags = new_r_Proj(add_low, mode_flags, pn_ia32_flags);
202 add_high = new_bd_ia32_l_Adc(dbg, block, a_h, b_h, flags, h_mode);
204 l_res = new_r_Proj(add_low, l_mode, pn_ia32_res);
207 resolve_call(call, l_res, h_res, current_ir_graph, block);
212 * Map a Sub (a_l, a_h, b_l, b_h)
214 static int map_Sub(ir_node *call, void *ctx)
216 dbg_info *dbg = get_irn_dbg_info(call);
217 ir_node *block = get_nodes_block(call);
218 ir_node **params = get_Call_param_arr(call);
219 ir_type *method = get_Call_type(call);
220 ir_node *a_l = params[BINOP_Left_Low];
221 ir_node *a_h = params[BINOP_Left_High];
222 ir_node *b_l = params[BINOP_Right_Low];
223 ir_node *b_h = params[BINOP_Right_High];
224 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
225 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
226 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
227 ir_node *sub_low, *sub_high, *flags;
228 ir_node *l_res, *h_res;
231 /* l_res = a_l - b_l */
232 /* h_res = a_h - b_h - carry */
234 sub_low = new_bd_ia32_l_Sub(dbg, block, a_l, b_l, mode_T);
235 flags = new_r_Proj(sub_low, mode_flags, pn_ia32_flags);
236 sub_high = new_bd_ia32_l_Sbb(dbg, block, a_h, b_h, flags, h_mode);
238 l_res = new_r_Proj(sub_low, l_mode, pn_ia32_res);
241 resolve_call(call, l_res, h_res, current_ir_graph, block);
246 * Checks where node high is a sign extension of low.
248 static int is_sign_extend(ir_node *low, ir_node *high)
253 ir_tarval *shift_count;
255 high_r = get_Shrs_right(high);
256 if (!is_Const(high_r)) return 0;
258 shift_count = get_Const_tarval(high_r);
259 if (!tarval_is_long(shift_count)) return 0;
260 if (get_tarval_long(shift_count) != 31) return 0;
262 high_l = get_Shrs_left(high);
264 if (is_Conv(low) && get_Conv_op(low) == high_l) return 1;
265 if (is_Conv(high_l) && get_Conv_op(high_l) == low) return 1;
266 } else if (is_Const(low) && is_Const(high)) {
267 ir_tarval *tl = get_Const_tarval(low);
268 ir_tarval *th = get_Const_tarval(high);
270 if (tarval_is_long(th) && tarval_is_long(tl)) {
271 long l = get_tarval_long(tl);
272 long h = get_tarval_long(th);
274 return (h == 0 && l >= 0) || (h == -1 && l < 0);
282 * Map a Mul (a_l, a_h, b_l, b_h)
284 static int map_Mul(ir_node *call, void *ctx)
286 dbg_info *dbg = get_irn_dbg_info(call);
287 ir_node *block = get_nodes_block(call);
288 ir_node **params = get_Call_param_arr(call);
289 ir_type *method = get_Call_type(call);
290 ir_node *a_l = params[BINOP_Left_Low];
291 ir_node *a_h = params[BINOP_Left_High];
292 ir_node *b_l = params[BINOP_Right_Low];
293 ir_node *b_h = params[BINOP_Right_High];
294 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
295 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
296 ir_node *l_res, *h_res, *mul, *pEDX, *add;
309 /* handle the often used case of 32x32=64 mul */
310 if (is_sign_extend(a_l, a_h) && is_sign_extend(b_l, b_h)) {
311 mul = new_bd_ia32_l_IMul(dbg, block, a_l, b_l);
312 h_res = new_rd_Proj(dbg, mul, h_mode, pn_ia32_l_IMul_res_high);
313 l_res = new_rd_Proj(dbg, mul, l_mode, pn_ia32_l_IMul_res_low);
315 /* note that zero extension is handled hare efficiently */
316 mul = new_bd_ia32_l_Mul(dbg, block, a_l, b_l);
317 pEDX = new_rd_Proj(dbg, mul, h_mode, pn_ia32_l_Mul_res_high);
318 l_res = new_rd_Proj(dbg, mul, l_mode, pn_ia32_l_Mul_res_low);
320 b_l = new_rd_Conv(dbg, block, b_l, h_mode);
321 mul = new_rd_Mul( dbg, block, a_h, b_l, h_mode);
322 add = new_rd_Add( dbg, block, mul, pEDX, h_mode);
323 a_l = new_rd_Conv(dbg, block, a_l, h_mode);
324 mul = new_rd_Mul( dbg, block, a_l, b_h, h_mode);
325 h_res = new_rd_Add( dbg, block, add, mul, h_mode);
327 resolve_call(call, l_res, h_res, current_ir_graph, block);
333 * Map a Minus (a_l, a_h)
335 static int map_Minus(ir_node *call, void *ctx)
337 dbg_info *dbg = get_irn_dbg_info(call);
338 ir_node *block = get_nodes_block(call);
339 ir_node **params = get_Call_param_arr(call);
340 ir_type *method = get_Call_type(call);
341 ir_node *a_l = params[BINOP_Left_Low];
342 ir_node *a_h = params[BINOP_Left_High];
343 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
344 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
345 ir_node *l_res, *h_res, *res;
348 res = new_bd_ia32_Minus64Bit(dbg, block, a_l, a_h);
349 l_res = new_r_Proj(res, l_mode, pn_ia32_Minus64Bit_low_res);
350 h_res = new_r_Proj(res, h_mode, pn_ia32_Minus64Bit_high_res);
352 resolve_call(call, l_res, h_res, current_ir_graph, block);
359 * Map a Abs (a_l, a_h)
361 static int map_Abs(ir_node *call, void *ctx)
363 dbg_info *dbg = get_irn_dbg_info(call);
364 ir_node *block = get_nodes_block(call);
365 ir_node **params = get_Call_param_arr(call);
366 ir_type *method = get_Call_type(call);
367 ir_node *a_l = params[BINOP_Left_Low];
368 ir_node *a_h = params[BINOP_Left_High];
369 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
370 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
371 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
372 ir_node *l_res, *h_res, *sign, *sub_l, *sub_h;
379 Code inspired by gcc output :) (although gcc doubles the
380 operation for t1 as t2 and uses t1 for operations with low part
381 and t2 for operations with high part which is actually unnecessary
382 because t1 and t2 represent the same value)
388 h_res = t3 - t1 - carry
392 /* TODO: give a hint to the backend somehow to not create a cltd here... */
393 sign = new_rd_Shrs(dbg, block, a_h, new_r_Const_long(irg, l_mode, 31), h_mode);
394 sign_l = new_rd_Conv(dbg, block, sign, l_mode);
395 sub_l = new_rd_Eor(dbg, block, a_l, sign_l, l_mode);
396 sub_h = new_rd_Eor(dbg, block, a_h, sign, h_mode);
398 l_sub = new_bd_ia32_l_Sub(dbg, block, sub_l, sign_l, mode_T);
399 l_res = new_r_Proj(l_sub, l_mode, pn_ia32_res);
400 flags = new_r_Proj(l_sub, mode_flags, pn_ia32_flags);
401 h_res = new_bd_ia32_l_Sbb(dbg, block, sub_h, sign, flags, h_mode);
403 resolve_call(call, l_res, h_res, current_ir_graph, block);
409 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
412 * Maps a Div. Change into a library call.
414 static int map_Div(ir_node *call, void *ctx)
416 ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
417 ir_type *method = get_Call_type(call);
418 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
421 ir_graph *irg = get_irn_irg(call);
424 if (mode_is_signed(h_mode)) {
425 /* 64bit signed Division */
428 /* create library entity */
429 ident *id = ID("__divdi3");
430 ent = env->divdi3 = create_compilerlib_entity(id, method);
433 /* 64bit unsigned Division */
436 /* create library entity */
437 ident *id = ID("__udivdi3");
438 ent = env->udivdi3 = create_compilerlib_entity(id, method);
442 ptr = get_Call_ptr(call);
444 ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
445 set_Call_ptr(call, ptr);
451 * Maps a Mod. Change into a library call
453 static int map_Mod(ir_node *call, void *ctx)
455 ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
456 ir_type *method = get_Call_type(call);
457 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
460 ir_graph *irg = get_irn_irg(call);
463 if (mode_is_signed(h_mode)) {
464 /* 64bit signed Modulo */
467 /* create library entity */
468 ident *id = ID("__moddi3");
469 ent = env->moddi3 = create_compilerlib_entity(id, method);
472 /* 64bit signed Modulo */
475 /* create library entity */
476 ident *id = ID("__umoddi3");
477 ent = env->umoddi3 = create_compilerlib_entity(id, method);
481 ptr = get_Call_ptr(call);
483 ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
484 set_Call_ptr(call, ptr);
492 static int map_Conv(ir_node *call, void *ctx)
494 ir_graph *irg = current_ir_graph;
495 dbg_info *dbg = get_irn_dbg_info(call);
496 ir_node *block = get_nodes_block(call);
497 ir_node **params = get_Call_param_arr(call);
498 ir_type *method = get_Call_type(call);
499 int n = get_Call_n_params(call);
500 ir_node *l_res, *h_res;
504 ir_node *float_to_ll;
506 /* We have a Conv float -> long long here */
507 ir_node *a_f = params[0];
508 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
509 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
511 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
513 if (mode_is_signed(h_res_mode)) {
514 /* convert from float to signed 64bit */
515 float_to_ll = new_bd_ia32_l_FloattoLL(dbg, block, a_f);
517 l_res = new_r_Proj(float_to_ll, l_res_mode,
518 pn_ia32_l_FloattoLL_res_low);
519 h_res = new_r_Proj(float_to_ll, h_res_mode,
520 pn_ia32_l_FloattoLL_res_high);
522 /* Convert from float to unsigned 64bit. */
523 ir_mode *flt_mode = get_irn_mode(a_f);
524 ir_tarval *flt_tv = new_tarval_from_str("9223372036854775808", 19, flt_mode);
525 ir_node *flt_corr = new_r_Const(irg, flt_tv);
526 ir_node *lower_blk = block;
528 ir_node *cmp, *proj, *cond, *blk, *int_phi, *flt_phi;
532 upper_blk = get_nodes_block(call);
534 cmp = new_rd_Cmp(dbg, upper_blk, a_f, flt_corr, ir_relation_less);
535 cond = new_rd_Cond(dbg, upper_blk, cmp);
536 in[0] = new_r_Proj(cond, mode_X, pn_Cond_true);
537 in[1] = new_r_Proj(cond, mode_X, pn_Cond_false);
538 blk = new_r_Block(irg, 1, &in[1]);
539 in[1] = new_r_Jmp(blk);
541 set_irn_in(lower_blk, 2, in);
544 in[0] = new_r_Const(irg, get_mode_null(h_res_mode));
545 in[1] = new_r_Const_long(irg, h_res_mode, 0x80000000);
547 int_phi = new_r_Phi(lower_blk, 2, in, h_res_mode);
550 in[1] = new_rd_Sub(dbg, upper_blk, a_f, flt_corr, flt_mode);
552 flt_phi = new_r_Phi(lower_blk, 2, in, flt_mode);
554 /* fix Phi links for next part_block() */
555 set_Block_phis(lower_blk, int_phi);
556 set_Phi_next(int_phi, flt_phi);
557 set_Phi_next(flt_phi, NULL);
559 float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);
561 l_res = new_r_Proj(float_to_ll, l_res_mode,
562 pn_ia32_l_FloattoLL_res_low);
563 h_res = new_r_Proj(float_to_ll, h_res_mode,
564 pn_ia32_l_FloattoLL_res_high);
566 h_res = new_rd_Add(dbg, lower_blk, h_res, int_phi, h_res_mode);
568 /* move the call and its Proj's to the lower block */
569 set_nodes_block(call, lower_blk);
571 for (proj = (ir_node*)get_irn_link(call); proj != NULL;
572 proj = (ir_node*)get_irn_link(proj)) {
573 set_nodes_block(proj, lower_blk);
578 resolve_call(call, l_res, h_res, irg, block);
580 ir_node *ll_to_float;
582 /* We have a Conv long long -> float here */
583 ir_node *a_l = params[BINOP_Left_Low];
584 ir_node *a_h = params[BINOP_Left_High];
585 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
587 assert(! mode_is_float(get_irn_mode(a_l))
588 && ! mode_is_float(get_irn_mode(a_h)));
590 ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
593 resolve_call(call, ll_to_float, NULL, irg, block);
595 panic("unexpected Conv call %+F", call);
601 /* Ia32 implementation of intrinsic mapping. */
602 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
603 const ir_mode *imode, const ir_mode *omode,
607 ir_entity **ent = NULL;
608 i_mapper_func mapper;
611 intrinsics = NEW_ARR_F(i_record, 0);
613 switch (get_op_code(op)) {
615 ent = &i_ents[iro_Add];
619 ent = &i_ents[iro_Sub];
623 ent = &i_ents[iro_Mul];
627 ent = &i_ents[iro_Minus];
631 ent = &i_ents[iro_Div];
635 ent = &i_ents[iro_Mod];
639 ent = &i_ents[iro_Conv];
643 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
644 return def_create_intrinsic_fkt(method, op, imode, omode, context);
648 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
650 ident *id = id_mangle(IDENT("L"), get_op_ident(op));
651 *ent = new_entity(get_glob_type(), id, method);
652 set_entity_visibility(*ent, ir_visibility_private);
655 elt.i_call.kind = INTRINSIC_CALL;
656 elt.i_call.i_ent = *ent;
657 elt.i_call.i_mapper = mapper;
658 elt.i_call.ctx = context;
659 elt.i_call.link = NULL;
661 ARR_APP1(i_record, intrinsics, elt);