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));
59 #define BINOP_Left_Low 0
60 #define BINOP_Left_High 1
61 #define BINOP_Right_Low 2
62 #define BINOP_Right_High 3
65 * Replace a call be a tuple of l_res, h_res.
67 static void resolve_call(ir_node *call, ir_node *l_res, ir_node *h_res, ir_graph *irg, ir_node *block) {
72 res = new_r_Tuple(irg, block, h_res == NULL ? 1 : 2, in);
74 turn_into_tuple(call, pn_Call_max);
75 set_Tuple_pred(call, pn_Call_M_regular, get_irg_no_mem(irg));
76 set_Tuple_pred(call, pn_Call_X_regular, new_r_Jmp(irg, block));
77 set_Tuple_pred(call, pn_Call_X_except, get_irg_bad(irg));
78 set_Tuple_pred(call, pn_Call_T_result, res);
79 set_Tuple_pred(call, pn_Call_M_except, get_irg_no_mem(irg));
80 set_Tuple_pred(call, pn_Call_P_value_res_base, get_irg_bad(irg));
84 * Map an Add (a_l, a_h, b_l, b_h)
86 static int map_Add(ir_node *call, void *ctx) {
87 ir_graph *irg = current_ir_graph;
88 dbg_info *dbg = get_irn_dbg_info(call);
89 ir_node *block = get_nodes_block(call);
90 ir_node **params = get_Call_param_arr(call);
91 ir_type *method = get_Call_type(call);
92 ir_node *a_l = params[BINOP_Left_Low];
93 ir_node *a_h = params[BINOP_Left_High];
94 ir_node *b_l = params[BINOP_Right_Low];
95 ir_node *b_h = params[BINOP_Right_High];
96 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
97 ir_node *l_res, *h_res, *add;
100 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
102 /* l_res = a_l + b_l */
103 /* h_res = a_h + b_h + carry */
105 add = new_rd_ia32_Add64Bit(dbg, irg, block, a_l, a_h, b_l, b_h);
106 l_res = new_r_Proj(irg, block, add, l_mode, pn_ia32_Add64Bit_low_res);
107 h_res = new_r_Proj(irg, block, add, l_mode, pn_ia32_Add64Bit_high_res);
109 resolve_call(call, l_res, h_res, irg, block);
114 * Map a Sub (a_l, a_h, b_l, b_h)
116 static int map_Sub(ir_node *call, void *ctx) {
117 ir_graph *irg = current_ir_graph;
118 dbg_info *dbg = get_irn_dbg_info(call);
119 ir_node *block = get_nodes_block(call);
120 ir_node **params = get_Call_param_arr(call);
121 ir_type *method = get_Call_type(call);
122 ir_node *a_l = params[BINOP_Left_Low];
123 ir_node *a_h = params[BINOP_Left_High];
124 ir_node *b_l = params[BINOP_Right_Low];
125 ir_node *b_h = params[BINOP_Right_High];
126 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
127 ir_node *l_res, *h_res, *res;
130 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
132 /* l_res = a_l - b_l */
133 /* h_res = a_h - b_h - carry */
135 res = new_rd_ia32_Sub64Bit(dbg, irg, block, a_l, a_h, b_l, b_h);
136 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
137 h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);
139 resolve_call(call, l_res, h_res, irg, block);
144 * Map a Shl (a_l, a_h, count)
146 static int map_Shl(ir_node *call, void *ctx) {
147 ir_graph *irg = current_ir_graph;
148 dbg_info *dbg = get_irn_dbg_info(call);
149 ir_node *block = get_nodes_block(call);
150 ir_node **params = get_Call_param_arr(call);
151 ir_type *method = get_Call_type(call);
152 ir_node *a_l = params[BINOP_Left_Low];
153 ir_node *a_h = params[BINOP_Left_High];
154 ir_node *cnt = params[BINOP_Right_Low];
155 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
156 ir_node *l_res, *h_res;
159 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
161 /* h_res = SHLD a_h, a_l, cnt */
162 h_res = new_rd_ia32_l_ShlD(dbg, irg, block, a_h, a_l, cnt, l_mode);
164 /* l_res = SHL a_l, cnt */
165 l_res = new_rd_ia32_l_ShlDep(dbg, irg, block, a_l, cnt, h_res, l_mode);
167 resolve_call(call, l_res, h_res, irg, block);
172 * Map a Shr (a_l, a_h, count)
174 static int map_Shr(ir_node *call, void *ctx) {
175 ir_graph *irg = current_ir_graph;
176 dbg_info *dbg = get_irn_dbg_info(call);
177 ir_node *block = get_nodes_block(call);
178 ir_node **params = get_Call_param_arr(call);
179 ir_type *method = get_Call_type(call);
180 ir_node *a_l = params[BINOP_Left_Low];
181 ir_node *a_h = params[BINOP_Left_High];
182 ir_node *cnt = params[BINOP_Right_Low];
183 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
184 ir_node *l_res, *h_res;
187 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
189 /* l_res = SHRD a_h:a_l, cnt */
190 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
192 /* h_res = SHR a_h, cnt */
193 h_res = new_rd_ia32_l_ShrDep(dbg, irg, block, a_h, cnt, l_res, l_mode);
195 resolve_call(call, l_res, h_res, irg, block);
200 * Map a Shrs (a_l, a_h, count)
202 static int map_Shrs(ir_node *call, void *ctx) {
203 ir_graph *irg = current_ir_graph;
204 dbg_info *dbg = get_irn_dbg_info(call);
205 ir_node *block = get_nodes_block(call);
206 ir_node **params = get_Call_param_arr(call);
207 ir_type *method = get_Call_type(call);
208 ir_node *a_l = params[BINOP_Left_Low];
209 ir_node *a_h = params[BINOP_Left_High];
210 ir_node *cnt = params[BINOP_Right_Low];
211 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
212 ir_node *l_res, *h_res;
215 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
217 /* l_res = SHRD a_h:a_l, cnt */
218 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
220 /* h_res = SAR a_h, cnt */
221 h_res = new_rd_ia32_l_SarDep(dbg, irg, block, a_h, cnt, l_res, l_mode);
223 resolve_call(call, l_res, h_res, irg, block);
228 * Map a Mul (a_l, a_h, b_l, b_h)
230 static int map_Mul(ir_node *call, void *ctx) {
231 ir_graph *irg = current_ir_graph;
232 dbg_info *dbg = get_irn_dbg_info(call);
233 ir_node *block = get_nodes_block(call);
234 ir_node **params = get_Call_param_arr(call);
235 ir_type *method = get_Call_type(call);
236 ir_node *a_l = params[BINOP_Left_Low];
237 ir_node *a_h = params[BINOP_Left_High];
238 ir_node *b_l = params[BINOP_Right_Low];
239 ir_node *b_h = params[BINOP_Right_High];
240 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
241 ir_node *l_res, *h_res, *mul, *pEDX, *add;
244 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
255 mul = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
256 pEDX = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
257 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
259 mul = new_rd_Mul(dbg, irg, block, a_h, b_l, l_mode);
260 add = new_rd_Add(dbg, irg, block, mul, pEDX, l_mode);
261 mul = new_rd_Mul(dbg, irg, block, a_l, b_h, l_mode);
262 h_res = new_rd_Add(dbg, irg, block, add, mul, l_mode);
264 resolve_call(call, l_res, h_res, irg, block);
270 * Map a Minus (a_l, a_h)
272 static int map_Minus(ir_node *call, void *ctx) {
273 ir_graph *irg = current_ir_graph;
274 dbg_info *dbg = get_irn_dbg_info(call);
275 ir_node *block = get_nodes_block(call);
276 ir_node **params = get_Call_param_arr(call);
277 ir_type *method = get_Call_type(call);
278 ir_node *a_l = params[BINOP_Left_Low];
279 ir_node *a_h = params[BINOP_Left_High];
280 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
281 ir_node *l_res, *h_res, *cnst, *res;
284 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
286 /* too bad: we need 0 in a register here */
287 cnst = new_Const_long(l_mode, 0);
289 /* l_res = 0 - a_l */
290 /* h_res = 0 - a_h - carry */
292 res = new_rd_ia32_Minus64Bit(dbg, irg, block, cnst, a_l, a_h);
293 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
294 h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_high_res);
296 resolve_call(call, l_res, h_res, irg, block);
302 * Map a Abs (a_l, a_h)
304 static int map_Abs(ir_node *call, void *ctx) {
305 ir_graph *irg = current_ir_graph;
306 dbg_info *dbg = get_irn_dbg_info(call);
307 ir_node *block = get_nodes_block(call);
308 ir_node **params = get_Call_param_arr(call);
309 ir_type *method = get_Call_type(call);
310 ir_node *a_l = params[BINOP_Left_Low];
311 ir_node *a_h = params[BINOP_Left_High];
312 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
313 ir_node *l_res, *h_res, *sign, *sub_l, *sub_h, *res;
316 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
319 Code inspired by gcc output :) (although gcc doubles the
320 operation for t1 as t2 and uses t1 for operations with low part
321 and t2 for operations with high part which is actually unnecessary
322 because t1 and t2 represent the same value)
328 h_res = t3 - t1 - carry
332 sign = new_rd_ia32_l_Sar(dbg, irg, block, a_h, new_Const_long(l_mode, 31), l_mode);
333 sub_l = new_rd_ia32_l_Xor(dbg, irg, block, a_l, sign, l_mode);
334 sub_h = new_rd_ia32_l_Xor(dbg, irg, block, a_h, sign, l_mode);
335 res = new_rd_ia32_Sub64Bit(dbg, irg, block, sub_l, sub_h, sign, sign);
336 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
337 h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);
339 resolve_call(call, l_res, h_res, irg, block);
344 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
347 * Maps a Div. Change into a library call
349 static int map_Div(ir_node *call, void *ctx) {
350 ia32_intrinsic_env_t *env = ctx;
351 ir_type *method = get_Call_type(call);
352 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
357 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
359 if (mode_is_signed(l_mode)) {
360 /* 64bit signed Division */
363 /* create library entity */
364 ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
365 set_entity_visibility(ent, visibility_external_allocated);
366 set_entity_ld_ident(ent, ID("__divdi3"));
369 /* 64bit signed Division */
372 /* create library entity */
373 ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
374 set_entity_visibility(ent, visibility_external_allocated);
375 set_entity_ld_ident(ent, ID("__udivdi3"));
379 ptr = get_Call_ptr(call);
380 set_SymConst_symbol(ptr, sym);
385 * Maps a Mod. Change into a library call
387 static int map_Mod(ir_node *call, void *ctx) {
388 ia32_intrinsic_env_t *env = ctx;
389 ir_type *method = get_Call_type(call);
390 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
395 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
397 if (mode_is_signed(l_mode)) {
398 /* 64bit signed Modulo */
401 /* create library entity */
402 ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
403 set_entity_visibility(ent, visibility_external_allocated);
404 set_entity_ld_ident(ent, ID("__moddi3"));
407 /* 64bit signed Modulo */
410 /* create library entity */
411 ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
412 set_entity_visibility(ent, visibility_external_allocated);
413 set_entity_ld_ident(ent, ID("__umoddi3"));
417 ptr = get_Call_ptr(call);
418 set_SymConst_symbol(ptr, sym);
425 static int map_Conv(ir_node *call, void *ctx) {
426 ia32_intrinsic_env_t *env = ctx;
427 ir_graph *irg = current_ir_graph;
428 dbg_info *dbg = get_irn_dbg_info(call);
429 ir_node *block = get_nodes_block(call);
430 ir_node **params = get_Call_param_arr(call);
431 ir_type *method = get_Call_type(call);
432 int n = get_Call_n_params(call);
433 int gp_bytes = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
435 ir_node *l_res, *h_res, *frame, *fres;
436 ir_node *store_l, *store_h;
437 ir_node *op_mem[2], *mem;
440 /* We have a Conv float -> long long here */
441 ir_node *a_f = params[0];
442 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
443 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
445 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
447 /* allocate memory on frame to store args */
448 ent = env->irg == irg ? env->d_ll_conv : NULL;
450 ent = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
455 frame = get_irg_frame(irg);
458 Now we create a node to move the value from a XMM register into
459 x87 FPU because it is unknown here, which FPU is used.
460 This node is killed in transformation phase when not needed.
461 Otherwise it is split up into a movsd + fld
463 a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
464 set_ia32_frame_ent(a_f, ent);
465 set_ia32_use_frame(a_f);
466 set_ia32_ls_mode(a_f, mode_D);
468 /* store from FPU as Int */
469 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
470 set_ia32_frame_ent(a_f, ent);
471 set_ia32_use_frame(a_f);
472 set_ia32_ls_mode(a_f, mode_D);
475 /* load low part of the result */
476 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
477 set_ia32_frame_ent(l_res, ent);
478 set_ia32_use_frame(l_res);
479 set_ia32_ls_mode(l_res, l_res_mode);
480 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
482 /* load hight part of the result */
483 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
484 set_ia32_frame_ent(h_res, ent);
485 add_ia32_am_offs_int(h_res, gp_bytes);
486 set_ia32_use_frame(h_res);
487 set_ia32_ls_mode(h_res, h_res_mode);
488 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
491 resolve_call(call, l_res, h_res, irg, block);
494 /* We have a Conv long long -> float here */
495 ir_node *a_l = params[BINOP_Left_Low];
496 ir_node *a_h = params[BINOP_Left_High];
497 ir_mode *mode_a_l = get_irn_mode(a_l);
498 ir_mode *mode_a_h = get_irn_mode(a_h);
499 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
501 assert(! mode_is_float(mode_a_l) && ! mode_is_float(mode_a_h) && "unexpected Conv call");
503 /* allocate memory on frame to store args */
504 ent = env->irg == irg ? env->ll_d_conv : NULL;
506 ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
511 frame = get_irg_frame(irg);
513 /* store first arg (low part) */
514 store_l = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
515 set_ia32_frame_ent(store_l, ent);
516 set_ia32_use_frame(store_l);
517 set_ia32_ls_mode(store_l, get_irn_mode(a_l));
520 /* store second arg (high part) */
521 store_h = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
522 set_ia32_frame_ent(store_h, ent);
523 add_ia32_am_offs_int(store_h, gp_bytes);
524 set_ia32_use_frame(store_h);
525 set_ia32_ls_mode(store_h, get_irn_mode(a_h));
528 mem = new_r_Sync(irg, block, 2, op_mem);
530 /* Load arg into x87 FPU (implicit convert) */
531 fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
532 set_ia32_frame_ent(fres, ent);
533 set_ia32_use_frame(fres);
534 set_ia32_ls_mode(fres, mode_D);
535 mem = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
536 fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);
539 Now we create a node to move the loaded value into a XMM
540 register because it is unknown here, which FPU is used.
541 This node is killed in transformation phase when not needed.
542 Otherwise it is split up into a fst + movsd
544 fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
545 set_ia32_frame_ent(fres, ent);
546 set_ia32_use_frame(fres);
547 set_ia32_ls_mode(fres, fres_mode);
550 resolve_call(call, fres, NULL, irg, block);
553 assert(0 && "unexpected Conv call");
559 /* Ia32 implementation of intrinsic mapping. */
560 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
561 const ir_mode *imode, const ir_mode *omode,
565 ir_entity **ent = NULL;
566 i_mapper_func mapper;
569 intrinsics = NEW_ARR_F(i_record, 0);
571 switch (get_op_code(op)) {
573 ent = &i_ents[iro_Add];
577 ent = &i_ents[iro_Sub];
581 ent = &i_ents[iro_Shl];
585 ent = &i_ents[iro_Shr];
589 ent = &i_ents[iro_Shrs];
593 ent = &i_ents[iro_Mul];
597 ent = &i_ents[iro_Minus];
601 ent = &i_ents[iro_Abs];
605 ent = &i_ents[iro_Div];
609 ent = &i_ents[iro_Mod];
613 ent = &i_ents[iro_Conv];
617 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
618 return def_create_intrinsic_fkt(method, op, imode, omode, context);
622 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
624 ident *id = mangle(IDENT("L"), get_op_ident(op));
625 *ent = new_entity(get_glob_type(), id, method);
628 elt.i_call.kind = INTRINSIC_CALL;
629 elt.i_call.i_ent = *ent;
630 elt.i_call.i_mapper = mapper;
631 elt.i_call.ctx = context;
632 elt.i_call.link = NULL;
634 ARR_APP1(i_record, intrinsics, elt);