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 /* handle the often used case of 32x32=64 mul */
441 if (is_Shrs(a_h) && get_Shrs_left(a_h) == a_l) {
442 ir_node *c1 = get_Shrs_right(a_h);
445 tarval *tv = get_Const_tarval(c1);
447 if (tarval_is_long(tv) && get_tarval_long(tv) == 31) {
448 /* a is a sign extend */
450 if (is_Shrs(b_h) && get_Shrs_left(b_h) == b_l && c1 == get_Shrs_right(b_h)) {
451 /* b is a sign extend: it's a 32 * 32 = 64 signed multiplication */
452 mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
453 h_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
454 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
458 /* we rely here on Consts being on the right site */
459 if (is_Const(b_h) && is_Const(b_l)) {
460 tarval *th = get_Const_tarval(b_h);
461 tarval *tl = get_Const_tarval(b_l);
463 if (tarval_is_long(th) && tarval_is_long(tl)) {
464 long h = get_tarval_long(th);
465 long l = get_tarval_long(tl);
467 if ((h == 0 && l >= 0) || (h == -1 && l < 0)) {
468 /* b is a sign extended const */
469 mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
470 h_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
471 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
482 mul = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
483 pEDX = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EDX);
484 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
486 mul = new_rd_Mul(dbg, irg, block, a_h, b_l, l_mode);
487 add = new_rd_Add(dbg, irg, block, mul, pEDX, l_mode);
488 mul = new_rd_Mul(dbg, irg, block, a_l, b_h, l_mode);
489 h_res = new_rd_Add(dbg, irg, block, add, mul, l_mode);
492 resolve_call(call, l_res, h_res, irg, block);
498 * Map a Minus (a_l, a_h)
500 static int map_Minus(ir_node *call, void *ctx) {
501 ir_graph *irg = current_ir_graph;
502 dbg_info *dbg = get_irn_dbg_info(call);
503 ir_node *block = get_nodes_block(call);
504 ir_node **params = get_Call_param_arr(call);
505 ir_type *method = get_Call_type(call);
506 ir_node *a_l = params[BINOP_Left_Low];
507 ir_node *a_h = params[BINOP_Left_High];
508 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
509 ir_node *l_res, *h_res, *res;
512 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
514 res = new_rd_ia32_Minus64Bit(dbg, irg, block, a_l, a_h);
515 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
516 h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_high_res);
518 resolve_call(call, l_res, h_res, irg, block);
524 * Map a Abs (a_l, a_h)
526 static int map_Abs(ir_node *call, void *ctx) {
527 ir_graph *irg = current_ir_graph;
528 dbg_info *dbg = get_irn_dbg_info(call);
529 ir_node *block = get_nodes_block(call);
530 ir_node **params = get_Call_param_arr(call);
531 ir_type *method = get_Call_type(call);
532 ir_node *a_l = params[BINOP_Left_Low];
533 ir_node *a_h = params[BINOP_Left_High];
534 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
535 ir_node *l_res, *h_res, *sign, *sub_l, *sub_h, *res;
538 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
541 Code inspired by gcc output :) (although gcc doubles the
542 operation for t1 as t2 and uses t1 for operations with low part
543 and t2 for operations with high part which is actually unnecessary
544 because t1 and t2 represent the same value)
550 h_res = t3 - t1 - carry
554 /* TODO: give a hint to the backend somehow to not create a cltd here... */
555 sign = new_rd_Shrs(dbg, irg, block, a_h, new_Const_long(l_mode, 31), l_mode);
556 sub_l = new_rd_Eor(dbg, irg, block, a_l, sign, l_mode);
557 sub_h = new_rd_Eor(dbg, irg, block, a_h, sign, l_mode);
558 res = new_rd_ia32_Sub64Bit(dbg, irg, block, sub_l, sub_h, sign, sign);
559 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
560 h_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_high_res);
562 resolve_call(call, l_res, h_res, irg, block);
567 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
570 * Maps a Div. Change into a library call
572 static int map_Div(ir_node *call, void *ctx) {
573 ia32_intrinsic_env_t *env = ctx;
574 ir_type *method = get_Call_type(call);
575 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
580 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
582 if (mode_is_signed(l_mode)) {
583 /* 64bit signed Division */
586 /* create library entity */
587 ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
588 set_entity_visibility(ent, visibility_external_allocated);
589 set_entity_ld_ident(ent, ID("__divdi3"));
592 /* 64bit signed Division */
595 /* create library entity */
596 ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
597 set_entity_visibility(ent, visibility_external_allocated);
598 set_entity_ld_ident(ent, ID("__udivdi3"));
602 ptr = get_Call_ptr(call);
603 set_SymConst_symbol(ptr, sym);
608 * Maps a Mod. Change into a library call
610 static int map_Mod(ir_node *call, void *ctx) {
611 ia32_intrinsic_env_t *env = ctx;
612 ir_type *method = get_Call_type(call);
613 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
618 assert(l_mode == get_type_mode(get_method_res_type(method, 1)) && "64bit lowered into different modes");
620 if (mode_is_signed(l_mode)) {
621 /* 64bit signed Modulo */
624 /* create library entity */
625 ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
626 set_entity_visibility(ent, visibility_external_allocated);
627 set_entity_ld_ident(ent, ID("__moddi3"));
630 /* 64bit signed Modulo */
633 /* create library entity */
634 ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
635 set_entity_visibility(ent, visibility_external_allocated);
636 set_entity_ld_ident(ent, ID("__umoddi3"));
640 ptr = get_Call_ptr(call);
641 set_SymConst_symbol(ptr, sym);
648 static int map_Conv(ir_node *call, void *ctx) {
649 ia32_intrinsic_env_t *env = ctx;
650 ir_graph *irg = current_ir_graph;
651 dbg_info *dbg = get_irn_dbg_info(call);
652 ir_node *block = get_nodes_block(call);
653 ir_node **params = get_Call_param_arr(call);
654 ir_type *method = get_Call_type(call);
655 int n = get_Call_n_params(call);
656 int gp_bytes = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
658 ir_node *l_res, *h_res, *frame, *fres;
659 ir_node *store_l, *store_h;
660 ir_node *op_mem[2], *mem;
663 /* We have a Conv float -> long long here */
664 ir_node *a_f = params[0];
665 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
666 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
668 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
670 /* allocate memory on frame to store args */
671 ent = env->irg == irg ? env->d_ll_conv : NULL;
673 ent = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
678 frame = get_irg_frame(irg);
681 Now we create a node to move the value from a XMM register into
682 x87 FPU because it is unknown here, which FPU is used.
683 This node is killed in transformation phase when not needed.
684 Otherwise it is split up into a movsd + fld
686 a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
687 set_ia32_frame_ent(a_f, ent);
688 set_ia32_use_frame(a_f);
689 set_ia32_ls_mode(a_f, mode_D);
691 /* store from FPU as Int */
692 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
693 set_ia32_frame_ent(a_f, ent);
694 set_ia32_use_frame(a_f);
695 set_ia32_ls_mode(a_f, mode_Ls);
698 /* load low part of the result */
699 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
700 set_ia32_frame_ent(l_res, ent);
701 set_ia32_use_frame(l_res);
702 set_ia32_ls_mode(l_res, l_res_mode);
703 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
705 /* load hight part of the result */
706 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
707 set_ia32_frame_ent(h_res, ent);
708 add_ia32_am_offs_int(h_res, gp_bytes);
709 set_ia32_use_frame(h_res);
710 set_ia32_ls_mode(h_res, h_res_mode);
711 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
714 resolve_call(call, l_res, h_res, irg, block);
717 /* We have a Conv long long -> float here */
718 ir_node *a_l = params[BINOP_Left_Low];
719 ir_node *a_h = params[BINOP_Left_High];
720 ir_mode *mode_a_l = get_irn_mode(a_l);
721 ir_mode *mode_a_h = get_irn_mode(a_h);
722 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
724 assert(! mode_is_float(mode_a_l) && ! mode_is_float(mode_a_h) && "unexpected Conv call");
726 /* allocate memory on frame to store args */
727 ent = env->irg == irg ? env->ll_d_conv : NULL;
729 ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
734 frame = get_irg_frame(irg);
736 /* store first arg (low part) */
737 store_l = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
738 set_ia32_frame_ent(store_l, ent);
739 set_ia32_use_frame(store_l);
740 set_ia32_ls_mode(store_l, get_irn_mode(a_l));
743 /* store second arg (high part) */
744 store_h = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
745 set_ia32_frame_ent(store_h, ent);
746 add_ia32_am_offs_int(store_h, gp_bytes);
747 set_ia32_use_frame(store_h);
748 set_ia32_ls_mode(store_h, get_irn_mode(a_h));
751 mem = new_r_Sync(irg, block, 2, op_mem);
753 /* Load arg into x87 FPU (implicit convert) */
754 fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
755 set_ia32_frame_ent(fres, ent);
756 set_ia32_use_frame(fres);
757 set_ia32_ls_mode(fres, mode_D);
758 mem = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
759 fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);
762 Now we create a node to move the loaded value into a XMM
763 register because it is unknown here, which FPU is used.
764 This node is killed in transformation phase when not needed.
765 Otherwise it is split up into a fst + movsd
767 fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
768 set_ia32_frame_ent(fres, ent);
769 set_ia32_use_frame(fres);
770 set_ia32_ls_mode(fres, fres_mode);
773 resolve_call(call, fres, NULL, irg, block);
776 assert(0 && "unexpected Conv call");
782 /* Ia32 implementation of intrinsic mapping. */
783 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
784 const ir_mode *imode, const ir_mode *omode,
788 ir_entity **ent = NULL;
789 i_mapper_func mapper;
792 intrinsics = NEW_ARR_F(i_record, 0);
794 switch (get_op_code(op)) {
796 ent = &i_ents[iro_Add];
800 ent = &i_ents[iro_Sub];
804 ent = &i_ents[iro_Shl];
808 ent = &i_ents[iro_Shr];
812 ent = &i_ents[iro_Shrs];
816 ent = &i_ents[iro_Mul];
820 ent = &i_ents[iro_Minus];
824 ent = &i_ents[iro_Abs];
828 ent = &i_ents[iro_Div];
832 ent = &i_ents[iro_Mod];
836 ent = &i_ents[iro_Conv];
840 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
841 return def_create_intrinsic_fkt(method, op, imode, omode, context);
845 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
847 ident *id = mangle(IDENT("L"), get_op_ident(op));
848 *ent = new_entity(get_glob_type(), id, method);
851 elt.i_call.kind = INTRINSIC_CALL;
852 elt.i_call.i_ent = *ent;
853 elt.i_call.i_mapper = mapper;
854 elt.i_call.ctx = context;
855 elt.i_call.link = NULL;
857 ARR_APP1(i_record, intrinsics, elt);