- implemented ull -> float conversion for x87
[libfirm] / ir / be / ia32 / ia32_intrinsics.c
index 2831bce..a2dc061 100644 (file)
@@ -191,7 +191,7 @@ static int map_Shl(ir_node *call, void *ctx) {
                           need to reduce the constant here, this is done by the hardware.  */
                        ir_node *conv = new_rd_Conv(dbg, irg, block, a_l, h_mode);
                        h_res = new_rd_Shl(dbg, irg, block, conv, cnt, h_mode);
-                       l_res = new_rd_Const(dbg, irg, block, l_mode, get_mode_null(l_mode));
+                       l_res = new_rd_Const(dbg, irg, l_mode, get_mode_null(l_mode));
 
                } else {
                        /* h_res = SHLD a_h, a_l, cnt */
@@ -215,9 +215,9 @@ static int map_Shl(ir_node *call, void *ctx) {
        l1 = new_bd_ia32_l_ShlDep(dbg, upper, a_l, cnt, h1, l_mode);
 
        c_mode = get_irn_mode(cnt);
-       irn    = new_r_Const_long(irg, upper, c_mode, 32);
+       irn    = new_r_Const_long(irg, c_mode, 32);
        irn    = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
-       irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
+       irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, c_mode, get_mode_null(c_mode)));
        irn    = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
        cond   = new_rd_Cond(dbg, irg, upper, irn);
 
@@ -227,7 +227,7 @@ static int map_Shl(ir_node *call, void *ctx) {
        /* the block for cnt >= 32 */
        n_block = new_rd_Block(dbg, irg, 1, &in[1]);
        h2      = new_rd_Conv(dbg, irg, n_block, l1, h_mode);
-       l2      = new_r_Const(irg, n_block, l_mode, get_mode_null(l_mode));
+       l2      = new_r_Const(irg, l_mode, get_mode_null(l_mode));
        in[1]   = new_r_Jmp(irg, n_block);
 
        set_irn_in(block, 2, in);
@@ -278,7 +278,7 @@ static int map_Shr(ir_node *call, void *ctx) {
                        /* simplest case: shift only the higher bits. Note that there is no
                           need to reduce the constant here, this is done by the hardware.  */
                        ir_node *conv = new_rd_Conv(dbg, irg, block, a_h, l_mode);
-                       h_res = new_rd_Const(dbg, irg, block, h_mode, get_mode_null(h_mode));
+                       h_res = new_rd_Const(dbg, irg, h_mode, get_mode_null(h_mode));
                        l_res = new_rd_Shr(dbg, irg, block, conv, cnt, l_mode);
                } else {
                        /* l_res = SHRD a_h:a_l, cnt */
@@ -301,9 +301,9 @@ static int map_Shr(ir_node *call, void *ctx) {
        h1 = new_bd_ia32_l_ShrDep(dbg, upper, a_h, cnt, l1, h_mode);
 
        c_mode = get_irn_mode(cnt);
-       irn    = new_r_Const_long(irg, upper, c_mode, 32);
+       irn    = new_r_Const_long(irg, c_mode, 32);
        irn    = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
-       irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
+       irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, c_mode, get_mode_null(c_mode)));
        irn    = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
        cond   = new_rd_Cond(dbg, irg, upper, irn);
 
@@ -313,7 +313,7 @@ static int map_Shr(ir_node *call, void *ctx) {
        /* the block for cnt >= 32 */
        n_block = new_rd_Block(dbg, irg, 1, &in[1]);
        l2      = new_rd_Conv(dbg, irg, n_block, h1, l_mode);
-       h2      = new_r_Const(irg, n_block, h_mode, get_mode_null(h_mode));
+       h2      = new_r_Const(irg, h_mode, get_mode_null(h_mode));
        in[1]   = new_r_Jmp(irg, n_block);
 
        set_irn_in(block, 2, in);
@@ -366,7 +366,7 @@ static int map_Shrs(ir_node *call, void *ctx) {
                        ir_node *conv    = new_rd_Conv(dbg, irg, block, a_h, l_mode);
                        ir_mode *c_mode  = get_irn_mode(cnt);
 
-                       h_res = new_rd_Shrs(dbg, irg, block, a_h, new_r_Const_long(irg, block, c_mode, 31), h_mode);
+                       h_res = new_rd_Shrs(dbg, irg, block, a_h, new_r_Const_long(irg, c_mode, 31), h_mode);
                        l_res = new_rd_Shrs(dbg, irg, block, conv, cnt, l_mode);
                } else {
                        /* l_res = SHRD a_h:a_l, cnt */
@@ -389,9 +389,9 @@ static int map_Shrs(ir_node *call, void *ctx) {
        h1 = new_bd_ia32_l_SarDep(dbg, upper, a_h, cnt, l1, h_mode);
 
        c_mode = get_irn_mode(cnt);
-       irn    = new_r_Const_long(irg, upper, c_mode, 32);
+       irn    = new_r_Const_long(irg, c_mode, 32);
        irn    = new_rd_And(dbg, irg, upper, cnt, irn, c_mode);
-       irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, upper, c_mode, get_mode_null(c_mode)));
+       irn    = new_rd_Cmp(dbg, irg, upper, irn, new_r_Const(irg, c_mode, get_mode_null(c_mode)));
        irn    = new_r_Proj(irg, upper, irn, mode_b, pn_Cmp_Eq);
        cond   = new_rd_Cond(dbg, irg, upper, irn);
 
@@ -401,7 +401,7 @@ static int map_Shrs(ir_node *call, void *ctx) {
        /* the block for cnt >= 32 */
        n_block = new_rd_Block(dbg, irg, 1, &in[1]);
        l2      = new_rd_Conv(dbg, irg, n_block, h1, l_mode);
-       h2      = new_rd_Shrs(dbg, irg, n_block, a_h, new_r_Const_long(irg, block, c_mode, 31), h_mode);
+       h2      = new_rd_Shrs(dbg, irg, n_block, a_h, new_r_Const_long(irg, c_mode, 31), h_mode);
        in[1]   = new_r_Jmp(irg, n_block);
 
        set_irn_in(block, 2, in);
@@ -685,13 +685,69 @@ static int map_Conv(ir_node *call, void *ctx) {
 
                assert(mode_is_float(get_irn_mode(a_f)) && "unexpected Conv call");
 
-               float_to_ll = new_bd_ia32_l_FloattoLL(dbg, block, a_f);
+               if (mode_is_signed(h_res_mode)) {
+                       /* convert from float to signed 64bit */
+                       float_to_ll = new_bd_ia32_l_FloattoLL(dbg, block, a_f);
 
-               l_res = new_r_Proj(irg, block, float_to_ll, l_res_mode,
-                                  pn_ia32_l_FloattoLL_res_low);
-               h_res = new_r_Proj(irg, block, float_to_ll, h_res_mode,
-                                  pn_ia32_l_FloattoLL_res_high);
+                       l_res = new_r_Proj(irg, block, float_to_ll, l_res_mode,
+                                                          pn_ia32_l_FloattoLL_res_low);
+                       h_res = new_r_Proj(irg, block, float_to_ll, h_res_mode,
+                                                          pn_ia32_l_FloattoLL_res_high);
+               } else {
+                       /* convert from float to signed 64bit */
+                       ir_mode *flt_mode = get_irn_mode(a_f);
+                       tarval  *flt_tv   = new_tarval_from_str("9223372036854775808", 19, flt_mode);
+                       ir_node *flt_corr = new_Const(flt_mode, flt_tv);
+                       ir_node *lower_blk = block;
+                       ir_node *upper_blk;
+                       ir_node *cmp, *proj, *cond, *blk, *int_phi, *flt_phi;
+                       ir_node *in[2];
+
+                       part_block(call);
+                       upper_blk = get_nodes_block(call);
+
+                       cmp   = new_rd_Cmp(dbg, irg, upper_blk, a_f, flt_corr);
+                       proj  = new_r_Proj(irg, upper_blk, cmp, mode_b, pn_Cmp_Lt);
+                       cond  = new_rd_Cond(dbg, irg, upper_blk, proj);
+                       in[0] = new_r_Proj(irg, upper_blk, cond, mode_X, pn_Cond_true);
+                       in[1] = new_r_Proj(irg, upper_blk, cond, mode_X, pn_Cond_false);
+                       blk   = new_r_Block(irg, 1, &in[1]);
+                       in[1] = new_r_Jmp(irg, blk);
+
+                       set_irn_in(lower_blk, 2, in);
+
+                       /* create to Phis */
+                       in[0] = new_Const(h_res_mode, get_mode_null(h_res_mode));
+                       in[1] = new_Const_long(h_res_mode, 0x80000000);
+
+                       int_phi = new_r_Phi(irg, lower_blk, 2, in, h_res_mode);
+
+                       in[0] = a_f;
+                       in[1] = new_rd_Sub(dbg, irg, upper_blk, a_f, flt_corr, flt_mode);
 
+                       flt_phi = new_r_Phi(irg, lower_blk, 2, in, flt_mode);
+
+                       /* fix Phi links for next part_block() */
+                       set_Block_phis(lower_blk, int_phi);
+                       set_Phi_next(int_phi, flt_phi);
+                       set_Phi_next(flt_phi, NULL);
+
+                       float_to_ll = new_bd_ia32_l_FloattoLL(dbg, lower_blk, flt_phi);
+
+                       l_res = new_r_Proj(irg, lower_blk, float_to_ll, l_res_mode,
+                                                          pn_ia32_l_FloattoLL_res_low);
+                       h_res = new_r_Proj(irg, lower_blk, float_to_ll, h_res_mode,
+                                                          pn_ia32_l_FloattoLL_res_high);
+
+                       h_res = new_rd_Add(dbg, irg, lower_blk, h_res, int_phi, h_res_mode);
+
+                       /* move the call and its Proj's to the lower block */
+                       set_nodes_block(call, lower_blk);
+
+                       for (proj = get_irn_link(call); proj != NULL; proj = get_irn_link(proj))
+                               set_nodes_block(proj, lower_blk);
+                       block = lower_blk;
+               }
                /* lower the call */
                resolve_call(call, l_res, h_res, irg, block);
        } else if (n == 2) {
@@ -781,7 +837,7 @@ ir_entity *ia32_create_intrinsic_fkt(ir_type *method, const ir_op *op,
        if (ent && ! *ent) {
 #define IDENT(s)  new_id_from_chars(s, sizeof(s)-1)
 
-               ident *id = mangle(IDENT("L"), get_op_ident(op));
+               ident *id = id_mangle(IDENT("L"), get_op_ident(op));
                *ent = new_entity(get_glob_type(), id, method);
        }