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) {
73 res = new_r_Tuple(irg, block, h_res == NULL ? 1 : 2, in);
75 turn_into_tuple(call, pn_Call_max);
76 set_Tuple_pred(call, pn_Call_M_regular, get_irg_no_mem(irg));
77 set_Tuple_pred(call, pn_Call_X_regular, new_r_Jmp(irg, block));
78 set_Tuple_pred(call, pn_Call_X_except, get_irg_bad(irg));
79 set_Tuple_pred(call, pn_Call_T_result, res);
80 set_Tuple_pred(call, pn_Call_M_except, get_irg_no_mem(irg));
81 set_Tuple_pred(call, pn_Call_P_value_res_base, get_irg_bad(irg));
85 * Map an Add (a_l, a_h, b_l, b_h)
87 static int map_Add(ir_node *call, void *ctx) {
88 ir_graph *irg = current_ir_graph;
89 dbg_info *dbg = get_irn_dbg_info(call);
90 ir_node *block = get_nodes_block(call);
91 ir_node **params = get_Call_param_arr(call);
92 ir_type *method = get_Call_type(call);
93 ir_node *a_l = params[BINOP_Left_Low];
94 ir_node *a_h = params[BINOP_Left_High];
95 ir_node *b_l = params[BINOP_Right_Low];
96 ir_node *b_h = params[BINOP_Right_High];
97 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
98 ir_node *l_res, *h_res, *add;
101 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
103 /* l_res = a_l + b_l */
104 /* h_res = a_h + b_h + carry */
106 add = new_rd_ia32_Add64Bit(dbg, irg, block, a_l, a_h, b_l, b_h);
107 l_res = new_r_Proj(irg, block, add, l_mode, pn_ia32_Add64Bit_low_res);
108 h_res = new_r_Proj(irg, block, add, l_mode, pn_ia32_Add64Bit_high_res);
110 resolve_call(call, l_res, h_res, irg, block);
115 * Map a Sub (a_l, a_h, b_l, b_h)
117 static int map_Sub(ir_node *call, void *ctx) {
118 ir_graph *irg = current_ir_graph;
119 dbg_info *dbg = get_irn_dbg_info(call);
120 ir_node *block = get_nodes_block(call);
121 ir_node **params = get_Call_param_arr(call);
122 ir_type *method = get_Call_type(call);
123 ir_node *a_l = params[BINOP_Left_Low];
124 ir_node *a_h = params[BINOP_Left_High];
125 ir_node *b_l = params[BINOP_Right_Low];
126 ir_node *b_h = params[BINOP_Right_High];
127 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
128 ir_node *l_res, *h_res, *res;
131 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
133 /* l_res = a_l - b_l */
134 /* h_res = a_h - b_h - carry */
136 res = new_rd_ia32_Sub64Bit(dbg, irg, block, a_l, a_h, b_l, b_h);
137 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
138 h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);
140 resolve_call(call, l_res, h_res, irg, block);
145 * Map a Shl (a_l, a_h, count)
147 static int map_Shl(ir_node *call, void *ctx) {
148 ir_graph *irg = current_ir_graph;
149 dbg_info *dbg = get_irn_dbg_info(call);
150 ir_node *block = get_nodes_block(call);
151 ir_node **params = get_Call_param_arr(call);
152 ir_type *method = get_Call_type(call);
153 ir_node *a_l = params[BINOP_Left_Low];
154 ir_node *a_h = params[BINOP_Left_High];
155 ir_node *cnt = params[BINOP_Right_Low];
156 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
158 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
161 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
164 /* the shift count is a const, create better code */
165 tarval *tv = get_Const_tarval(cnt);
167 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
168 /* simplest case: shift only the lower bits. Note that there is no
169 need to reduce the constant here, this is done by the hardware. */
170 h_res = new_rd_Shl(dbg, irg, block, a_l, cnt, l_mode);
171 l_res = new_rd_Const(dbg, irg, block, l_mode, get_mode_null(l_mode));
174 /* h_res = SHLD a_h, a_l, cnt */
175 h_res = new_rd_ia32_l_ShlD(dbg, irg, block, a_h, a_l, cnt, l_mode);
177 /* l_res = SHL a_l, cnt */
178 l_res = new_rd_ia32_l_ShlDep(dbg, irg, block, a_l, cnt, h_res, l_mode);
181 resolve_call(call, l_res, h_res, irg, block);
186 upper = get_nodes_block(call);
188 /* h_res = SHLD a_h, a_l, cnt */
189 h1 = new_rd_ia32_l_ShlD(dbg, irg, upper, a_h, a_l, cnt, l_mode);
191 /* l_res = SHL a_l, cnt */
192 l1 = new_rd_ia32_l_ShlDep(dbg, irg, upper, a_l, cnt, h1, l_mode);
194 c_mode = get_irn_mode(cnt);
195 irn = new_r_Const_long(irg, upper, c_mode, 32);
196 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
197 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
198 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
199 cond = new_rd_Cond(dbg, irg, upper, irn);
201 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
202 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
204 /* the block for cnt >= 32 */
205 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
207 l2 = new_r_Const(irg, n_block, l_mode, get_mode_null(l_mode));
208 in[1] = new_r_Jmp(irg, n_block);
210 set_irn_in(block, 2, in);
214 l_res = new_r_Phi(irg, block, 2, in, l_mode);
215 set_irn_link(block, l_res);
219 h_res = new_r_Phi(irg, block, 2, in, l_mode);
220 set_irn_link(l_res, h_res);
221 set_irn_link(h_res, NULL);
224 set_nodes_block(call, block);
225 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
226 set_nodes_block(irn, block);
228 resolve_call(call, l_res, h_res, irg, block);
233 * Map a Shr (a_l, a_h, count)
235 static int map_Shr(ir_node *call, void *ctx) {
236 ir_graph *irg = current_ir_graph;
237 dbg_info *dbg = get_irn_dbg_info(call);
238 ir_node *block = get_nodes_block(call);
239 ir_node **params = get_Call_param_arr(call);
240 ir_type *method = get_Call_type(call);
241 ir_node *a_l = params[BINOP_Left_Low];
242 ir_node *a_h = params[BINOP_Left_High];
243 ir_node *cnt = params[BINOP_Right_Low];
244 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
246 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
249 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
252 /* the shift count is a const, create better code */
253 tarval *tv = get_Const_tarval(cnt);
255 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
256 /* simplest case: shift only the higher bits. Note that there is no
257 need to reduce the constant here, this is done by the hardware. */
258 h_res = new_rd_Const(dbg, irg, block, l_mode, get_mode_null(l_mode));
259 l_res = new_rd_Shr(dbg, irg, block, a_h, cnt, l_mode);
261 /* l_res = SHRD a_h:a_l, cnt */
262 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
264 /* h_res = SHR a_h, cnt */
265 h_res = new_rd_ia32_l_ShrDep(dbg, irg, block, a_h, cnt, l_res, l_mode);
267 resolve_call(call, l_res, h_res, irg, block);
272 upper = get_nodes_block(call);
274 /* l_res = SHRD a_h:a_l, cnt */
275 l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
277 /* h_res = SHR a_h, cnt */
278 h1 = new_rd_ia32_l_ShrDep(dbg, irg, upper, a_h, cnt, l1, l_mode);
280 c_mode = get_irn_mode(cnt);
281 irn = new_r_Const_long(irg, upper, c_mode, 32);
282 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
283 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
284 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
285 cond = new_rd_Cond(dbg, irg, upper, irn);
287 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
288 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
290 /* the block for cnt >= 32 */
291 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
293 h2 = new_r_Const(irg, n_block, l_mode, get_mode_null(l_mode));
294 in[1] = new_r_Jmp(irg, n_block);
296 set_irn_in(block, 2, in);
300 l_res = new_r_Phi(irg, block, 2, in, l_mode);
301 set_irn_link(block, l_res);
305 h_res = new_r_Phi(irg, block, 2, in, l_mode);
306 set_irn_link(l_res, h_res);
307 set_irn_link(h_res, NULL);
310 set_nodes_block(call, block);
311 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
312 set_nodes_block(irn, block);
314 resolve_call(call, l_res, h_res, irg, block);
319 * Map a Shrs (a_l, a_h, count)
321 static int map_Shrs(ir_node *call, void *ctx) {
322 ir_graph *irg = current_ir_graph;
323 dbg_info *dbg = get_irn_dbg_info(call);
324 ir_node *block = get_nodes_block(call);
325 ir_node **params = get_Call_param_arr(call);
326 ir_type *method = get_Call_type(call);
327 ir_node *a_l = params[BINOP_Left_Low];
328 ir_node *a_h = params[BINOP_Left_High];
329 ir_node *cnt = params[BINOP_Right_Low];
330 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
332 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
335 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
338 /* the shift count is a const, create better code */
339 tarval *tv = get_Const_tarval(cnt);
341 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
342 /* simplest case: shift only the higher bits. Note that there is no
343 need to reduce the constant here, this is done by the hardware. */
344 ir_mode *c_mode = get_irn_mode(cnt);
346 h_res = new_rd_Shrs(dbg, irg, block, a_h, new_r_Const_long(irg, block, c_mode, 31), l_mode);
347 l_res = new_rd_Shrs(dbg, irg, block, a_h, cnt, l_mode);
349 /* l_res = SHRD a_h:a_l, cnt */
350 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
352 /* h_res = SAR a_h, cnt */
353 h_res = new_rd_ia32_l_SarDep(dbg, irg, block, a_h, cnt, l_res, l_mode);
355 resolve_call(call, l_res, h_res, irg, block);
360 upper = get_nodes_block(call);
362 /* l_res = SHRD a_h:a_l, cnt */
363 l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
365 /* h_res = SAR a_h, cnt */
366 h1 = new_rd_ia32_l_SarDep(dbg, irg, upper, a_h, cnt, l1, l_mode);
368 c_mode = get_irn_mode(cnt);
369 irn = new_r_Const_long(irg, upper, c_mode, 32);
370 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
371 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
372 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
373 cond = new_rd_Cond(dbg, irg, upper, irn);
375 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
376 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
378 /* the block for cnt >= 32 */
379 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
381 h2 = new_rd_Shrs(dbg, irg, n_block, a_h, new_r_Const_long(irg, block, c_mode, 31), l_mode);
382 in[1] = new_r_Jmp(irg, n_block);
384 set_irn_in(block, 2, in);
388 l_res = new_r_Phi(irg, block, 2, in, l_mode);
389 set_irn_link(block, l_res);
393 h_res = new_r_Phi(irg, block, 2, in, l_mode);
394 set_irn_link(l_res, h_res);
395 set_irn_link(h_res, NULL);
398 set_nodes_block(call, block);
399 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
400 set_nodes_block(irn, block);
402 resolve_call(call, l_res, h_res, irg, block);
407 * Map a Mul (a_l, a_h, b_l, b_h)
409 static int map_Mul(ir_node *call, void *ctx) {
410 ir_graph *irg = current_ir_graph;
411 dbg_info *dbg = get_irn_dbg_info(call);
412 ir_node *block = get_nodes_block(call);
413 ir_node **params = get_Call_param_arr(call);
414 ir_type *method = get_Call_type(call);
415 ir_node *a_l = params[BINOP_Left_Low];
416 ir_node *a_h = params[BINOP_Left_High];
417 ir_node *b_l = params[BINOP_Right_Low];
418 ir_node *b_h = params[BINOP_Right_High];
419 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
420 ir_node *l_res, *h_res, *mul, *pEDX, *add;
423 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
434 if (is_Shrs(a_h) && get_Shrs_left(a_h) == a_l &&
435 is_Shrs(b_h) && get_Shrs_left(b_h) == b_l) {
436 ir_node *c1 = get_Shrs_right(a_h);
438 if (c1 == get_Shrs_right(b_h) && is_Const(c1)) {
439 tarval *tv = get_Const_tarval(c1);
441 if (tarval_is_long(tv) && get_tarval_long(tv) == 31) {
442 /* it's a 32 * 32 = 64 signed multiplication */
444 mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
445 h_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
446 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
453 mul = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
454 pEDX = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
455 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
457 mul = new_rd_Mul(dbg, irg, block, a_h, b_l, l_mode);
458 add = new_rd_Add(dbg, irg, block, mul, pEDX, l_mode);
459 mul = new_rd_Mul(dbg, irg, block, a_l, b_h, l_mode);
460 h_res = new_rd_Add(dbg, irg, block, add, mul, l_mode);
463 resolve_call(call, l_res, h_res, irg, block);
469 * Map a Minus (a_l, a_h)
471 static int map_Minus(ir_node *call, void *ctx) {
472 ir_graph *irg = current_ir_graph;
473 dbg_info *dbg = get_irn_dbg_info(call);
474 ir_node *block = get_nodes_block(call);
475 ir_node **params = get_Call_param_arr(call);
476 ir_type *method = get_Call_type(call);
477 ir_node *a_l = params[BINOP_Left_Low];
478 ir_node *a_h = params[BINOP_Left_High];
479 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
480 ir_node *l_res, *h_res, *res;
483 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
485 res = new_rd_ia32_Minus64Bit(dbg, irg, block, a_l, a_h);
486 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
487 h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_high_res);
489 resolve_call(call, l_res, h_res, irg, block);
495 * Map a Abs (a_l, a_h)
497 static int map_Abs(ir_node *call, void *ctx) {
498 ir_graph *irg = current_ir_graph;
499 dbg_info *dbg = get_irn_dbg_info(call);
500 ir_node *block = get_nodes_block(call);
501 ir_node **params = get_Call_param_arr(call);
502 ir_type *method = get_Call_type(call);
503 ir_node *a_l = params[BINOP_Left_Low];
504 ir_node *a_h = params[BINOP_Left_High];
505 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
506 ir_node *l_res, *h_res, *sign, *sub_l, *sub_h, *res;
509 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
512 Code inspired by gcc output :) (although gcc doubles the
513 operation for t1 as t2 and uses t1 for operations with low part
514 and t2 for operations with high part which is actually unnecessary
515 because t1 and t2 represent the same value)
521 h_res = t3 - t1 - carry
525 sign = new_rd_ia32_l_Sar(dbg, irg, block, a_h, new_Const_long(l_mode, 31), l_mode);
526 sub_l = new_rd_ia32_l_Xor(dbg, irg, block, a_l, sign, l_mode);
527 sub_h = new_rd_ia32_l_Xor(dbg, irg, block, a_h, sign, l_mode);
528 res = new_rd_ia32_Sub64Bit(dbg, irg, block, sub_l, sub_h, sign, sign);
529 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
530 h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);
532 resolve_call(call, l_res, h_res, irg, block);
537 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
540 * Maps a Div. Change into a library call
542 static int map_Div(ir_node *call, void *ctx) {
543 ia32_intrinsic_env_t *env = ctx;
544 ir_type *method = get_Call_type(call);
545 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
550 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
552 if (mode_is_signed(l_mode)) {
553 /* 64bit signed Division */
556 /* create library entity */
557 ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
558 set_entity_visibility(ent, visibility_external_allocated);
559 set_entity_ld_ident(ent, ID("__divdi3"));
562 /* 64bit signed Division */
565 /* create library entity */
566 ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
567 set_entity_visibility(ent, visibility_external_allocated);
568 set_entity_ld_ident(ent, ID("__udivdi3"));
572 ptr = get_Call_ptr(call);
573 set_SymConst_symbol(ptr, sym);
578 * Maps a Mod. Change into a library call
580 static int map_Mod(ir_node *call, void *ctx) {
581 ia32_intrinsic_env_t *env = ctx;
582 ir_type *method = get_Call_type(call);
583 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
588 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
590 if (mode_is_signed(l_mode)) {
591 /* 64bit signed Modulo */
594 /* create library entity */
595 ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
596 set_entity_visibility(ent, visibility_external_allocated);
597 set_entity_ld_ident(ent, ID("__moddi3"));
600 /* 64bit signed Modulo */
603 /* create library entity */
604 ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
605 set_entity_visibility(ent, visibility_external_allocated);
606 set_entity_ld_ident(ent, ID("__umoddi3"));
610 ptr = get_Call_ptr(call);
611 set_SymConst_symbol(ptr, sym);
618 static int map_Conv(ir_node *call, void *ctx) {
619 ia32_intrinsic_env_t *env = ctx;
620 ir_graph *irg = current_ir_graph;
621 dbg_info *dbg = get_irn_dbg_info(call);
622 ir_node *block = get_nodes_block(call);
623 ir_node **params = get_Call_param_arr(call);
624 ir_type *method = get_Call_type(call);
625 int n = get_Call_n_params(call);
626 int gp_bytes = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
628 ir_node *l_res, *h_res, *frame, *fres;
629 ir_node *store_l, *store_h;
630 ir_node *op_mem[2], *mem;
633 /* We have a Conv float -> long long here */
634 ir_node *a_f = params[0];
635 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
636 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
638 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
640 /* allocate memory on frame to store args */
641 ent = env->irg == irg ? env->d_ll_conv : NULL;
643 ent = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
648 frame = get_irg_frame(irg);
651 Now we create a node to move the value from a XMM register into
652 x87 FPU because it is unknown here, which FPU is used.
653 This node is killed in transformation phase when not needed.
654 Otherwise it is split up into a movsd + fld
656 a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
657 set_ia32_frame_ent(a_f, ent);
658 set_ia32_use_frame(a_f);
659 set_ia32_ls_mode(a_f, mode_D);
661 /* store from FPU as Int */
662 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
663 set_ia32_frame_ent(a_f, ent);
664 set_ia32_use_frame(a_f);
665 set_ia32_ls_mode(a_f, mode_Ls);
668 /* load low part of the result */
669 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
670 set_ia32_frame_ent(l_res, ent);
671 set_ia32_use_frame(l_res);
672 set_ia32_ls_mode(l_res, l_res_mode);
673 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
675 /* load hight part of the result */
676 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
677 set_ia32_frame_ent(h_res, ent);
678 add_ia32_am_offs_int(h_res, gp_bytes);
679 set_ia32_use_frame(h_res);
680 set_ia32_ls_mode(h_res, h_res_mode);
681 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
684 resolve_call(call, l_res, h_res, irg, block);
687 /* We have a Conv long long -> float here */
688 ir_node *a_l = params[BINOP_Left_Low];
689 ir_node *a_h = params[BINOP_Left_High];
690 ir_mode *mode_a_l = get_irn_mode(a_l);
691 ir_mode *mode_a_h = get_irn_mode(a_h);
692 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
694 assert(! mode_is_float(mode_a_l) && ! mode_is_float(mode_a_h) && "unexpected Conv call");
696 /* allocate memory on frame to store args */
697 ent = env->irg == irg ? env->ll_d_conv : NULL;
699 ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
704 frame = get_irg_frame(irg);
706 /* store first arg (low part) */
707 store_l = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
708 set_ia32_frame_ent(store_l, ent);
709 set_ia32_use_frame(store_l);
710 set_ia32_ls_mode(store_l, get_irn_mode(a_l));
713 /* store second arg (high part) */
714 store_h = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
715 set_ia32_frame_ent(store_h, ent);
716 add_ia32_am_offs_int(store_h, gp_bytes);
717 set_ia32_use_frame(store_h);
718 set_ia32_ls_mode(store_h, get_irn_mode(a_h));
721 mem = new_r_Sync(irg, block, 2, op_mem);
723 /* Load arg into x87 FPU (implicit convert) */
724 fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
725 set_ia32_frame_ent(fres, ent);
726 set_ia32_use_frame(fres);
727 set_ia32_ls_mode(fres, mode_D);
728 mem = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
729 fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);
732 Now we create a node to move the loaded value into a XMM
733 register because it is unknown here, which FPU is used.
734 This node is killed in transformation phase when not needed.
735 Otherwise it is split up into a fst + movsd
737 fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
738 set_ia32_frame_ent(fres, ent);
739 set_ia32_use_frame(fres);
740 set_ia32_ls_mode(fres, fres_mode);
743 resolve_call(call, fres, NULL, irg, block);
746 assert(0 && "unexpected Conv call");
752 /* Ia32 implementation of intrinsic mapping. */
753 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
754 const ir_mode *imode, const ir_mode *omode,
758 ir_entity **ent = NULL;
759 i_mapper_func mapper;
762 intrinsics = NEW_ARR_F(i_record, 0);
764 switch (get_op_code(op)) {
766 ent = &i_ents[iro_Add];
770 ent = &i_ents[iro_Sub];
774 ent = &i_ents[iro_Shl];
778 ent = &i_ents[iro_Shr];
782 ent = &i_ents[iro_Shrs];
786 ent = &i_ents[iro_Mul];
790 ent = &i_ents[iro_Minus];
794 ent = &i_ents[iro_Abs];
798 ent = &i_ents[iro_Div];
802 ent = &i_ents[iro_Mod];
806 ent = &i_ents[iro_Conv];
810 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
811 return def_create_intrinsic_fkt(method, op, imode, omode, context);
815 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
817 ident *id = mangle(IDENT("L"), get_op_ident(op));
818 *ent = new_entity(get_glob_type(), id, method);
821 elt.i_call.kind = INTRINSIC_CALL;
822 elt.i_call.i_ent = *ent;
823 elt.i_call.i_mapper = mapper;
824 elt.i_call.ctx = context;
825 elt.i_call.link = NULL;
827 ARR_APP1(i_record, intrinsics, elt);