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) {
70 ir_node *bad = get_irg_bad(irg);
71 ir_node *nomem = get_irg_no_mem(irg);
75 res = new_r_Tuple(irg, block, h_res == NULL ? 1 : 2, in);
77 turn_into_tuple(call, pn_Call_max);
78 set_Tuple_pred(call, pn_Call_M_regular, nomem);
79 /* Matze: the new_r_Jmp here sometimes CSEs and then bad things happen
80 * (in movgen.c from 186.crafty for example) I don't know why it is here
81 * and if this fix is correct... */
82 /*set_Tuple_pred(call, pn_Call_X_regular, new_r_Jmp(irg, block));*/
83 set_Tuple_pred(call, pn_Call_X_regular, bad);
84 set_Tuple_pred(call, pn_Call_X_except, bad);
85 set_Tuple_pred(call, pn_Call_T_result, res);
86 set_Tuple_pred(call, pn_Call_M_except, nomem);
87 set_Tuple_pred(call, pn_Call_P_value_res_base, bad);
91 * Map an Add (a_l, a_h, b_l, b_h)
93 static int map_Add(ir_node *call, void *ctx) {
94 ir_graph *irg = current_ir_graph;
95 dbg_info *dbg = get_irn_dbg_info(call);
96 ir_node *block = get_nodes_block(call);
97 ir_node **params = get_Call_param_arr(call);
98 ir_type *method = get_Call_type(call);
99 ir_node *a_l = params[BINOP_Left_Low];
100 ir_node *a_h = params[BINOP_Left_High];
101 ir_node *b_l = params[BINOP_Right_Low];
102 ir_node *b_h = params[BINOP_Right_High];
103 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
104 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
105 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
106 ir_node *add_low, *add_high, *flags;
107 ir_node *l_res, *h_res;
110 /* l_res = a_l + b_l */
111 /* h_res = a_h + b_h + carry */
113 add_low = new_rd_ia32_l_Add(dbg, irg, block, a_l, b_l, mode_T);
114 flags = new_r_Proj(irg, block, add_low, mode_flags, pn_ia32_flags);
115 add_high = new_rd_ia32_l_Adc(dbg, irg, block, a_h, b_h, flags, h_mode);
117 l_res = new_r_Proj(irg, block, add_low, l_mode, pn_ia32_res);
120 resolve_call(call, l_res, h_res, irg, block);
125 * Map a Sub (a_l, a_h, b_l, b_h)
127 static int map_Sub(ir_node *call, void *ctx)
129 ir_graph *irg = current_ir_graph;
130 dbg_info *dbg = get_irn_dbg_info(call);
131 ir_node *block = get_nodes_block(call);
132 ir_node **params = get_Call_param_arr(call);
133 ir_type *method = get_Call_type(call);
134 ir_node *a_l = params[BINOP_Left_Low];
135 ir_node *a_h = params[BINOP_Left_High];
136 ir_node *b_l = params[BINOP_Right_Low];
137 ir_node *b_h = params[BINOP_Right_High];
138 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
139 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
140 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
141 ir_node *sub_low, *sub_high, *flags;
142 ir_node *l_res, *h_res;
145 /* l_res = a_l - b_l */
146 /* h_res = a_h - b_h - carry */
148 sub_low = new_rd_ia32_l_Sub(dbg, irg, block, a_l, b_l, mode_T);
149 flags = new_r_Proj(irg, block, sub_low, mode_flags, pn_ia32_flags);
150 sub_high = new_rd_ia32_l_Sbb(dbg, irg, block, a_h, b_h, flags, h_mode);
152 l_res = new_r_Proj(irg, block, sub_low, l_mode, pn_ia32_res);
155 resolve_call(call, l_res, h_res, irg, block);
160 * Map a Shl (a_l, a_h, count)
162 static int map_Shl(ir_node *call, void *ctx) {
163 ir_graph *irg = current_ir_graph;
164 dbg_info *dbg = get_irn_dbg_info(call);
165 ir_node *block = get_nodes_block(call);
166 ir_node **params = get_Call_param_arr(call);
167 ir_type *method = get_Call_type(call);
168 ir_node *a_l = params[BINOP_Left_Low];
169 ir_node *a_h = params[BINOP_Left_High];
170 ir_node *cnt = params[BINOP_Right_Low];
171 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
172 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
174 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
178 /* the shift count is a const, create better code */
179 tarval *tv = get_Const_tarval(cnt);
181 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
182 /* simplest case: shift only the lower bits. Note that there is no
183 need to reduce the constant here, this is done by the hardware. */
184 ir_node *conv = new_rd_Conv(dbg, irg, block, a_l, h_mode);
185 h_res = new_rd_Shl(dbg, irg, block, conv, cnt, h_mode);
186 l_res = new_rd_Const(dbg, irg, block, l_mode, get_mode_null(l_mode));
189 /* h_res = SHLD a_h, a_l, cnt */
190 h_res = new_rd_ia32_l_ShlD(dbg, irg, block, a_h, a_l, cnt, h_mode);
192 /* l_res = SHL a_l, cnt */
193 l_res = new_rd_ia32_l_ShlDep(dbg, irg, block, a_l, cnt, h_res, l_mode);
196 resolve_call(call, l_res, h_res, irg, block);
201 upper = get_nodes_block(call);
203 /* h_res = SHLD a_h, a_l, cnt */
204 h1 = new_rd_ia32_l_ShlD(dbg, irg, upper, a_h, a_l, cnt, h_mode);
206 /* l_res = SHL a_l, cnt */
207 l1 = new_rd_ia32_l_ShlDep(dbg, irg, upper, a_l, cnt, h1, l_mode);
209 c_mode = get_irn_mode(cnt);
210 irn = new_r_Const_long(irg, upper, c_mode, 32);
211 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
212 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
213 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
214 cond = new_rd_Cond(dbg, irg, upper, irn);
216 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
217 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
219 /* the block for cnt >= 32 */
220 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
221 h2 = new_rd_Conv(dbg, irg, n_block, l1, h_mode);
222 l2 = new_r_Const(irg, n_block, l_mode, get_mode_null(l_mode));
223 in[1] = new_r_Jmp(irg, n_block);
225 set_irn_in(block, 2, in);
229 l_res = new_r_Phi(irg, block, 2, in, l_mode);
230 set_irn_link(block, l_res);
234 h_res = new_r_Phi(irg, block, 2, in, h_mode);
235 set_irn_link(l_res, h_res);
236 set_irn_link(h_res, NULL);
239 set_nodes_block(call, block);
240 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
241 set_nodes_block(irn, block);
243 resolve_call(call, l_res, h_res, irg, block);
248 * Map a Shr (a_l, a_h, count)
250 static int map_Shr(ir_node *call, void *ctx) {
251 ir_graph *irg = current_ir_graph;
252 dbg_info *dbg = get_irn_dbg_info(call);
253 ir_node *block = get_nodes_block(call);
254 ir_node **params = get_Call_param_arr(call);
255 ir_type *method = get_Call_type(call);
256 ir_node *a_l = params[BINOP_Left_Low];
257 ir_node *a_h = params[BINOP_Left_High];
258 ir_node *cnt = params[BINOP_Right_Low];
259 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
260 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
262 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
266 /* the shift count is a const, create better code */
267 tarval *tv = get_Const_tarval(cnt);
269 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
270 /* simplest case: shift only the higher bits. Note that there is no
271 need to reduce the constant here, this is done by the hardware. */
272 ir_node *conv = new_rd_Conv(dbg, irg, block, a_h, l_mode);
273 h_res = new_rd_Const(dbg, irg, block, h_mode, get_mode_null(h_mode));
274 l_res = new_rd_Shr(dbg, irg, block, conv, cnt, l_mode);
276 /* l_res = SHRD a_h:a_l, cnt */
277 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
279 /* h_res = SHR a_h, cnt */
280 h_res = new_rd_ia32_l_ShrDep(dbg, irg, block, a_h, cnt, l_res, h_mode);
282 resolve_call(call, l_res, h_res, irg, block);
287 upper = get_nodes_block(call);
289 /* l_res = SHRD a_h:a_l, cnt */
290 l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
292 /* h_res = SHR a_h, cnt */
293 h1 = new_rd_ia32_l_ShrDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
295 c_mode = get_irn_mode(cnt);
296 irn = new_r_Const_long(irg, upper, c_mode, 32);
297 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
298 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
299 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
300 cond = new_rd_Cond(dbg, irg, upper, irn);
302 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
303 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
305 /* the block for cnt >= 32 */
306 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
307 l2 = new_rd_Conv(dbg, irg, n_block, h1, l_mode);
308 h2 = new_r_Const(irg, n_block, l_mode, get_mode_null(h_mode));
309 in[1] = new_r_Jmp(irg, n_block);
311 set_irn_in(block, 2, in);
315 l_res = new_r_Phi(irg, block, 2, in, l_mode);
316 set_irn_link(block, l_res);
320 h_res = new_r_Phi(irg, block, 2, in, h_mode);
321 set_irn_link(l_res, h_res);
322 set_irn_link(h_res, NULL);
325 set_nodes_block(call, block);
326 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
327 set_nodes_block(irn, block);
329 resolve_call(call, l_res, h_res, irg, block);
334 * Map a Shrs (a_l, a_h, count)
336 static int map_Shrs(ir_node *call, void *ctx) {
337 ir_graph *irg = current_ir_graph;
338 dbg_info *dbg = get_irn_dbg_info(call);
339 ir_node *block = get_nodes_block(call);
340 ir_node **params = get_Call_param_arr(call);
341 ir_type *method = get_Call_type(call);
342 ir_node *a_l = params[BINOP_Left_Low];
343 ir_node *a_h = params[BINOP_Left_High];
344 ir_node *cnt = params[BINOP_Right_Low];
345 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
346 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
348 ir_node *l_res, *h_res, *irn, *cond, *upper, *n_block, *l1, *l2, *h1, *h2, *in[2];
352 /* the shift count is a const, create better code */
353 tarval *tv = get_Const_tarval(cnt);
355 if (tarval_cmp(tv, new_tarval_from_long(32, l_mode)) & (pn_Cmp_Gt|pn_Cmp_Eq)) {
356 /* simplest case: shift only the higher bits. Note that there is no
357 need to reduce the constant here, this is done by the hardware. */
358 ir_node *conv = new_rd_Conv(dbg, irg, block, a_h, l_mode);
359 ir_mode *c_mode = get_irn_mode(cnt);
361 h_res = new_rd_Shrs(dbg, irg, block, a_h, new_r_Const_long(irg, block, c_mode, 31), h_mode);
362 l_res = new_rd_Shrs(dbg, irg, block, conv, cnt, l_mode);
364 /* l_res = SHRD a_h:a_l, cnt */
365 l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
367 /* h_res = SAR a_h, cnt */
368 h_res = new_rd_ia32_l_SarDep(dbg, irg, block, a_h, cnt, l_res, h_mode);
370 resolve_call(call, l_res, h_res, irg, block);
375 upper = get_nodes_block(call);
377 /* l_res = SHRD a_h:a_l, cnt */
378 l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
380 /* h_res = SAR a_h, cnt */
381 h1 = new_rd_ia32_l_SarDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
383 c_mode = get_irn_mode(cnt);
384 irn = new_r_Const_long(irg, upper, c_mode, 32);
385 irn = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
386 irn = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
387 irn = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
388 cond = new_rd_Cond(dbg, irg, upper, irn);
390 in[0] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_true);
391 in[1] = new_r_Proj(irg, upper, cond, mode_X, pn_Cond_false);
393 /* the block for cnt >= 32 */
394 n_block = new_rd_Block(dbg, irg, 1, &in[1]);
395 l2 = new_rd_Conv(dbg, irg, n_block, h1, l_mode);
396 h2 = new_rd_Shrs(dbg, irg, n_block, a_h, new_r_Const_long(irg, block, c_mode, 31), h_mode);
397 in[1] = new_r_Jmp(irg, n_block);
399 set_irn_in(block, 2, in);
403 l_res = new_r_Phi(irg, block, 2, in, l_mode);
404 set_irn_link(block, l_res);
408 h_res = new_r_Phi(irg, block, 2, in, h_mode);
409 set_irn_link(l_res, h_res);
410 set_irn_link(h_res, NULL);
413 set_nodes_block(call, block);
414 for (irn = get_irn_link(call); irn != NULL; irn = get_irn_link(irn))
415 set_nodes_block(irn, block);
417 resolve_call(call, l_res, h_res, irg, block);
422 * Map a Mul (a_l, a_h, b_l, b_h)
424 static int map_Mul(ir_node *call, void *ctx) {
425 ir_graph *irg = current_ir_graph;
426 dbg_info *dbg = get_irn_dbg_info(call);
427 ir_node *block = get_nodes_block(call);
428 ir_node **params = get_Call_param_arr(call);
429 ir_type *method = get_Call_type(call);
430 ir_node *a_l = params[BINOP_Left_Low];
431 ir_node *a_h = params[BINOP_Left_High];
432 ir_node *b_l = params[BINOP_Right_Low];
433 ir_node *b_h = params[BINOP_Right_High];
434 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
435 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
436 ir_node *l_res, *h_res, *mul, *pEDX, *add;
449 /* handle the often used case of 32x32=64 mul */
450 if (is_Shrs(a_h) && get_Shrs_left(a_h) == a_l) {
451 ir_node *c1 = get_Shrs_right(a_h);
454 tarval *tv = get_Const_tarval(c1);
456 if (tarval_is_long(tv) && get_tarval_long(tv) == 31) {
457 /* a is a sign extend */
459 if (is_Shrs(b_h) && get_Shrs_left(b_h) == b_l && c1 == get_Shrs_right(b_h)) {
460 /* b is a sign extend: it's a 32 * 32 = 64 signed multiplication */
461 mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
462 h_res = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
463 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
467 /* we rely here on Consts being on the right side */
468 if (is_Const(b_h) && is_Const(b_l)) {
469 tarval *th = get_Const_tarval(b_h);
470 tarval *tl = get_Const_tarval(b_l);
472 if (tarval_is_long(th) && tarval_is_long(tl)) {
473 long h = get_tarval_long(th);
474 long l = get_tarval_long(tl);
476 if ((h == 0 && l >= 0) || (h == -1 && l < 0)) {
477 /* b is a sign extended const */
478 mul = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
479 h_res = 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);
490 mul = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
491 pEDX = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
492 l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
494 b_l = new_rd_Conv(dbg, irg, block, b_l, h_mode);
495 mul = new_rd_Mul( dbg, irg, block, a_h, b_l, h_mode);
496 add = new_rd_Add( dbg, irg, block, mul, pEDX, h_mode);
497 a_l = new_rd_Conv(dbg, irg, block, a_l, h_mode);
498 mul = new_rd_Mul( dbg, irg, block, a_l, b_h, h_mode);
499 h_res = new_rd_Add( dbg, irg, block, add, mul, h_mode);
502 resolve_call(call, l_res, h_res, irg, block);
508 * Map a Minus (a_l, a_h)
510 static int map_Minus(ir_node *call, void *ctx) {
511 ir_graph *irg = current_ir_graph;
512 dbg_info *dbg = get_irn_dbg_info(call);
513 ir_node *block = get_nodes_block(call);
514 ir_node **params = get_Call_param_arr(call);
515 ir_type *method = get_Call_type(call);
516 ir_node *a_l = params[BINOP_Left_Low];
517 ir_node *a_h = params[BINOP_Left_High];
518 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
519 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
520 ir_node *l_res, *h_res, *res;
523 res = new_rd_ia32_Minus64Bit(dbg, irg, block, a_l, a_h);
524 l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
525 h_res = new_r_Proj(irg, block, res, h_mode, pn_ia32_Minus64Bit_high_res);
527 resolve_call(call, l_res, h_res, irg, block);
533 * Map a Abs (a_l, a_h)
535 static int map_Abs(ir_node *call, void *ctx) {
536 ir_graph *irg = current_ir_graph;
537 dbg_info *dbg = get_irn_dbg_info(call);
538 ir_node *block = get_nodes_block(call);
539 ir_node **params = get_Call_param_arr(call);
540 ir_type *method = get_Call_type(call);
541 ir_node *a_l = params[BINOP_Left_Low];
542 ir_node *a_h = params[BINOP_Left_High];
543 ir_mode *l_mode = get_type_mode(get_method_res_type(method, 0));
544 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
545 ir_mode *mode_flags = ia32_reg_classes[CLASS_ia32_flags].mode;
546 ir_node *l_res, *h_res, *sign, *sub_l, *sub_h;
553 Code inspired by gcc output :) (although gcc doubles the
554 operation for t1 as t2 and uses t1 for operations with low part
555 and t2 for operations with high part which is actually unnecessary
556 because t1 and t2 represent the same value)
562 h_res = t3 - t1 - carry
566 /* TODO: give a hint to the backend somehow to not create a cltd here... */
567 sign = new_rd_Shrs(dbg, irg, block, a_h, new_Const_long(l_mode, 31), h_mode);
568 sign_l = new_rd_Conv(dbg, irg, block, sign, l_mode);
569 sub_l = new_rd_Eor(dbg, irg, block, a_l, sign_l, l_mode);
570 sub_h = new_rd_Eor(dbg, irg, block, a_h, sign, h_mode);
572 l_sub = new_rd_ia32_l_Sub(dbg, irg, block, sub_l, sign_l, mode_T);
573 l_res = new_r_Proj(irg, block, l_sub, l_mode, pn_ia32_res);
574 flags = new_r_Proj(irg, block, l_sub, mode_flags, pn_ia32_flags);
575 h_res = new_rd_ia32_l_Sbb(dbg, irg, block, sub_h, sign, flags, h_mode);
577 resolve_call(call, l_res, h_res, irg, block);
582 #define ID(x) new_id_from_chars(x, sizeof(x)-1)
585 * Maps a Div. Change into a library call
587 static int map_Div(ir_node *call, void *ctx) {
588 ia32_intrinsic_env_t *env = ctx;
589 ir_type *method = get_Call_type(call);
590 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 1));
595 if (mode_is_signed(h_mode)) {
596 /* 64bit signed Division */
599 /* create library entity */
600 ent = env->divdi3 = new_entity(get_glob_type(), ID("__divdi3"), method);
601 set_entity_visibility(ent, visibility_external_allocated);
602 set_entity_ld_ident(ent, ID("__divdi3"));
605 /* 64bit unsigned Division */
608 /* create library entity */
609 ent = env->udivdi3 = new_entity(get_glob_type(), ID("__udivdi3"), method);
610 set_entity_visibility(ent, visibility_external_allocated);
611 set_entity_ld_ident(ent, ID("__udivdi3"));
615 ptr = get_Call_ptr(call);
616 set_SymConst_symbol(ptr, sym);
621 * Maps a Mod. Change into a library call
623 static int map_Mod(ir_node *call, void *ctx) {
624 ia32_intrinsic_env_t *env = ctx;
625 ir_type *method = get_Call_type(call);
626 ir_mode *h_mode = get_type_mode(get_method_res_type(method, 0));
631 if (mode_is_signed(h_mode)) {
632 /* 64bit signed Modulo */
635 /* create library entity */
636 ent = env->moddi3 = new_entity(get_glob_type(), ID("__moddi3"), method);
637 set_entity_visibility(ent, visibility_external_allocated);
638 set_entity_ld_ident(ent, ID("__moddi3"));
641 /* 64bit signed Modulo */
644 /* create library entity */
645 ent = env->umoddi3 = new_entity(get_glob_type(), ID("__umoddi3"), method);
646 set_entity_visibility(ent, visibility_external_allocated);
647 set_entity_ld_ident(ent, ID("__umoddi3"));
651 ptr = get_Call_ptr(call);
652 set_SymConst_symbol(ptr, sym);
659 static int map_Conv(ir_node *call, void *ctx) {
660 ia32_intrinsic_env_t *env = ctx;
661 ir_graph *irg = current_ir_graph;
662 dbg_info *dbg = get_irn_dbg_info(call);
663 ir_node *block = get_nodes_block(call);
664 ir_node **params = get_Call_param_arr(call);
665 ir_type *method = get_Call_type(call);
666 int n = get_Call_n_params(call);
667 int gp_bytes = get_mode_size_bytes(ia32_reg_classes[CLASS_ia32_gp].mode);
669 ir_node *l_res, *h_res, *frame, *fres;
670 ir_node *store_l, *store_h;
671 ir_node *op_mem[2], *mem;
674 /* We have a Conv float -> long long here */
675 ir_node *a_f = params[0];
676 ir_mode *l_res_mode = get_type_mode(get_method_res_type(method, 0));
677 ir_mode *h_res_mode = get_type_mode(get_method_res_type(method, 1));
679 assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
681 /* allocate memory on frame to store args */
682 ent = env->irg == irg ? env->d_ll_conv : NULL;
684 ent = env->d_ll_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
689 frame = get_irg_frame(irg);
692 Now we create a node to move the value from a XMM register into
693 x87 FPU because it is unknown here, which FPU is used.
694 This node is killed in transformation phase when not needed.
695 Otherwise it is split up into a movsd + fld
697 a_f = new_rd_ia32_l_SSEtoX87(dbg, irg, block, frame, a_f, get_irg_no_mem(irg), mode_D);
698 set_ia32_frame_ent(a_f, ent);
699 set_ia32_use_frame(a_f);
700 set_ia32_ls_mode(a_f, mode_D);
702 /* store from FPU as Int */
703 a_f = new_rd_ia32_l_vfist(dbg, irg, block, frame, a_f, get_irg_no_mem(irg));
704 set_ia32_frame_ent(a_f, ent);
705 set_ia32_use_frame(a_f);
706 set_ia32_ls_mode(a_f, mode_Ls);
709 /* load low part of the result */
710 l_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
711 set_ia32_frame_ent(l_res, ent);
712 set_ia32_use_frame(l_res);
713 set_ia32_ls_mode(l_res, l_res_mode);
714 l_res = new_r_Proj(irg, block, l_res, l_res_mode, pn_ia32_l_Load_res);
716 /* load hight part of the result */
717 h_res = new_rd_ia32_l_Load(dbg, irg, block, frame, mem);
718 set_ia32_frame_ent(h_res, ent);
719 add_ia32_am_offs_int(h_res, gp_bytes);
720 set_ia32_use_frame(h_res);
721 set_ia32_ls_mode(h_res, h_res_mode);
722 h_res = new_r_Proj(irg, block, h_res, h_res_mode, pn_ia32_l_Load_res);
725 resolve_call(call, l_res, h_res, irg, block);
728 /* We have a Conv long long -> float here */
729 ir_node *a_l = params[BINOP_Left_Low];
730 ir_node *a_h = params[BINOP_Left_High];
731 ir_mode *mode_a_l = get_irn_mode(a_l);
732 ir_mode *mode_a_h = get_irn_mode(a_h);
733 ir_mode *fres_mode = get_type_mode(get_method_res_type(method, 0));
735 assert(! mode_is_float(mode_a_l) && ! mode_is_float(mode_a_h) && "unexpected Conv call");
737 /* allocate memory on frame to store args */
738 ent = env->irg == irg ? env->ll_d_conv : NULL;
740 ent = env->ll_d_conv = frame_alloc_area(get_irg_frame_type(irg), 2 * gp_bytes, 16, 0);
745 frame = get_irg_frame(irg);
747 /* store first arg (low part) */
748 store_l = new_rd_ia32_l_Store(dbg, irg, block, frame, a_l, get_irg_no_mem(irg));
749 set_ia32_frame_ent(store_l, ent);
750 set_ia32_use_frame(store_l);
751 set_ia32_ls_mode(store_l, get_irn_mode(a_l));
754 /* store second arg (high part) */
755 store_h = new_rd_ia32_l_Store(dbg, irg, block, frame, a_h, get_irg_no_mem(irg));
756 set_ia32_frame_ent(store_h, ent);
757 add_ia32_am_offs_int(store_h, gp_bytes);
758 set_ia32_use_frame(store_h);
759 set_ia32_ls_mode(store_h, get_irn_mode(a_h));
762 mem = new_r_Sync(irg, block, 2, op_mem);
764 /* Load arg into x87 FPU (implicit convert) */
765 fres = new_rd_ia32_l_vfild(dbg, irg, block, frame, mem);
766 set_ia32_frame_ent(fres, ent);
767 set_ia32_use_frame(fres);
768 set_ia32_ls_mode(fres, mode_D);
769 mem = new_r_Proj(irg, block, fres, mode_M, pn_ia32_l_vfild_M);
770 fres = new_r_Proj(irg, block, fres, fres_mode, pn_ia32_l_vfild_res);
773 Now we create a node to move the loaded value into a XMM
774 register because it is unknown here, which FPU is used.
775 This node is killed in transformation phase when not needed.
776 Otherwise it is split up into a fst + movsd
778 fres = new_rd_ia32_l_X87toSSE(dbg, irg, block, frame, fres, mem, fres_mode);
779 set_ia32_frame_ent(fres, ent);
780 set_ia32_use_frame(fres);
781 set_ia32_ls_mode(fres, fres_mode);
784 resolve_call(call, fres, NULL, irg, block);
787 assert(0 && "unexpected Conv call");
793 /* Ia32 implementation of intrinsic mapping. */
794 ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
795 const ir_mode *imode, const ir_mode *omode,
799 ir_entity **ent = NULL;
800 i_mapper_func mapper;
803 intrinsics = NEW_ARR_F(i_record, 0);
805 switch (get_op_code(op)) {
807 ent = &i_ents[iro_Add];
811 ent = &i_ents[iro_Sub];
815 ent = &i_ents[iro_Shl];
819 ent = &i_ents[iro_Shr];
823 ent = &i_ents[iro_Shrs];
827 ent = &i_ents[iro_Mul];
831 ent = &i_ents[iro_Minus];
835 ent = &i_ents[iro_Abs];
839 ent = &i_ents[iro_Div];
843 ent = &i_ents[iro_Mod];
847 ent = &i_ents[iro_Conv];
851 fprintf(stderr, "FIXME: unhandled op for ia32 intrinsic function %s\n", get_id_str(op->name));
852 return def_create_intrinsic_fkt(method, op, imode, omode, context);
856 #define IDENT(s) new_id_from_chars(s, sizeof(s)-1)
858 ident *id = mangle(IDENT("L"), get_op_ident(op));
859 *ent = new_entity(get_glob_type(), id, method);
862 elt.i_call.kind = INTRINSIC_CALL;
863 elt.i_call.i_ent = *ent;
864 elt.i_call.i_mapper = mapper;
865 elt.i_call.ctx = context;
866 elt.i_call.link = NULL;
868 ARR_APP1(i_record, intrinsics, elt);