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 /* l_res = a_l + b_l */
105 /* h_res = a_h + b_h + carry */
107 add_low = new_rd_ia32_l_Add(dbg, irg, block, a_l, b_l, mode_T);
108 flags = new_r_Proj(irg, block, add_low, mode_flags, pn_ia32_flags);
109 add_high = new_rd_ia32_l_Adc(dbg, irg, block, a_h, b_h, flags, h_mode);
111 l_res = new_r_Proj(irg, block, add_low, l_mode, pn_ia32_res);
114 resolve_call(call, l_res, h_res, irg, block);
119 * Map a Sub (a_l, a_h, b_l, b_h)
121 static int map_Sub(ir_node *call, void *ctx) {
122 ir_graph *irg = current_ir_graph;
123 dbg_info *dbg = get_irn_dbg_info(call);
124 ir_node *block = get_nodes_block(call);
125 ir_node **params = get_Call_param_arr(call);
126 ir_type *method = get_Call_type(call);
127 ir_node *a_l = params[BINOP_Left_Low];
128 ir_node *a_h = params[BINOP_Left_High];
129 ir_node *b_l = params[BINOP_Right_Low];
130 ir_node *b_h = params[BINOP_Right_High];
131 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
132 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
133 ir_node *l_res, *h_res, *res;
136 /* l_res = a_l - b_l */
137 /* h_res = a_h - b_h - carry */
139 res = new_rd_ia32_Sub64Bit(dbg, irg, block, a_l, a_h, b_l, b_h);
140 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
141 h_res = new_r_Proj(irg, block, res, h_mode, pn_ia32_Sub64Bit_high_res);
143 resolve_call(call, l_res, h_res, irg, block);
148 * Map a Shl (a_l, a_h, count)
150 static int map_Shl(ir_node *call, void *ctx) {
151 ir_graph *irg = current_ir_graph;
152 dbg_info *dbg = get_irn_dbg_info(call);
153 ir_node *block = get_nodes_block(call);
154 ir_node **params = get_Call_param_arr(call);
155 ir_type *method = get_Call_type(call);
156 ir_node *a_l = params[BINOP_Left_Low];
157 ir_node *a_h = params[BINOP_Left_High];
158 ir_node *cnt = params[BINOP_Right_Low];
159 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
160 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
162 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
166 /* the shift count is a const, create better code */
167 tarval *tv = get_Const_tarval(cnt);
169 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
170 /* simplest case: shift only the lower bits. Note that there is no
171 need to reduce the constant here, this is done by the hardware. */
172 ir_node *conv = new_rd_Conv(dbg, irg, block, a_l, h_mode);
173 h_res = new_rd_Shl(dbg, irg, block, conv, cnt, h_mode);
174 l_res = new_rd_Const(dbg, irg, block, l_mode, get_mode_null(l_mode));
177 /* h_res = SHLD a_h, a_l, cnt */
178 h_res = new_rd_ia32_l_ShlD(dbg, irg, block, a_h, a_l, cnt, h_mode);
180 /* l_res = SHL a_l, cnt */
181 l_res = new_rd_ia32_l_ShlDep(dbg, irg, block, a_l, cnt, h_res, l_mode);
184 resolve_call(call, l_res, h_res, irg, block);
189 upper = get_nodes_block(call);
191 /* h_res = SHLD a_h, a_l, cnt */
192 h1 = new_rd_ia32_l_ShlD(dbg, irg, upper, a_h, a_l, cnt, h_mode);
194 /* l_res = SHL a_l, cnt */
195 l1 = new_rd_ia32_l_ShlDep(dbg, irg, upper, a_l, cnt, h1, l_mode);
197 c_mode = get_irn_mode(cnt);
198 irn = new_r_Const_long(irg, upper, c_mode, 32);
199 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
200 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
201 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
202 cond = new_rd_Cond(dbg, irg, upper, irn);
204 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
205 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
207 /* the block for cnt >= 32 */
208 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
209 h2 = new_rd_Conv(dbg, irg, n_block, l1, h_mode);
210 l2 = new_r_Const(irg, n_block, l_mode, get_mode_null(l_mode));
211 in[1] = new_r_Jmp(irg, n_block);
213 set_irn_in(block, 2, in);
217 l_res = new_r_Phi(irg, block, 2, in, l_mode);
218 set_irn_link(block, l_res);
222 h_res = new_r_Phi(irg, block, 2, in, h_mode);
223 set_irn_link(l_res, h_res);
224 set_irn_link(h_res, NULL);
227 set_nodes_block(call, block);
228 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
229 set_nodes_block(irn, block);
231 resolve_call(call, l_res, h_res, irg, block);
236 * Map a Shr (a_l, a_h, count)
238 static int map_Shr(ir_node *call, void *ctx) {
239 ir_graph *irg = current_ir_graph;
240 dbg_info *dbg = get_irn_dbg_info(call);
241 ir_node *block = get_nodes_block(call);
242 ir_node **params = get_Call_param_arr(call);
243 ir_type *method = get_Call_type(call);
244 ir_node *a_l = params[BINOP_Left_Low];
245 ir_node *a_h = params[BINOP_Left_High];
246 ir_node *cnt = params[BINOP_Right_Low];
247 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
248 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
250 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
254 /* the shift count is a const, create better code */
255 tarval *tv = get_Const_tarval(cnt);
257 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
258 /* simplest case: shift only the higher bits. Note that there is no
259 need to reduce the constant here, this is done by the hardware. */
260 ir_node *conv = new_rd_Conv(dbg, irg, block, a_h, l_mode);
261 h_res = new_rd_Const(dbg, irg, block, h_mode, get_mode_null(h_mode));
262 l_res = new_rd_Shr(dbg, irg, block, conv, cnt, l_mode);
264 /* l_res = SHRD a_h:a_l, cnt */
265 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
267 /* h_res = SHR a_h, cnt */
268 h_res = new_rd_ia32_l_ShrDep(dbg, irg, block, a_h, cnt, l_res, h_mode);
270 resolve_call(call, l_res, h_res, irg, block);
275 upper = get_nodes_block(call);
277 /* l_res = SHRD a_h:a_l, cnt */
278 l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
280 /* h_res = SHR a_h, cnt */
281 h1 = new_rd_ia32_l_ShrDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
283 c_mode = get_irn_mode(cnt);
284 irn = new_r_Const_long(irg, upper, c_mode, 32);
285 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
286 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
287 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
288 cond = new_rd_Cond(dbg, irg, upper, irn);
290 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
291 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
293 /* the block for cnt >= 32 */
294 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
295 l2 = new_rd_Conv(dbg, irg, n_block, h1, l_mode);
296 h2 = new_r_Const(irg, n_block, l_mode, get_mode_null(h_mode));
297 in[1] = new_r_Jmp(irg, n_block);
299 set_irn_in(block, 2, in);
303 l_res = new_r_Phi(irg, block, 2, in, l_mode);
304 set_irn_link(block, l_res);
308 h_res = new_r_Phi(irg, block, 2, in, h_mode);
309 set_irn_link(l_res, h_res);
310 set_irn_link(h_res, NULL);
313 set_nodes_block(call, block);
314 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
315 set_nodes_block(irn, block);
317 resolve_call(call, l_res, h_res, irg, block);
322 * Map a Shrs (a_l, a_h, count)
324 static int map_Shrs(ir_node *call, void *ctx) {
325 ir_graph *irg = current_ir_graph;
326 dbg_info *dbg = get_irn_dbg_info(call);
327 ir_node *block = get_nodes_block(call);
328 ir_node **params = get_Call_param_arr(call);
329 ir_type *method = get_Call_type(call);
330 ir_node *a_l = params[BINOP_Left_Low];
331 ir_node *a_h = params[BINOP_Left_High];
332 ir_node *cnt = params[BINOP_Right_Low];
333 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
334 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
336 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
340 /* the shift count is a const, create better code */
341 tarval *tv = get_Const_tarval(cnt);
343 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
344 /* simplest case: shift only the higher bits. Note that there is no
345 need to reduce the constant here, this is done by the hardware. */
346 ir_node *conv = new_rd_Conv(dbg, irg, block, a_h, l_mode);
347 ir_mode *c_mode = get_irn_mode(cnt);
349 h_res = new_rd_Shrs(dbg, irg, block, a_h, new_r_Const_long(irg, block, c_mode, 31), h_mode);
350 l_res = new_rd_Shrs(dbg, irg, block, conv, cnt, l_mode);
352 /* l_res = SHRD a_h:a_l, cnt */
353 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
355 /* h_res = SAR a_h, cnt */
356 h_res = new_rd_ia32_l_SarDep(dbg, irg, block, a_h, cnt, l_res, h_mode);
358 resolve_call(call, l_res, h_res, irg, block);
363 upper = get_nodes_block(call);
365 /* l_res = SHRD a_h:a_l, cnt */
366 l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
368 /* h_res = SAR a_h, cnt */
369 h1 = new_rd_ia32_l_SarDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
371 c_mode = get_irn_mode(cnt);
372 irn = new_r_Const_long(irg, upper, c_mode, 32);
373 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
374 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
375 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
376 cond = new_rd_Cond(dbg, irg, upper, irn);
378 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
379 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
381 /* the block for cnt >= 32 */
382 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
383 l2 = new_rd_Conv(dbg, irg, n_block, h1, l_mode);
384 h2 = new_rd_Shrs(dbg, irg, n_block, a_h, new_r_Const_long(irg, block, c_mode, 31), h_mode);
385 in[1] = new_r_Jmp(irg, n_block);
387 set_irn_in(block, 2, in);
391 l_res = new_r_Phi(irg, block, 2, in, l_mode);
392 set_irn_link(block, l_res);
396 h_res = new_r_Phi(irg, block, 2, in, h_mode);
397 set_irn_link(l_res, h_res);
398 set_irn_link(h_res, NULL);
401 set_nodes_block(call, block);
402 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
403 set_nodes_block(irn, block);
405 resolve_call(call, l_res, h_res, irg, block);
410 * Map a Mul (a_l, a_h, b_l, b_h)
412 static int map_Mul(ir_node *call, void *ctx) {
413 ir_graph *irg = current_ir_graph;
414 dbg_info *dbg = get_irn_dbg_info(call);
415 ir_node *block = get_nodes_block(call);
416 ir_node **params = get_Call_param_arr(call);
417 ir_type *method = get_Call_type(call);
418 ir_node *a_l = params[BINOP_Left_Low];
419 ir_node *a_h = params[BINOP_Left_High];
420 ir_node *b_l = params[BINOP_Right_Low];
421 ir_node *b_h = params[BINOP_Right_High];
422 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
423 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
424 ir_node *l_res, *h_res, *mul, *pEDX, *add;
437 /* handle the often used case of 32x32=64 mul */
438 if (is_Shrs(a_h) && get_Shrs_left(a_h) == a_l) {
439 ir_node *c1 = get_Shrs_right(a_h);
442 tarval *tv = get_Const_tarval(c1);
444 if (tarval_is_long(tv) && get_tarval_long(tv) == 31) {
445 /* a is a sign extend */
447 if (is_Shrs(b_h) && get_Shrs_left(b_h) == b_l && c1 == get_Shrs_right(b_h)) {
448 /* b is a sign extend: it's a 32 * 32 = 64 signed multiplication */
449 mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
450 h_res = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
451 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
455 /* we rely here on Consts being on the right side */
456 if (is_Const(b_h) && is_Const(b_l)) {
457 tarval *th = get_Const_tarval(b_h);
458 tarval *tl = get_Const_tarval(b_l);
460 if (tarval_is_long(th) && tarval_is_long(tl)) {
461 long h = get_tarval_long(th);
462 long l = get_tarval_long(tl);
464 if ((h == 0 && l >= 0) || (h == -1 && l < 0)) {
465 /* b is a sign extended const */
466 mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
467 h_res = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
468 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
478 mul = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
479 pEDX = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
480 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
482 b_l = new_rd_Conv(dbg, irg, block, b_l, h_mode);
483 mul = new_rd_Mul( dbg, irg, block, a_h, b_l, h_mode);
484 add = new_rd_Add( dbg, irg, block, mul, pEDX, h_mode);
485 a_l = new_rd_Conv(dbg, irg, block, a_l, h_mode);
486 mul = new_rd_Mul( dbg, irg, block, a_l, b_h, h_mode);
487 h_res = new_rd_Add( dbg, irg, block, add, mul, h_mode);
490 resolve_call(call, l_res, h_res, irg, block);
496 * Map a Minus (a_l, a_h)
498 static int map_Minus(ir_node *call, void *ctx) {
499 ir_graph *irg = current_ir_graph;
500 dbg_info *dbg = get_irn_dbg_info(call);
501 ir_node *block = get_nodes_block(call);
502 ir_node **params = get_Call_param_arr(call);
503 ir_type *method = get_Call_type(call);
504 ir_node *a_l = params[BINOP_Left_Low];
505 ir_node *a_h = params[BINOP_Left_High];
506 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
507 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
508 ir_node *l_res, *h_res, *res;
511 res = new_rd_ia32_Minus64Bit(dbg, irg, block, a_l, a_h);
512 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
513 h_res = new_r_Proj(irg, block, res, h_mode, pn_ia32_Minus64Bit_high_res);
515 resolve_call(call, l_res, h_res, irg, block);
521 * Map a Abs (a_l, a_h)
523 static int map_Abs(ir_node *call, void *ctx) {
524 ir_graph *irg = current_ir_graph;
525 dbg_info *dbg = get_irn_dbg_info(call);
526 ir_node *block = get_nodes_block(call);
527 ir_node **params = get_Call_param_arr(call);
528 ir_type *method = get_Call_type(call);
529 ir_node *a_l = params[BINOP_Left_Low];
530 ir_node *a_h = params[BINOP_Left_High];
531 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
532 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
533 ir_node *l_res, *h_res, *sign, *sub_l, *sub_h, *res;
538 Code inspired by gcc output :) (although gcc doubles the
539 operation for t1 as t2 and uses t1 for operations with low part
540 and t2 for operations with high part which is actually unnecessary
541 because t1 and t2 represent the same value)
547 h_res = t3 - t1 - carry
551 /* TODO: give a hint to the backend somehow to not create a cltd here... */
552 sign = new_rd_Shrs(dbg, irg, block, a_h, new_Const_long(l_mode, 31), h_mode);
553 sign_l = new_rd_Conv(dbg, irg, block, sign, l_mode);
554 sub_l = new_rd_Eor(dbg, irg, block, a_l, sign_l, l_mode);
555 sub_h = new_rd_Eor(dbg, irg, block, a_h, sign, h_mode);
556 res = new_rd_ia32_Sub64Bit(dbg, irg, block, sub_l, sub_h, sign, sign);
557 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Sub64Bit_low_res);
558 h_res = new_r_Proj(irg, block, res, h_mode, pn_ia32_Sub64Bit_high_res);
560 resolve_call(call, l_res, h_res, irg, block);
565 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
568 * Maps a Div. Change into a library call
570 static int map_Div(ir_node *call, void *ctx) {
571 ia32_intrinsic_env_t *env = ctx;
572 ir_type *method = get_Call_type(call);
573 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
578 if (mode_is_signed(h_mode)) {
579 /* 64bit signed Division */
582 /* create library entity */
583 ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
584 set_entity_visibility(ent, visibility_external_allocated);
585 set_entity_ld_ident(ent, ID("__divdi3"));
588 /* 64bit unsigned Division */
591 /* create library entity */
592 ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
593 set_entity_visibility(ent, visibility_external_allocated);
594 set_entity_ld_ident(ent, ID("__udivdi3"));
598 ptr = get_Call_ptr(call);
599 set_SymConst_symbol(ptr, sym);
604 * Maps a Mod. Change into a library call
606 static int map_Mod(ir_node *call, void *ctx) {
607 ia32_intrinsic_env_t *env = ctx;
608 ir_type *method = get_Call_type(call);
609 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 0));
614 if (mode_is_signed(h_mode)) {
615 /* 64bit signed Modulo */
618 /* create library entity */
619 ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
620 set_entity_visibility(ent, visibility_external_allocated);
621 set_entity_ld_ident(ent, ID("__moddi3"));
624 /* 64bit signed Modulo */
627 /* create library entity */
628 ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
629 set_entity_visibility(ent, visibility_external_allocated);
630 set_entity_ld_ident(ent, ID("__umoddi3"));
634 ptr = get_Call_ptr(call);
635 set_SymConst_symbol(ptr, sym);
642 static int map_Conv(ir_node *call, void *ctx) {
643 ia32_intrinsic_env_t *env = ctx;
644 ir_graph *irg = current_ir_graph;
645 dbg_info *dbg = get_irn_dbg_info(call);
646 ir_node *block = get_nodes_block(call);
647 ir_node **params = get_Call_param_arr(call);
648 ir_type *method = get_Call_type(call);
649 int n = get_Call_n_params(call);
650 int gp_bytes = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
652 ir_node *l_res, *h_res, *frame, *fres;
653 ir_node *store_l, *store_h;
654 ir_node *op_mem[2], *mem;
657 /* We have a Conv float -> long long here */
658 ir_node *a_f = params[0];
659 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
660 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
662 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
664 /* allocate memory on frame to store args */
665 ent = env->irg == irg ? env->d_ll_conv : NULL;
667 ent = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
672 frame = get_irg_frame(irg);
675 Now we create a node to move the value from a XMM register into
676 x87 FPU because it is unknown here, which FPU is used.
677 This node is killed in transformation phase when not needed.
678 Otherwise it is split up into a movsd + fld
680 a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
681 set_ia32_frame_ent(a_f, ent);
682 set_ia32_use_frame(a_f);
683 set_ia32_ls_mode(a_f, mode_D);
685 /* store from FPU as Int */
686 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
687 set_ia32_frame_ent(a_f, ent);
688 set_ia32_use_frame(a_f);
689 set_ia32_ls_mode(a_f, mode_Ls);
692 /* load low part of the result */
693 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
694 set_ia32_frame_ent(l_res, ent);
695 set_ia32_use_frame(l_res);
696 set_ia32_ls_mode(l_res, l_res_mode);
697 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
699 /* load hight part of the result */
700 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
701 set_ia32_frame_ent(h_res, ent);
702 add_ia32_am_offs_int(h_res, gp_bytes);
703 set_ia32_use_frame(h_res);
704 set_ia32_ls_mode(h_res, h_res_mode);
705 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
708 resolve_call(call, l_res, h_res, irg, block);
711 /* We have a Conv long long -> float here */
712 ir_node *a_l = params[BINOP_Left_Low];
713 ir_node *a_h = params[BINOP_Left_High];
714 ir_mode *mode_a_l = get_irn_mode(a_l);
715 ir_mode *mode_a_h = get_irn_mode(a_h);
716 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
718 assert(! mode_is_float(mode_a_l) && ! mode_is_float(mode_a_h) && "unexpected Conv call");
720 /* allocate memory on frame to store args */
721 ent = env->irg == irg ? env->ll_d_conv : NULL;
723 ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
728 frame = get_irg_frame(irg);
730 /* store first arg (low part) */
731 store_l = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
732 set_ia32_frame_ent(store_l, ent);
733 set_ia32_use_frame(store_l);
734 set_ia32_ls_mode(store_l, get_irn_mode(a_l));
737 /* store second arg (high part) */
738 store_h = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
739 set_ia32_frame_ent(store_h, ent);
740 add_ia32_am_offs_int(store_h, gp_bytes);
741 set_ia32_use_frame(store_h);
742 set_ia32_ls_mode(store_h, get_irn_mode(a_h));
745 mem = new_r_Sync(irg, block, 2, op_mem);
747 /* Load arg into x87 FPU (implicit convert) */
748 fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
749 set_ia32_frame_ent(fres, ent);
750 set_ia32_use_frame(fres);
751 set_ia32_ls_mode(fres, mode_D);
752 mem = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
753 fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);
756 Now we create a node to move the loaded value into a XMM
757 register because it is unknown here, which FPU is used.
758 This node is killed in transformation phase when not needed.
759 Otherwise it is split up into a fst + movsd
761 fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
762 set_ia32_frame_ent(fres, ent);
763 set_ia32_use_frame(fres);
764 set_ia32_ls_mode(fres, fres_mode);
767 resolve_call(call, fres, NULL, irg, block);
770 assert(0 && "unexpected Conv call");
776 /* Ia32 implementation of intrinsic mapping. */
777 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
778 const ir_mode *imode, const ir_mode *omode,
782 ir_entity **ent = NULL;
783 i_mapper_func mapper;
786 intrinsics = NEW_ARR_F(i_record, 0);
788 switch (get_op_code(op)) {
790 ent = &i_ents[iro_Add];
794 ent = &i_ents[iro_Sub];
798 ent = &i_ents[iro_Shl];
802 ent = &i_ents[iro_Shr];
806 ent = &i_ents[iro_Shrs];
810 ent = &i_ents[iro_Mul];
814 ent = &i_ents[iro_Minus];
818 ent = &i_ents[iro_Abs];
822 ent = &i_ents[iro_Div];
826 ent = &i_ents[iro_Mod];
830 ent = &i_ents[iro_Conv];
834 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
835 return def_create_intrinsic_fkt(method, op, imode, omode, context);
839 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
841 ident *id = mangle(IDENT("L"), get_op_ident(op));
842 *ent = new_entity(get_glob_type(), id, method);
845 elt.i_call.kind = INTRINSIC_CALL;
846 elt.i_call.i_ent = *ent;
847 elt.i_call.i_mapper = mapper;
848 elt.i_call.ctx = context;
849 elt.i_call.link = NULL;
851 ARR_APP1(i_record, intrinsics, elt);