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
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)
411 static ir_entity *create_compiler_lib_entity(const char *name, ir_type *type)
413 ir_type *glob = get_glob_type();
414 ident *id = new_id_from_str(name);
417 /* Hack: we need to know the type of runtime library we use. Strictly
418 speaking it's not the same as the object-file-format. But in practice
419 the following should be enough */
420 if (be_gas_object_file_format == OBJECT_FILE_FORMAT_MACH_O
421 || be_gas_object_file_format == OBJECT_FILE_FORMAT_COFF) {
422 id = id_mangle3("___", id, "");
424 id = id_mangle3("__", id, "");
426 entity = new_entity(glob, id, type);
427 set_entity_visibility(entity, ir_visibility_external);
428 set_entity_ld_ident(entity, id);
433 * Maps a Div. Change into a library call.
435 static int map_Div(ir_node *call, void *ctx)
437 ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
438 ir_type *method = get_Call_type(call);
439 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
442 ir_graph *irg = get_irn_irg(call);
445 if (mode_is_signed(h_mode)) {
446 /* 64bit signed Division */
449 ent = env->divdi3 = create_compiler_lib_entity("divdi3", method);
452 /* 64bit unsigned Division */
455 /* create library entity */
456 ent = env->udivdi3 = create_compiler_lib_entity("udivdi3", method);
460 ptr = get_Call_ptr(call);
462 ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
463 set_Call_ptr(call, ptr);
469 * Maps a Mod. Change into a library call
471 static int map_Mod(ir_node *call, void *ctx)
473 ia32_intrinsic_env_t *env = (ia32_intrinsic_env_t*)ctx;
474 ir_type *method = get_Call_type(call);
475 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
478 ir_graph *irg = get_irn_irg(call);
481 if (mode_is_signed(h_mode)) {
482 /* 64bit signed Modulo */
485 /* create library entity */
486 ent = env->moddi3 = create_compiler_lib_entity("moddi3", method);
489 /* 64bit signed Modulo */
492 /* create library entity */
493 ent = env->umoddi3 = create_compiler_lib_entity("umoddi3", method);
497 ptr = get_Call_ptr(call);
499 ptr = new_r_SymConst(irg, get_irn_mode(ptr), sym, symconst_addr_ent);
500 set_Call_ptr(call, ptr);
508 static int map_Conv(ir_node *call, void *ctx)
510 ir_graph *irg = current_ir_graph;
511 dbg_info *dbg = get_irn_dbg_info(call);
512 ir_node *block = get_nodes_block(call);
513 ir_node **params = get_Call_param_arr(call);
514 ir_type *method = get_Call_type(call);
515 int n = get_Call_n_params(call);
516 ir_node *l_res, *h_res;
520 ir_node *float_to_ll;
522 /* We have a Conv float -> long long here */
523 ir_node *a_f = params[0];
524 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
525 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
527 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
529 if (mode_is_signed(h_res_mode)) {
530 /* convert from float to signed 64bit */
531 float_to_ll = new_bd_ia32_l_FloattoLL(dbg, block, a_f);
533 l_res = new_r_Proj(float_to_ll, l_res_mode,
534 pn_ia32_l_FloattoLL_res_low);
535 h_res = new_r_Proj(float_to_ll, h_res_mode,
536 pn_ia32_l_FloattoLL_res_high);
538 /* convert from float to signed 64bit */
539 ir_mode *flt_mode = get_irn_mode(a_f);
540 ir_tarval *flt_tv = new_tarval_from_str("9223372036854775808", 19, flt_mode);
541 ir_node *flt_corr = new_r_Const(irg, flt_tv);
542 ir_node *lower_blk = block;
544 ir_node *cmp, *proj, *cond, *blk, *int_phi, *flt_phi;
548 upper_blk = get_nodes_block(call);
550 cmp = new_rd_Cmp(dbg, upper_blk, a_f, flt_corr, ir_relation_less);
551 cond = new_rd_Cond(dbg, upper_blk, cmp);
552 in[0] = new_r_Proj(cond, mode_X, pn_Cond_true);
553 in[1] = new_r_Proj(cond, mode_X, pn_Cond_false);
554 blk = new_r_Block(irg, 1, &in[1]);
555 in[1] = new_r_Jmp(blk);
557 set_irn_in(lower_blk, 2, in);
560 in[0] = new_r_Const(irg, get_mode_null(h_res_mode));
561 in[1] = new_r_Const_long(irg, h_res_mode, 0x80000000);
563 int_phi = new_r_Phi(lower_blk, 2, in, h_res_mode);
566 in[1] = new_rd_Sub(dbg, upper_blk, a_f, flt_corr, flt_mode);
568 flt_phi = new_r_Phi(lower_blk, 2, in, flt_mode);
570 /* fix Phi links for next part_block() */
571 set_Block_phis(lower_blk, int_phi);
572 set_Phi_next(int_phi, flt_phi);
573 set_Phi_next(flt_phi, NULL);
575 float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);
577 l_res = new_r_Proj(float_to_ll, l_res_mode,
578 pn_ia32_l_FloattoLL_res_low);
579 h_res = new_r_Proj(float_to_ll, h_res_mode,
580 pn_ia32_l_FloattoLL_res_high);
582 h_res = new_rd_Add(dbg, lower_blk, h_res, int_phi, h_res_mode);
584 /* move the call and its Proj's to the lower block */
585 set_nodes_block(call, lower_blk);
587 for (proj = (ir_node*)get_irn_link(call); proj != NULL;
588 proj = (ir_node*)get_irn_link(proj)) {
589 set_nodes_block(proj, lower_blk);
594 resolve_call(call, l_res, h_res, irg, block);
596 ir_node *ll_to_float;
598 /* We have a Conv long long -> float here */
599 ir_node *a_l = params[BINOP_Left_Low];
600 ir_node *a_h = params[BINOP_Left_High];
601 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
603 assert(! mode_is_float(get_irn_mode(a_l))
604 && ! mode_is_float(get_irn_mode(a_h)));
606 ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
609 resolve_call(call, ll_to_float, NULL, irg, block);
611 panic("unexpected Conv call %+F", call);
617 /* Ia32 implementation of intrinsic mapping. */
618 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
619 const ir_mode *imode, const ir_mode *omode,
623 ir_entity **ent = NULL;
624 i_mapper_func mapper;
627 intrinsics = NEW_ARR_F(i_record, 0);
629 switch (get_op_code(op)) {
631 ent = &i_ents[iro_Add];
635 ent = &i_ents[iro_Sub];
639 ent = &i_ents[iro_Mul];
643 ent = &i_ents[iro_Minus];
647 ent = &i_ents[iro_Div];
651 ent = &i_ents[iro_Mod];
655 ent = &i_ents[iro_Conv];
659 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
660 return def_create_intrinsic_fkt(method, op, imode, omode, context);
664 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
666 ident *id = id_mangle(IDENT("L"), get_op_ident(op));
667 *ent = new_entity(get_glob_type(), id, method);
668 set_entity_visibility(*ent, ir_visibility_private);
671 elt.i_call.kind = INTRINSIC_CALL;
672 elt.i_call.i_ent = *ent;
673 elt.i_call.i_mapper = mapper;
674 elt.i_call.ctx = context;
675 elt.i_call.link = NULL;
677 ARR_APP1(i_record, intrinsics, elt);