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_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
99 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
100 ir_node *add_low, *add_high, *flags;
101 ir_node *l_res, *h_res;
104 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
106 /* l_res = a_l + b_l */
107 /* h_res = a_h + b_h + carry */
109 add_low = new_rd_ia32_l_Add(dbg, irg, block, a_l, b_l, mode_T);
110 flags = new_r_Proj(irg, block, add_low, mode_flags, pn_ia32_flags);
111 add_high = new_rd_ia32_l_Adc(dbg, irg, block, a_h, b_h, flags, h_mode);
113 l_res = new_r_Proj(irg, block, add_low, l_mode, pn_ia32_res);
116 resolve_call(call, l_res, h_res, irg, block);
121 * Map a Sub (a_l, a_h, b_l, b_h)
123 static int map_Sub(ir_node *call, void *ctx) {
124 ir_graph *irg = current_ir_graph;
125 dbg_info *dbg = get_irn_dbg_info(call);
126 ir_node *block = get_nodes_block(call);
127 ir_node **params = get_Call_param_arr(call);
128 ir_type *method = get_Call_type(call);
129 ir_node *a_l = params[BINOP_Left_Low];
130 ir_node *a_h = params[BINOP_Left_High];
131 ir_node *b_l = params[BINOP_Right_Low];
132 ir_node *b_h = params[BINOP_Right_High];
133 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
134 ir_node *l_res, *h_res, *res;
137 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
139 /* l_res = a_l - b_l */
140 /* h_res = a_h - b_h - carry */
142 res = new_rd_ia32_Sub64Bit(dbg, irg, block, a_l, a_h, b_l, b_h);
143 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
144 h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);
146 resolve_call(call, l_res, h_res, irg, block);
151 * Map a Shl (a_l, a_h, count)
153 static int map_Shl(ir_node *call, void *ctx) {
154 ir_graph *irg = current_ir_graph;
155 dbg_info *dbg = get_irn_dbg_info(call);
156 ir_node *block = get_nodes_block(call);
157 ir_node **params = get_Call_param_arr(call);
158 ir_type *method = get_Call_type(call);
159 ir_node *a_l = params[BINOP_Left_Low];
160 ir_node *a_h = params[BINOP_Left_High];
161 ir_node *cnt = params[BINOP_Right_Low];
162 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
164 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
167 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
170 /* the shift count is a const, create better code */
171 tarval *tv = get_Const_tarval(cnt);
173 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
174 /* simplest case: shift only the lower bits. Note that there is no
175 need to reduce the constant here, this is done by the hardware. */
176 h_res = new_rd_Shl(dbg, irg, block, a_l, cnt, l_mode);
177 l_res = new_rd_Const(dbg, irg, block, l_mode, get_mode_null(l_mode));
180 /* h_res = SHLD a_h, a_l, cnt */
181 h_res = new_rd_ia32_l_ShlD(dbg, irg, block, a_h, a_l, cnt, l_mode);
183 /* l_res = SHL a_l, cnt */
184 l_res = new_rd_ia32_l_ShlDep(dbg, irg, block, a_l, cnt, h_res, l_mode);
187 resolve_call(call, l_res, h_res, irg, block);
192 upper = get_nodes_block(call);
194 /* h_res = SHLD a_h, a_l, cnt */
195 h1 = new_rd_ia32_l_ShlD(dbg, irg, upper, a_h, a_l, cnt, l_mode);
197 /* l_res = SHL a_l, cnt */
198 l1 = new_rd_ia32_l_ShlDep(dbg, irg, upper, a_l, cnt, h1, l_mode);
200 c_mode = get_irn_mode(cnt);
201 irn = new_r_Const_long(irg, upper, c_mode, 32);
202 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
203 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
204 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
205 cond = new_rd_Cond(dbg, irg, upper, irn);
207 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
208 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
210 /* the block for cnt >= 32 */
211 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
213 l2 = new_r_Const(irg, n_block, l_mode, get_mode_null(l_mode));
214 in[1] = new_r_Jmp(irg, n_block);
216 set_irn_in(block, 2, in);
220 l_res = new_r_Phi(irg, block, 2, in, l_mode);
221 set_irn_link(block, l_res);
225 h_res = new_r_Phi(irg, block, 2, in, l_mode);
226 set_irn_link(l_res, h_res);
227 set_irn_link(h_res, NULL);
230 set_nodes_block(call, block);
231 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
232 set_nodes_block(irn, block);
234 resolve_call(call, l_res, h_res, irg, block);
239 * Map a Shr (a_l, a_h, count)
241 static int map_Shr(ir_node *call, void *ctx) {
242 ir_graph *irg = current_ir_graph;
243 dbg_info *dbg = get_irn_dbg_info(call);
244 ir_node *block = get_nodes_block(call);
245 ir_node **params = get_Call_param_arr(call);
246 ir_type *method = get_Call_type(call);
247 ir_node *a_l = params[BINOP_Left_Low];
248 ir_node *a_h = params[BINOP_Left_High];
249 ir_node *cnt = params[BINOP_Right_Low];
250 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
252 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
255 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
258 /* the shift count is a const, create better code */
259 tarval *tv = get_Const_tarval(cnt);
261 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
262 /* simplest case: shift only the higher bits. Note that there is no
263 need to reduce the constant here, this is done by the hardware. */
264 h_res = new_rd_Const(dbg, irg, block, l_mode, get_mode_null(l_mode));
265 l_res = new_rd_Shr(dbg, irg, block, a_h, cnt, l_mode);
267 /* l_res = SHRD a_h:a_l, cnt */
268 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
270 /* h_res = SHR a_h, cnt */
271 h_res = new_rd_ia32_l_ShrDep(dbg, irg, block, a_h, cnt, l_res, l_mode);
273 resolve_call(call, l_res, h_res, irg, block);
278 upper = get_nodes_block(call);
280 /* l_res = SHRD a_h:a_l, cnt */
281 l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
283 /* h_res = SHR a_h, cnt */
284 h1 = new_rd_ia32_l_ShrDep(dbg, irg, upper, a_h, cnt, l1, l_mode);
286 c_mode = get_irn_mode(cnt);
287 irn = new_r_Const_long(irg, upper, c_mode, 32);
288 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
289 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
290 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
291 cond = new_rd_Cond(dbg, irg, upper, irn);
293 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
294 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
296 /* the block for cnt >= 32 */
297 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
299 h2 = new_r_Const(irg, n_block, l_mode, get_mode_null(l_mode));
300 in[1] = new_r_Jmp(irg, n_block);
302 set_irn_in(block, 2, in);
306 l_res = new_r_Phi(irg, block, 2, in, l_mode);
307 set_irn_link(block, l_res);
311 h_res = new_r_Phi(irg, block, 2, in, l_mode);
312 set_irn_link(l_res, h_res);
313 set_irn_link(h_res, NULL);
316 set_nodes_block(call, block);
317 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
318 set_nodes_block(irn, block);
320 resolve_call(call, l_res, h_res, irg, block);
325 * Map a Shrs (a_l, a_h, count)
327 static int map_Shrs(ir_node *call, void *ctx) {
328 ir_graph *irg = current_ir_graph;
329 dbg_info *dbg = get_irn_dbg_info(call);
330 ir_node *block = get_nodes_block(call);
331 ir_node **params = get_Call_param_arr(call);
332 ir_type *method = get_Call_type(call);
333 ir_node *a_l = params[BINOP_Left_Low];
334 ir_node *a_h = params[BINOP_Left_High];
335 ir_node *cnt = params[BINOP_Right_Low];
336 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
338 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
341 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
344 /* the shift count is a const, create better code */
345 tarval *tv = get_Const_tarval(cnt);
347 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
348 /* simplest case: shift only the higher bits. Note that there is no
349 need to reduce the constant here, this is done by the hardware. */
350 ir_mode *c_mode = get_irn_mode(cnt);
352 h_res = new_rd_Shrs(dbg, irg, block, a_h, new_r_Const_long(irg, block, c_mode, 31), l_mode);
353 l_res = new_rd_Shrs(dbg, irg, block, a_h, cnt, l_mode);
355 /* l_res = SHRD a_h:a_l, cnt */
356 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
358 /* h_res = SAR a_h, cnt */
359 h_res = new_rd_ia32_l_SarDep(dbg, irg, block, a_h, cnt, l_res, l_mode);
361 resolve_call(call, l_res, h_res, irg, block);
366 upper = get_nodes_block(call);
368 /* l_res = SHRD a_h:a_l, cnt */
369 l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
371 /* h_res = SAR a_h, cnt */
372 h1 = new_rd_ia32_l_SarDep(dbg, irg, upper, a_h, cnt, l1, l_mode);
374 c_mode = get_irn_mode(cnt);
375 irn = new_r_Const_long(irg, upper, c_mode, 32);
376 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
377 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
378 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
379 cond = new_rd_Cond(dbg, irg, upper, irn);
381 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
382 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
384 /* the block for cnt >= 32 */
385 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
387 h2 = new_rd_Shrs(dbg, irg, n_block, a_h, new_r_Const_long(irg, block, c_mode, 31), l_mode);
388 in[1] = new_r_Jmp(irg, n_block);
390 set_irn_in(block, 2, in);
394 l_res = new_r_Phi(irg, block, 2, in, l_mode);
395 set_irn_link(block, l_res);
399 h_res = new_r_Phi(irg, block, 2, in, l_mode);
400 set_irn_link(l_res, h_res);
401 set_irn_link(h_res, NULL);
404 set_nodes_block(call, block);
405 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
406 set_nodes_block(irn, block);
408 resolve_call(call, l_res, h_res, irg, block);
413 * Map a Mul (a_l, a_h, b_l, b_h)
415 static int map_Mul(ir_node *call, void *ctx) {
416 ir_graph *irg = current_ir_graph;
417 dbg_info *dbg = get_irn_dbg_info(call);
418 ir_node *block = get_nodes_block(call);
419 ir_node **params = get_Call_param_arr(call);
420 ir_type *method = get_Call_type(call);
421 ir_node *a_l = params[BINOP_Left_Low];
422 ir_node *a_h = params[BINOP_Left_High];
423 ir_node *b_l = params[BINOP_Right_Low];
424 ir_node *b_h = params[BINOP_Right_High];
425 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
426 ir_node *l_res, *h_res, *mul, *pEDX, *add;
429 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
440 if (is_Shrs(a_h) && get_Shrs_left(a_h) == a_l &&
441 is_Shrs(b_h) && get_Shrs_left(b_h) == b_l) {
442 ir_node *c1 = get_Shrs_right(a_h);
444 if (c1 == get_Shrs_right(b_h) && is_Const(c1)) {
445 tarval *tv = get_Const_tarval(c1);
447 if (tarval_is_long(tv) && get_tarval_long(tv) == 31) {
448 /* it's a 32 * 32 = 64 signed multiplication */
450 mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
451 h_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
452 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
459 mul = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
460 pEDX = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
461 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
463 mul = new_rd_Mul(dbg, irg, block, a_h, b_l, l_mode);
464 add = new_rd_Add(dbg, irg, block, mul, pEDX, l_mode);
465 mul = new_rd_Mul(dbg, irg, block, a_l, b_h, l_mode);
466 h_res = new_rd_Add(dbg, irg, block, add, mul, l_mode);
469 resolve_call(call, l_res, h_res, irg, block);
475 * Map a Minus (a_l, a_h)
477 static int map_Minus(ir_node *call, void *ctx) {
478 ir_graph *irg = current_ir_graph;
479 dbg_info *dbg = get_irn_dbg_info(call);
480 ir_node *block = get_nodes_block(call);
481 ir_node **params = get_Call_param_arr(call);
482 ir_type *method = get_Call_type(call);
483 ir_node *a_l = params[BINOP_Left_Low];
484 ir_node *a_h = params[BINOP_Left_High];
485 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
486 ir_node *l_res, *h_res, *res;
489 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
491 res = new_rd_ia32_Minus64Bit(dbg, irg, block, a_l, a_h);
492 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
493 h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_high_res);
495 resolve_call(call, l_res, h_res, irg, block);
501 * Map a Abs (a_l, a_h)
503 static int map_Abs(ir_node *call, void *ctx) {
504 ir_graph *irg = current_ir_graph;
505 dbg_info *dbg = get_irn_dbg_info(call);
506 ir_node *block = get_nodes_block(call);
507 ir_node **params = get_Call_param_arr(call);
508 ir_type *method = get_Call_type(call);
509 ir_node *a_l = params[BINOP_Left_Low];
510 ir_node *a_h = params[BINOP_Left_High];
511 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
512 ir_node *l_res, *h_res, *sign, *sub_l, *sub_h, *res;
515 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
518 Code inspired by gcc output :) (although gcc doubles the
519 operation for t1 as t2 and uses t1 for operations with low part
520 and t2 for operations with high part which is actually unnecessary
521 because t1 and t2 represent the same value)
527 h_res = t3 - t1 - carry
531 /* TODO: give a hint to the backend somehow to not create a cltd here... */
532 sign = new_rd_Shrs(dbg, irg, block, a_h, new_Const_long(l_mode, 31), l_mode);
533 sub_l = new_rd_Eor(dbg, irg, block, a_l, sign, l_mode);
534 sub_h = new_rd_Eor(dbg, irg, block, a_h, sign, l_mode);
535 res = new_rd_ia32_Sub64Bit(dbg, irg, block, sub_l, sub_h, sign, sign);
536 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
537 h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);
539 resolve_call(call, l_res, h_res, irg, block);
544 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
547 * Maps a Div. Change into a library call
549 static int map_Div(ir_node *call, void *ctx) {
550 ia32_intrinsic_env_t *env = ctx;
551 ir_type *method = get_Call_type(call);
552 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
557 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
559 if (mode_is_signed(l_mode)) {
560 /* 64bit signed Division */
563 /* create library entity */
564 ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
565 set_entity_visibility(ent, visibility_external_allocated);
566 set_entity_ld_ident(ent, ID("__divdi3"));
569 /* 64bit signed Division */
572 /* create library entity */
573 ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
574 set_entity_visibility(ent, visibility_external_allocated);
575 set_entity_ld_ident(ent, ID("__udivdi3"));
579 ptr = get_Call_ptr(call);
580 set_SymConst_symbol(ptr, sym);
585 * Maps a Mod. Change into a library call
587 static int map_Mod(ir_node *call, void *ctx) {
588 ia32_intrinsic_env_t *env = ctx;
589 ir_type *method = get_Call_type(call);
590 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
595 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
597 if (mode_is_signed(l_mode)) {
598 /* 64bit signed Modulo */
601 /* create library entity */
602 ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
603 set_entity_visibility(ent, visibility_external_allocated);
604 set_entity_ld_ident(ent, ID("__moddi3"));
607 /* 64bit signed Modulo */
610 /* create library entity */
611 ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
612 set_entity_visibility(ent, visibility_external_allocated);
613 set_entity_ld_ident(ent, ID("__umoddi3"));
617 ptr = get_Call_ptr(call);
618 set_SymConst_symbol(ptr, sym);
625 static int map_Conv(ir_node *call, void *ctx) {
626 ia32_intrinsic_env_t *env = ctx;
627 ir_graph *irg = current_ir_graph;
628 dbg_info *dbg = get_irn_dbg_info(call);
629 ir_node *block = get_nodes_block(call);
630 ir_node **params = get_Call_param_arr(call);
631 ir_type *method = get_Call_type(call);
632 int n = get_Call_n_params(call);
633 int gp_bytes = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
635 ir_node *l_res, *h_res, *frame, *fres;
636 ir_node *store_l, *store_h;
637 ir_node *op_mem[2], *mem;
640 /* We have a Conv float -> long long here */
641 ir_node *a_f = params[0];
642 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
643 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
645 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
647 /* allocate memory on frame to store args */
648 ent = env->irg == irg ? env->d_ll_conv : NULL;
650 ent = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
655 frame = get_irg_frame(irg);
658 Now we create a node to move the value from a XMM register into
659 x87 FPU because it is unknown here, which FPU is used.
660 This node is killed in transformation phase when not needed.
661 Otherwise it is split up into a movsd + fld
663 a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
664 set_ia32_frame_ent(a_f, ent);
665 set_ia32_use_frame(a_f);
666 set_ia32_ls_mode(a_f, mode_D);
668 /* store from FPU as Int */
669 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
670 set_ia32_frame_ent(a_f, ent);
671 set_ia32_use_frame(a_f);
672 set_ia32_ls_mode(a_f, mode_Ls);
675 /* load low part of the result */
676 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
677 set_ia32_frame_ent(l_res, ent);
678 set_ia32_use_frame(l_res);
679 set_ia32_ls_mode(l_res, l_res_mode);
680 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
682 /* load hight part of the result */
683 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
684 set_ia32_frame_ent(h_res, ent);
685 add_ia32_am_offs_int(h_res, gp_bytes);
686 set_ia32_use_frame(h_res);
687 set_ia32_ls_mode(h_res, h_res_mode);
688 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
691 resolve_call(call, l_res, h_res, irg, block);
694 /* We have a Conv long long -> float here */
695 ir_node *a_l = params[BINOP_Left_Low];
696 ir_node *a_h = params[BINOP_Left_High];
697 ir_mode *mode_a_l = get_irn_mode(a_l);
698 ir_mode *mode_a_h = get_irn_mode(a_h);
699 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
701 assert(! mode_is_float(mode_a_l) && ! mode_is_float(mode_a_h) && "unexpected Conv call");
703 /* allocate memory on frame to store args */
704 ent = env->irg == irg ? env->ll_d_conv : NULL;
706 ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
711 frame = get_irg_frame(irg);
713 /* store first arg (low part) */
714 store_l = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
715 set_ia32_frame_ent(store_l, ent);
716 set_ia32_use_frame(store_l);
717 set_ia32_ls_mode(store_l, get_irn_mode(a_l));
720 /* store second arg (high part) */
721 store_h = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
722 set_ia32_frame_ent(store_h, ent);
723 add_ia32_am_offs_int(store_h, gp_bytes);
724 set_ia32_use_frame(store_h);
725 set_ia32_ls_mode(store_h, get_irn_mode(a_h));
728 mem = new_r_Sync(irg, block, 2, op_mem);
730 /* Load arg into x87 FPU (implicit convert) */
731 fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
732 set_ia32_frame_ent(fres, ent);
733 set_ia32_use_frame(fres);
734 set_ia32_ls_mode(fres, mode_D);
735 mem = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
736 fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);
739 Now we create a node to move the loaded value into a XMM
740 register because it is unknown here, which FPU is used.
741 This node is killed in transformation phase when not needed.
742 Otherwise it is split up into a fst + movsd
744 fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
745 set_ia32_frame_ent(fres, ent);
746 set_ia32_use_frame(fres);
747 set_ia32_ls_mode(fres, fres_mode);
750 resolve_call(call, fres, NULL, irg, block);
753 assert(0 && "unexpected Conv call");
759 /* Ia32 implementation of intrinsic mapping. */
760 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
761 const ir_mode *imode, const ir_mode *omode,
765 ir_entity **ent = NULL;
766 i_mapper_func mapper;
769 intrinsics = NEW_ARR_F(i_record, 0);
771 switch (get_op_code(op)) {
773 ent = &i_ents[iro_Add];
777 ent = &i_ents[iro_Sub];
781 ent = &i_ents[iro_Shl];
785 ent = &i_ents[iro_Shr];
789 ent = &i_ents[iro_Shrs];
793 ent = &i_ents[iro_Mul];
797 ent = &i_ents[iro_Minus];
801 ent = &i_ents[iro_Abs];
805 ent = &i_ents[iro_Div];
809 ent = &i_ents[iro_Mod];
813 ent = &i_ents[iro_Conv];
817 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
818 return def_create_intrinsic_fkt(method, op, imode, omode, context);
822 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
824 ident *id = mangle(IDENT("L"), get_op_ident(op));
825 *ent = new_entity(get_glob_type(), id, method);
828 elt.i_call.kind = INTRINSIC_CALL;
829 elt.i_call.i_ent = *ent;
830 elt.i_call.i_mapper = mapper;
831 elt.i_call.ctx = context;
832 elt.i_call.link = NULL;
834 ARR_APP1(i_record, intrinsics, elt);