- implemented ull -> float conversion for x87
[libfirm] / ir / be / ia32 / ia32_intrinsics.c
index 08ceb82..a2dc061 100644 (file)
@@ -24,9 +24,7 @@
  * @author      Michael Beck
  * @version     $Id$
  */
-#ifdef HAVE_CONFIG_H
 #include "config.h"
-#endif
 
 #include "irgmod.h"
 #include "irop.h"
@@ -45,7 +43,7 @@
 static i_record *intrinsics;
 
 /** An array to cache all entities. */
-static ir_entity *i_ents[iro_Last];
+static ir_entity *i_ents[iro_Last + 1];
 
 /*
  * Maps all intrinsic calls that the backend support
@@ -120,9 +118,9 @@ static int map_Add(ir_node *call, void *ctx) {
        /* l_res = a_l + b_l */
        /* h_res = a_h + b_h + carry */
 
-       add_low  = new_rd_ia32_l_Add(dbg, irg, block, a_l, b_l, mode_T);
+       add_low  = new_bd_ia32_l_Add(dbg, block, a_l, b_l, mode_T);
        flags    = new_r_Proj(irg, block, add_low, mode_flags, pn_ia32_flags);
-       add_high = new_rd_ia32_l_Adc(dbg, irg, block, a_h, b_h, flags, h_mode);
+       add_high = new_bd_ia32_l_Adc(dbg, block, a_h, b_h, flags, h_mode);
 
        l_res = new_r_Proj(irg, block, add_low, l_mode, pn_ia32_res);
        h_res = add_high;
@@ -155,9 +153,9 @@ static int map_Sub(ir_node *call, void *ctx)
        /* l_res = a_l - b_l */
        /* h_res = a_h - b_h - carry */
 
-       sub_low  = new_rd_ia32_l_Sub(dbg, irg, block, a_l, b_l, mode_T);
+       sub_low  = new_bd_ia32_l_Sub(dbg, block, a_l, b_l, mode_T);
        flags    = new_r_Proj(irg, block, sub_low, mode_flags, pn_ia32_flags);
-       sub_high = new_rd_ia32_l_Sbb(dbg, irg, block, a_h, b_h, flags, h_mode);
+       sub_high = new_bd_ia32_l_Sbb(dbg, block, a_h, b_h, flags, h_mode);
 
        l_res = new_r_Proj(irg, block, sub_low, l_mode, pn_ia32_res);
        h_res = sub_high;
@@ -193,14 +191,14 @@ 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 */
-                       h_res = new_rd_ia32_l_ShlD(dbg, irg, block, a_h, a_l, cnt, h_mode);
+                       h_res = new_bd_ia32_l_ShlD(dbg, block, a_h, a_l, cnt, h_mode);
 
                        /* l_res = SHL a_l, cnt */
-                       l_res = new_rd_ia32_l_ShlDep(dbg, irg, block, a_l, cnt, h_res, l_mode);
+                       l_res = new_bd_ia32_l_ShlDep(dbg, block, a_l, cnt, h_res, l_mode);
                }
 
                resolve_call(call, l_res, h_res, irg, block);
@@ -211,15 +209,15 @@ static int map_Shl(ir_node *call, void *ctx) {
        upper = get_nodes_block(call);
 
        /* h_res = SHLD a_h, a_l, cnt */
-       h1 = new_rd_ia32_l_ShlD(dbg, irg, upper, a_h, a_l, cnt, h_mode);
+       h1 = new_bd_ia32_l_ShlD(dbg, upper, a_h, a_l, cnt, h_mode);
 
        /* l_res = SHL a_l, cnt */
-       l1 = new_rd_ia32_l_ShlDep(dbg, irg, upper, a_l, cnt, h1, l_mode);
+       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);
 
@@ -229,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);
@@ -280,14 +278,14 @@ 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 */
-                       l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
+                       l_res = new_bd_ia32_l_ShrD(dbg, block, a_l, a_h, cnt, l_mode);
 
                        /* h_res = SHR a_h, cnt */
-                       h_res = new_rd_ia32_l_ShrDep(dbg, irg, block, a_h, cnt, l_res, h_mode);
+                       h_res = new_bd_ia32_l_ShrDep(dbg, block, a_h, cnt, l_res, h_mode);
                }
                resolve_call(call, l_res, h_res, irg, block);
                return 1;
@@ -297,15 +295,15 @@ static int map_Shr(ir_node *call, void *ctx) {
        upper = get_nodes_block(call);
 
        /* l_res = SHRD a_h:a_l, cnt */
-       l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
+       l1 = new_bd_ia32_l_ShrD(dbg, upper, a_l, a_h, cnt, l_mode);
 
        /* h_res = SHR a_h, cnt */
-       h1 = new_rd_ia32_l_ShrDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
+       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);
 
@@ -315,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);
@@ -368,14 +366,14 @@ 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 */
-                       l_res = new_rd_ia32_l_ShrD(dbg, irg, block, a_l, a_h, cnt, l_mode);
+                       l_res = new_bd_ia32_l_ShrD(dbg, block, a_l, a_h, cnt, l_mode);
 
                        /* h_res = SAR a_h, cnt */
-                       h_res = new_rd_ia32_l_SarDep(dbg, irg, block, a_h, cnt, l_res, h_mode);
+                       h_res = new_bd_ia32_l_SarDep(dbg, block, a_h, cnt, l_res, h_mode);
                }
                resolve_call(call, l_res, h_res, irg, block);
                return 1;
@@ -385,15 +383,15 @@ static int map_Shrs(ir_node *call, void *ctx) {
        upper = get_nodes_block(call);
 
        /* l_res = SHRD a_h:a_l, cnt */
-       l1 = new_rd_ia32_l_ShrD(dbg, irg, upper, a_l, a_h, cnt, l_mode);
+       l1 = new_bd_ia32_l_ShrD(dbg, upper, a_l, a_h, cnt, l_mode);
 
        /* h_res = SAR a_h, cnt */
-       h1 = new_rd_ia32_l_SarDep(dbg, irg, upper, a_h, cnt, l1, h_mode);
+       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);
 
@@ -403,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);
@@ -491,14 +489,14 @@ static int map_Mul(ir_node *call, void *ctx) {
 
        /* handle the often used case of 32x32=64 mul */
        if (is_sign_extend(a_l, a_h) && is_sign_extend(b_l, b_h)) {
-               mul   = new_rd_ia32_l_IMul(dbg, irg, block, a_l, b_l);
+               mul   = new_bd_ia32_l_IMul(dbg, block, a_l, b_l);
                h_res = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
                l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
 
                goto end;
        }
 
-       mul   = new_rd_ia32_l_Mul(dbg, irg, block, a_l, b_l);
+       mul   = new_bd_ia32_l_Mul(dbg, block, a_l, b_l);
        pEDX  = new_rd_Proj(dbg, irg, block, mul, h_mode, pn_ia32_l_Mul_EDX);
        l_res = new_rd_Proj(dbg, irg, block, mul, l_mode, pn_ia32_l_Mul_EAX);
 
@@ -531,7 +529,7 @@ static int map_Minus(ir_node *call, void *ctx) {
        ir_node  *l_res, *h_res, *res;
        (void) ctx;
 
-       res   = new_rd_ia32_Minus64Bit(dbg, irg, block, a_l, a_h);
+       res   = new_bd_ia32_Minus64Bit(dbg, block, a_l, a_h);
        l_res = new_r_Proj(irg, block, res, l_mode, pn_ia32_Minus64Bit_low_res);
        h_res = new_r_Proj(irg, block, res, h_mode, pn_ia32_Minus64Bit_high_res);
 
@@ -580,10 +578,10 @@ static int map_Abs(ir_node *call, void *ctx) {
        sub_l  = new_rd_Eor(dbg, irg, block, a_l, sign_l, l_mode);
        sub_h  = new_rd_Eor(dbg, irg, block, a_h, sign,   h_mode);
 
-       l_sub  = new_rd_ia32_l_Sub(dbg, irg, block, sub_l, sign_l, mode_T);
+       l_sub  = new_bd_ia32_l_Sub(dbg, block, sub_l, sign_l, mode_T);
        l_res  = new_r_Proj(irg, block, l_sub, l_mode,     pn_ia32_res);
        flags  = new_r_Proj(irg, block, l_sub, mode_flags, pn_ia32_flags);
-       h_res  = new_rd_ia32_l_Sbb(dbg, irg, block, sub_h, sign, flags, h_mode);
+       h_res  = new_bd_ia32_l_Sbb(dbg, block, sub_h, sign, flags, h_mode);
 
        resolve_call(call, l_res, h_res, irg, block);
 
@@ -687,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_rd_ia32_l_FloattoLL(dbg, irg, 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) {
@@ -707,8 +761,7 @@ static int map_Conv(ir_node *call, void *ctx) {
                assert(! mode_is_float(get_irn_mode(a_l))
                                && ! mode_is_float(get_irn_mode(a_h)));
 
-               ll_to_float = new_rd_ia32_l_LLtoFloat(dbg, irg, block, a_h, a_l,
-                                                     fres_mode);
+               ll_to_float = new_bd_ia32_l_LLtoFloat(dbg, block, a_h, a_l, fres_mode);
 
                /* lower the call */
                resolve_call(call, ll_to_float, NULL, irg, block);
@@ -784,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);
        }