- C99 feature removed
[libfirm] / ir / be / ia32 / ia32_transform.c
index c97a579..7c8d69b 100644 (file)
@@ -44,7 +44,6 @@
 #include "irprintf.h"
 #include "debug.h"
 #include "irdom.h"
-#include "archop.h"
 #include "error.h"
 #include "array_t.h"
 #include "height.h"
 #define SFP_ABS    "0x7FFFFFFF"
 #define DFP_ABS    "0x7FFFFFFFFFFFFFFF"
 #define DFP_INTMAX "9223372036854775807"
+#define ULL_BIAS   "18446744073709551616"
 
-#define TP_SFP_SIGN "ia32_sfp_sign"
-#define TP_DFP_SIGN "ia32_dfp_sign"
-#define TP_SFP_ABS  "ia32_sfp_abs"
-#define TP_DFP_ABS  "ia32_dfp_abs"
-#define TP_INT_MAX  "ia32_int_max"
-
-#define ENT_SFP_SIGN "IA32_SFP_SIGN"
-#define ENT_DFP_SIGN "IA32_DFP_SIGN"
-#define ENT_SFP_ABS  "IA32_SFP_ABS"
-#define ENT_DFP_ABS  "IA32_DFP_ABS"
-#define ENT_INT_MAX  "IA32_INT_MAX"
+#define ENT_SFP_SIGN ".LC_ia32_sfp_sign"
+#define ENT_DFP_SIGN ".LC_ia32_dfp_sign"
+#define ENT_SFP_ABS  ".LC_ia32_sfp_abs"
+#define ENT_DFP_ABS  ".LC_ia32_dfp_abs"
+#define ENT_ULL_BIAS ".LC_ia32_ull_bias"
 
 #define mode_vfp       (ia32_reg_classes[CLASS_ia32_vfp].mode)
 #define mode_xmm    (ia32_reg_classes[CLASS_ia32_xmm].mode)
@@ -278,15 +272,19 @@ static ir_node *gen_Const(ir_node *node)
                                res  = load;
                                set_ia32_ls_mode(load, mode);
                        } else {
+                               ir_mode *ls_mode;
+
                                floatent = create_float_const_entity(node);
+                               /* create_float_const_ent is smart and sometimes creates
+                                  smaller entities */
+                               ls_mode  = get_type_mode(get_entity_type(floatent));
 
-                               load     = new_bd_ia32_vfld(dbgi, block, noreg, noreg, nomem, mode);
+                               load     = new_bd_ia32_vfld(dbgi, block, noreg, noreg, nomem,
+                                                           ls_mode);
                                set_ia32_op_type(load, ia32_AddrModeS);
                                set_ia32_am_sc(load, floatent);
                                arch_irn_add_flags(load, arch_irn_flags_rematerializable);
                                res = new_r_Proj(current_ir_graph, block, load, mode_vfp, pn_ia32_vfld_res);
-                               /* take the mode from the entity */
-                               set_ia32_ls_mode(load, get_type_mode(get_entity_type(floatent)));
                        }
                }
 end:
@@ -352,47 +350,149 @@ static ir_node *gen_SymConst(ir_node *node)
        return cnst;
 }
 
+/**
+ * Create a float type for the given mode and cache it.
+ *
+ * @param mode   the mode for the float type (might be integer mode for SSE2 types)
+ * @param align  alignment
+ */
+static ir_type *ia32_create_float_type(ir_mode *mode, unsigned align) {
+       char    buf[32];
+       ir_type *tp;
+
+       assert(align <= 16);
+
+       if (mode == mode_Iu) {
+               static ir_type *int_Iu[16] = {NULL, };
+
+               if (int_Iu[align] == NULL) {
+                       snprintf(buf, sizeof(buf), "int_Iu_%u", align);
+                       int_Iu[align] = tp = new_type_primitive(new_id_from_str(buf), mode);
+                       /* set the specified alignment */
+                       set_type_alignment_bytes(tp, align);
+               }
+               return int_Iu[align];
+       } else if (mode == mode_Lu) {
+               static ir_type *int_Lu[16] = {NULL, };
+
+               if (int_Lu[align] == NULL) {
+                       snprintf(buf, sizeof(buf), "int_Lu_%u", align);
+                       int_Lu[align] = tp = new_type_primitive(new_id_from_str(buf), mode);
+                       /* set the specified alignment */
+                       set_type_alignment_bytes(tp, align);
+               }
+               return int_Lu[align];
+       } else if (mode == mode_F) {
+               static ir_type *float_F[16] = {NULL, };
+
+               if (float_F[align] == NULL) {
+                       snprintf(buf, sizeof(buf), "float_F_%u", align);
+                       float_F[align] = tp = new_type_primitive(new_id_from_str(buf), mode);
+                       /* set the specified alignment */
+                       set_type_alignment_bytes(tp, align);
+               }
+               return float_F[align];
+       } else if (mode == mode_D) {
+               static ir_type *float_D[16] = {NULL, };
+
+               if (float_D[align] == NULL) {
+                       snprintf(buf, sizeof(buf), "float_D_%u", align);
+                       float_D[align] = tp = new_type_primitive(new_id_from_str(buf), mode);
+                       /* set the specified alignment */
+                       set_type_alignment_bytes(tp, align);
+               }
+               return float_D[align];
+       } else {
+               static ir_type *float_E[16] = {NULL, };
+
+               if (float_E[align] == NULL) {
+                       snprintf(buf, sizeof(buf), "float_E_%u", align);
+                       float_E[align] = tp = new_type_primitive(new_id_from_str(buf), mode);
+                       /* set the specified alignment */
+                       set_type_alignment_bytes(tp, align);
+               }
+               return float_E[align];
+       }
+}
+
+/**
+ * Create a float[2] array type for the given atomic type.
+ *
+ * @param tp  the atomic type
+ */
+static ir_type *ia32_create_float_array(ir_type *tp) {
+       char     buf[32];
+       ir_mode  *mode = get_type_mode(tp);
+       unsigned align = get_type_alignment_bytes(tp);
+       ir_type  *arr;
+
+       assert(align <= 16);
+
+       if (mode == mode_F) {
+               static ir_type *float_F[16] = {NULL, };
+
+               if (float_F[align] != NULL)
+                       return float_F[align];
+               snprintf(buf, sizeof(buf), "arr_float_F_%u", align);
+               arr = float_F[align] = new_type_array(new_id_from_str(buf), 1, tp);
+       } else if (mode == mode_D) {
+               static ir_type *float_D[16] = {NULL, };
+
+               if (float_D[align] != NULL)
+                       return float_D[align];
+               snprintf(buf, sizeof(buf), "arr_float_D_%u", align);
+               arr = float_D[align] = new_type_array(new_id_from_str(buf), 1, tp);
+       } else {
+               static ir_type *float_E[16] = {NULL, };
+
+               if (float_E[align] != NULL)
+                       return float_E[align];
+               snprintf(buf, sizeof(buf), "arr_float_E_%u", align);
+               arr = float_E[align] = new_type_array(new_id_from_str(buf), 1, tp);
+       }
+       set_type_alignment_bytes(arr, align);
+       set_type_size_bytes(arr, 2 * get_type_size_bytes(tp));
+       set_type_state(arr, layout_fixed);
+       return arr;
+}
+
 /* Generates an entity for a known FP const (used for FP Neg + Abs) */
 ir_entity *ia32_gen_fp_known_const(ia32_known_const_t kct)
 {
        static const struct {
-               const char *tp_name;
                const char *ent_name;
                const char *cnst_str;
                char mode;
-               char align;
+               unsigned char align;
        } names [ia32_known_const_max] = {
-               { TP_SFP_SIGN, ENT_SFP_SIGN, SFP_SIGN,   0, 16 },       /* ia32_SSIGN */
-               { TP_DFP_SIGN, ENT_DFP_SIGN, DFP_SIGN,   1, 16 },       /* ia32_DSIGN */
-               { TP_SFP_ABS,  ENT_SFP_ABS,  SFP_ABS,    0, 16 },       /* ia32_SABS */
-               { TP_DFP_ABS,  ENT_DFP_ABS,  DFP_ABS,    1, 16 },       /* ia32_DABS */
-               { TP_INT_MAX,  ENT_INT_MAX,  DFP_INTMAX, 2, 4 }         /* ia32_INTMAX */
+               { ENT_SFP_SIGN, SFP_SIGN,   0, 16 }, /* ia32_SSIGN */
+               { ENT_DFP_SIGN, DFP_SIGN,   1, 16 }, /* ia32_DSIGN */
+               { ENT_SFP_ABS,  SFP_ABS,    0, 16 }, /* ia32_SABS */
+               { ENT_DFP_ABS,  DFP_ABS,    1, 16 }, /* ia32_DABS */
+               { ENT_ULL_BIAS, ULL_BIAS,   2, 4 }   /* ia32_ULLBIAS */
        };
        static ir_entity *ent_cache[ia32_known_const_max];
 
-       const char    *tp_name, *ent_name, *cnst_str;
+       const char    *ent_name, *cnst_str;
        ir_type       *tp;
-       ir_node       *cnst;
-       ir_graph      *rem;
        ir_entity     *ent;
        tarval        *tv;
        ir_mode       *mode;
 
        ent_name = names[kct].ent_name;
        if (! ent_cache[kct]) {
-               tp_name  = names[kct].tp_name;
                cnst_str = names[kct].cnst_str;
 
                switch (names[kct].mode) {
                case 0:  mode = mode_Iu; break;
                case 1:  mode = mode_Lu; break;
-               default: mode = mode_F; break;
+               default: mode = mode_F;  break;
                }
                tv  = new_tarval_from_str(cnst_str, strlen(cnst_str), mode);
-               tp  = new_type_primitive(new_id_from_str(tp_name), mode);
-               /* set the specified alignment */
-               set_type_alignment_bytes(tp, names[kct].align);
+               tp  = ia32_create_float_type(mode, names[kct].align);
 
+               if (kct == ia32_ULLBIAS)
+                       tp = ia32_create_float_array(tp);
                ent = new_entity(get_glob_type(), new_id_from_str(ent_name), tp);
 
                set_entity_ld_ident(ent, get_entity_ident(ent));
@@ -400,14 +500,18 @@ ir_entity *ia32_gen_fp_known_const(ia32_known_const_t kct)
                set_entity_variability(ent, variability_constant);
                set_entity_allocation(ent, allocation_static);
 
-               /* we create a new entity here: It's initialization must resist on the
-                   const code irg */
-               rem = current_ir_graph;
-               current_ir_graph = get_const_code_irg();
-               cnst = new_Const(mode, tv);
-               current_ir_graph = rem;
+               if (kct == ia32_ULLBIAS) {
+                       ir_initializer_t *initializer = create_initializer_compound(2);
+
+                       set_initializer_compound_value(initializer, 0,
+                               create_initializer_tarval(get_tarval_null(mode)));
+                       set_initializer_compound_value(initializer, 1,
+                               create_initializer_tarval(tv));
 
-               set_atomic_ent_value(ent, cnst);
+                       set_entity_initializer(ent, initializer);
+               } else {
+                       set_entity_initializer(ent, create_initializer_tarval(tv));
+               }
 
                /* cache the entry */
                ent_cache[kct] = ent;
@@ -593,9 +697,10 @@ static int is_downconv(const ir_node *node)
 
        src_mode  = get_irn_mode(get_Conv_op(node));
        dest_mode = get_irn_mode(node);
-       return ia32_mode_needs_gp_reg(src_mode)
-               && ia32_mode_needs_gp_reg(dest_mode)
-               && get_mode_size_bits(dest_mode) < get_mode_size_bits(src_mode);
+       return
+               ia32_mode_needs_gp_reg(src_mode)  &&
+               ia32_mode_needs_gp_reg(dest_mode) &&
+               get_mode_size_bits(dest_mode) <= get_mode_size_bits(src_mode);
 }
 
 /* Skip all Down-Conv's on a given node and return the resulting node. */
@@ -1486,9 +1591,8 @@ static ir_node *gen_Shrs(ir_node *node)
 {
        ir_node *left  = get_Shrs_left(node);
        ir_node *right = get_Shrs_right(node);
-       ir_mode *mode  = get_irn_mode(node);
 
-       if (is_Const(right) && mode == mode_Is) {
+       if (is_Const(right)) {
                tarval *tv = get_Const_tarval(right);
                long val = get_tarval_long(tv);
                if (val == 31) {
@@ -1502,7 +1606,7 @@ static ir_node *gen_Shrs(ir_node *node)
        }
 
        /* 8 or 16 bit sign extension? */
-       if (is_Const(right) && is_Shl(left) && mode == mode_Is) {
+       if (is_Const(right) && is_Shl(left)) {
                ir_node *shl_left  = get_Shl_left(left);
                ir_node *shl_right = get_Shl_right(left);
                if (is_Const(shl_right)) {
@@ -2222,16 +2326,25 @@ static ir_node *try_create_dest_am(ir_node *node)
        return new_node;
 }
 
+static bool possible_int_mode_for_fp(ir_mode *mode)
+{
+       unsigned size;
+
+       if (!mode_is_signed(mode))
+               return false;
+       size = get_mode_size_bits(mode);
+       if (size != 16 && size != 32)
+               return false;
+       return true;
+}
+
 static int is_float_to_int_conv(const ir_node *node)
 {
        ir_mode  *mode = get_irn_mode(node);
-       unsigned  size = get_mode_size_bits(mode);
        ir_node  *conv_op;
        ir_mode  *conv_mode;
 
-       if (size != 16 && size != 32)
-               return 0;
-       if (!mode_is_signed(mode))
+       if (!possible_int_mode_for_fp(mode))
                return 0;
 
        if (!is_Conv(node))
@@ -2459,8 +2572,8 @@ static ir_node *create_Switch(ir_node *node)
        ir_node  *block      = be_transform_node(get_nodes_block(node));
        ir_node  *sel        = get_Cond_selector(node);
        ir_node  *new_sel    = be_transform_node(sel);
-       int       switch_min = INT_MAX;
-       int       switch_max = INT_MIN;
+       long      switch_min = LONG_MAX;
+       long      switch_max = LONG_MIN;
        long      default_pn = get_Cond_defaultProj(node);
        ir_node  *new_node;
        const ir_edge_t *edge;
@@ -2480,7 +2593,7 @@ static ir_node *create_Switch(ir_node *node)
                        switch_max = pn;
        }
 
-       if ((unsigned) (switch_max - switch_min) > 256000) {
+       if ((unsigned long) (switch_max - switch_min) > 256000) {
                panic("Size of switch %+F bigger than 256000", node);
        }
 
@@ -2858,7 +2971,9 @@ static ir_node *create_Doz(ir_node *psi, ir_node *a, ir_node *b)
 {
        ir_graph *irg   = current_ir_graph;
        ir_mode  *mode  = get_irn_mode(psi);
-       ir_node  *new_node, *sub, *sbb, *eflags, *block, *noreg, *tmpreg, *nomem;
+       ir_node  *nomem = new_NoMem();
+       ir_node  *new_node, *sub, *sbb, *eflags, *block, *noreg;
+
        dbg_info *dbgi;
 
        new_node = gen_binop(psi, a, b, new_bd_ia32_Sub,
@@ -2877,16 +2992,73 @@ static ir_node *create_Doz(ir_node *psi, ir_node *a, ir_node *b)
        eflags = new_rd_Proj(NULL, irg, block, sub, mode_Iu, pn_ia32_Sub_flags);
 
        dbgi   = get_irn_dbg_info(psi);
-       noreg  = ia32_new_NoReg_gp(env_cg);
-       tmpreg = new_bd_ia32_ProduceVal(dbgi, block);
-       nomem  = new_NoMem();
-       sbb    = new_bd_ia32_Sbb(dbgi, block, noreg, noreg, nomem, tmpreg, tmpreg, eflags);
+       sbb    = new_bd_ia32_Sbb0(dbgi, block, eflags);
 
+       noreg    = ia32_new_NoReg_gp(env_cg);
        new_node = new_bd_ia32_And(dbgi, block, noreg, noreg, nomem, new_node, sbb);
        set_ia32_commutative(new_node);
        return new_node;
 }
 
+/**
+ * Create an const array of two float consts.
+ *
+ * @param c0        the first constant
+ * @param c1        the second constant
+ * @param new_mode  IN/OUT for the mode of the constants, if NULL
+ *                  smallest possible mode will be used
+ */
+static ir_entity *ia32_create_const_array(ir_node *c0, ir_node *c1, ir_mode **new_mode) {
+       ir_entity        *ent;
+       ir_mode          *mode = *new_mode;
+       ir_type          *tp;
+       ir_initializer_t *initializer;
+       tarval           *tv0 = get_Const_tarval(c0);
+       tarval           *tv1 = get_Const_tarval(c1);
+
+       if (mode == NULL) {
+               /* detect the best mode for the constants */
+               mode = get_tarval_mode(tv0);
+
+               if (mode != mode_F) {
+                       if (tarval_ieee754_can_conv_lossless(tv0, mode_F) &&
+                           tarval_ieee754_can_conv_lossless(tv1, mode_F)) {
+                               mode = mode_F;
+                               tv0 = tarval_convert_to(tv0, mode);
+                               tv1 = tarval_convert_to(tv1, mode);
+                       } else if (mode != mode_D) {
+                               if (tarval_ieee754_can_conv_lossless(tv0, mode_D) &&
+                                   tarval_ieee754_can_conv_lossless(tv1, mode_D)) {
+                                       mode = mode_D;
+                                       tv0 = tarval_convert_to(tv0, mode);
+                                       tv1 = tarval_convert_to(tv1, mode);
+                               }
+                       }
+               }
+
+       }
+
+       tp = ia32_create_float_type(mode, 4);
+       tp = ia32_create_float_array(tp);
+
+       ent = new_entity(get_glob_type(), ia32_unique_id(".LC%u"), tp);
+
+       set_entity_ld_ident(ent, get_entity_ident(ent));
+       set_entity_visibility(ent, visibility_local);
+       set_entity_variability(ent, variability_constant);
+       set_entity_allocation(ent, allocation_static);
+
+       initializer = create_initializer_compound(2);
+
+       set_initializer_compound_value(initializer, 0, create_initializer_tarval(tv0));
+       set_initializer_compound_value(initializer, 1, create_initializer_tarval(tv1));
+
+       set_entity_initializer(ent, initializer);
+
+       *new_mode = mode;
+       return ent;
+}
+
 /**
  * Transforms a Mux node into CMov.
  *
@@ -2901,6 +3073,8 @@ static ir_node *gen_Mux(ir_node *node)
        ir_node  *mux_false   = get_Mux_false(node);
        ir_node  *cond        = get_Mux_sel(node);
        ir_mode  *mode        = get_irn_mode(node);
+       ir_node  *flags;
+       ir_node  *new_node;
        pn_Cmp   pnc;
 
        assert(get_irn_mode(cond) == mode_b);
@@ -2935,12 +3109,83 @@ static ir_node *gen_Mux(ir_node *node)
                                }
                        }
                }
+               if (is_Const(mux_true) && is_Const(mux_false)) {
+                       ia32_address_mode_t am;
+                       ir_node             *noreg = ia32_new_NoReg_gp(env_cg);
+                       ir_node             *nomem = new_NoMem();
+                       ir_node             *load;
+                       ir_mode             *new_mode;
+                       unsigned            scale;
+
+                       flags    = get_flags_node(cond, &pnc);
+                       new_node = create_set_32bit(dbgi, new_block, flags, pnc, node, /*is_premuted=*/0);
+
+                       if (ia32_cg_config.use_sse2) {
+                               /* cannot load from different mode on SSE */
+                               new_mode = mode;
+                       } else {
+                               /* x87 can load any mode */
+                               new_mode = NULL;
+                       }
+
+                       am.addr.symconst_ent = ia32_create_const_array(mux_false, mux_true, &new_mode);
+
+                       switch (get_mode_size_bytes(new_mode)) {
+                       case 4:
+                               scale = 2;
+                               break;
+                       case 8:
+                               scale = 3;
+                               break;
+                       case 10:
+                               /* use 2 * 5 */
+                               scale = 1;
+                               new_node = new_bd_ia32_Lea(dbgi, new_block, new_node, new_node);
+                               set_ia32_am_scale(new_node, 2);
+                               break;
+                       case 12:
+                               /* use 4 * 3 */
+                               scale = 2;
+                               new_node = new_bd_ia32_Lea(dbgi, new_block, new_node, new_node);
+                               set_ia32_am_scale(new_node, 1);
+                               break;
+                       case 16:
+                               /* arg, shift 16 NOT supported */
+                               scale = 3;
+                               new_node = new_bd_ia32_Add(dbgi, new_block, noreg, noreg, nomem, new_node, new_node);
+                               break;
+                       default:
+                               panic("Unsupported constant size");
+                       }
+
+                       am.ls_mode            = new_mode;
+                       am.addr.base          = noreg;
+                       am.addr.index         = new_node;
+                       am.addr.mem           = nomem;
+                       am.addr.offset        = 0;
+                       am.addr.scale         = scale;
+                       am.addr.use_frame     = 0;
+                       am.addr.frame_entity  = NULL;
+                       am.addr.symconst_sign = 0;
+                       am.mem_proj           = am.addr.mem;
+                       am.op_type            = ia32_AddrModeS;
+                       am.new_op1            = NULL;
+                       am.new_op2            = NULL;
+                       am.pinned             = op_pin_state_floats;
+                       am.commutative        = 1;
+                       am.ins_permuted       = 0;
+
+                       if (ia32_cg_config.use_sse2)
+                               load = new_bd_ia32_xLoad(dbgi, block, am.addr.base, am.addr.index, am.addr.mem, new_mode);
+                       else
+                               load = new_bd_ia32_vfld(dbgi, block, am.addr.base, am.addr.index, am.addr.mem, new_mode);
+                       set_am_attributes(load, &am);
+
+                       return new_rd_Proj(NULL, current_ir_graph, block, load, mode_vfp, pn_ia32_res);
+               }
                panic("cannot transform floating point Mux");
 
        } else {
-               ir_node *flags;
-               ir_node *new_node;
-
                assert(ia32_mode_needs_gp_reg(mode));
 
                if (is_Proj(cond)) {
@@ -3093,10 +3338,7 @@ static ir_node *gen_x87_gp_to_fp(ir_node *node, ir_mode *src_mode)
        ir_node  *new_node;
 
        /* fild can use source AM if the operand is a signed 16bit or 32bit integer */
-       if (mode_is_signed(src_mode) && (
-                               get_mode_size_bits(src_mode) == 32 ||
-                               get_mode_size_bits(src_mode) == 16
-                       )) {
+       if (possible_int_mode_for_fp(src_mode)) {
                ia32_address_mode_t am;
 
                match_arguments(&am, src_block, NULL, op, NULL, match_am | match_try_am | match_16bit_am);
@@ -3126,8 +3368,10 @@ static ir_node *gen_x87_gp_to_fp(ir_node *node, ir_mode *src_mode)
 
        /* first convert to 32 bit signed if necessary */
        if (get_mode_size_bits(src_mode) < 32) {
-               new_op = create_Conv_I2I(dbgi, block, noreg, noreg, nomem, new_op, src_mode);
-               SET_IA32_ORIG_NODE(new_op, node);
+               if (!upper_bits_clean(new_op, src_mode)) {
+                       new_op = create_Conv_I2I(dbgi, block, noreg, noreg, nomem, new_op, src_mode);
+                       SET_IA32_ORIG_NODE(new_op, node);
+               }
                mode = mode_Is;
        }
 
@@ -3247,6 +3491,9 @@ static ir_node *gen_Conv(ir_node *node)
        ir_node  *nomem     = new_NoMem();
        ir_node  *res       = NULL;
 
+       assert(!mode_is_int(src_mode) || src_bits <= 32);
+       assert(!mode_is_int(tgt_mode) || tgt_bits <= 32);
+
        if (src_mode == mode_b) {
                assert(mode_is_int(tgt_mode) || mode_is_reference(tgt_mode));
                /* nothing to do, we already model bools as 0/1 ints */
@@ -3271,11 +3518,15 @@ static ir_node *gen_Conv(ir_node *node)
                new_op = be_transform_node(op);
                /* we convert from float ... */
                if (mode_is_float(tgt_mode)) {
+#if 0
+                       /* Matze: I'm a bit unsure what the following is for? seems wrong
+                        * to me... */
                        if (src_mode == mode_E && tgt_mode == mode_D
                                        && !get_Conv_strict(node)) {
                                DB((dbg, LEVEL_1, "killed Conv(mode, mode) ..."));
                                return new_op;
                        }
+#endif
 
                        /* ... to float */
                        if (ia32_cg_config.use_sse2) {
@@ -3285,9 +3536,18 @@ static ir_node *gen_Conv(ir_node *node)
                                set_ia32_ls_mode(res, tgt_mode);
                        } else {
                                if (get_Conv_strict(node)) {
-                                       res = gen_x87_strict_conv(tgt_mode, new_op);
-                                       SET_IA32_ORIG_NODE(get_Proj_pred(res), node);
-                                       return res;
+                                       /* if fp_no_float_fold is not set then we assume that we
+                                        * don't have any float operations in a non
+                                        * mode_float_arithmetic mode and can skip strict upconvs */
+                                       if (src_bits < tgt_bits
+                                                       && !(get_irg_fp_model(current_ir_graph) & fp_no_float_fold)) {
+                                               DB((dbg, LEVEL_1, "killed Conv(float, float) ..."));
+                                               return new_op;
+                                       } else {
+                                               res = gen_x87_strict_conv(tgt_mode, new_op);
+                                               SET_IA32_ORIG_NODE(get_Proj_pred(res), node);
+                                               return res;
+                                       }
                                }
                                DB((dbg, LEVEL_1, "killed Conv(float, float) ..."));
                                return new_op;
@@ -3314,24 +3574,15 @@ static ir_node *gen_Conv(ir_node *node)
                                                            nomem, new_op);
                                set_ia32_ls_mode(res, tgt_mode);
                        } else {
+                               unsigned int_mantissa   = get_mode_size_bits(src_mode) - (mode_is_signed(src_mode) ? 1 : 0);
+                               unsigned float_mantissa = tarval_ieee754_get_mantissa_size(tgt_mode);
                                res = gen_x87_gp_to_fp(node, src_mode);
-                               if (get_Conv_strict(node)) {
-                                       /* The strict-Conv is only necessary, if the int mode has more bits
-                                        * than the float mantissa */
-                                       size_t int_mantissa = get_mode_size_bits(src_mode) - (mode_is_signed(src_mode) ? 1 : 0);
-                                       size_t float_mantissa;
-                                       /* FIXME There is no way to get the mantissa size of a mode */
-                                       switch (get_mode_size_bits(tgt_mode)) {
-                                               case 32: float_mantissa = 23 + 1; break; // + 1 for implicit 1
-                                               case 64: float_mantissa = 52 + 1; break;
-                                               case 80:
-                                               case 96: float_mantissa = 64;     break;
-                                               default: float_mantissa = 0;      break;
-                                       }
-                                       if (float_mantissa < int_mantissa) {
-                                               res = gen_x87_strict_conv(tgt_mode, res);
-                                               SET_IA32_ORIG_NODE(get_Proj_pred(res), node);
-                                       }
+
+                               /* we need a strict-Conv, if the int mode has more bits than the
+                                * float mantissa */
+                               if (float_mantissa < int_mantissa) {
+                                       res = gen_x87_strict_conv(tgt_mode, res);
+                                       SET_IA32_ORIG_NODE(get_Proj_pred(res), node);
                                }
                                return res;
                        }
@@ -3782,13 +4033,11 @@ static ir_node *gen_ia32_l_LLtoFloat(ir_node *node)
        ir_node  *new_val_low  = be_transform_node(val_low);
        ir_node  *new_val_high = be_transform_node(val_high);
        ir_node  *in[2];
-       ir_node  *sync;
-       ir_node  *fild;
-       ir_node  *store_low;
-       ir_node  *store_high;
+       ir_node  *sync, *fild, *res;
+       ir_node  *store_low, *store_high;
 
-       if (!mode_is_signed(get_irn_mode(val_high))) {
-               panic("unsigned long long -> float not supported yet (%+F)", node);
+       if (ia32_cg_config.use_sse2) {
+               panic("ia32_l_LLtoFloat not implemented for SSE2");
        }
 
        /* do a store */
@@ -3820,7 +4069,40 @@ static ir_node *gen_ia32_l_LLtoFloat(ir_node *node)
 
        SET_IA32_ORIG_NODE(fild, node);
 
-       return new_r_Proj(irg, block, fild, mode_vfp, pn_ia32_vfild_res);
+       res = new_r_Proj(irg, block, fild, mode_vfp, pn_ia32_vfild_res);
+
+       if (! mode_is_signed(get_irn_mode(val_high))) {
+               ia32_address_mode_t  am;
+
+               ir_node *count = create_Immediate(NULL, 0, 31);
+               ir_node *fadd;
+
+               am.addr.base          = ia32_new_NoReg_gp(env_cg);
+               am.addr.index         = new_bd_ia32_Shr(dbgi, block, new_val_high, count);
+               am.addr.mem           = nomem;
+               am.addr.offset        = 0;
+               am.addr.scale         = 2;
+               am.addr.symconst_ent  = ia32_gen_fp_known_const(ia32_ULLBIAS);
+               am.addr.use_frame     = 0;
+               am.addr.frame_entity  = NULL;
+               am.addr.symconst_sign = 0;
+               am.ls_mode            = mode_F;
+               am.mem_proj           = nomem;
+               am.op_type            = ia32_AddrModeS;
+               am.new_op1            = res;
+               am.new_op2            = ia32_new_NoReg_vfp(env_cg);
+               am.pinned             = op_pin_state_floats;
+               am.commutative        = 1;
+               am.ins_permuted       = 0;
+
+               fadd  = new_bd_ia32_vfadd(dbgi, block, am.addr.base, am.addr.index, am.addr.mem,
+                       am.new_op1, am.new_op2, get_fpcw());
+               set_am_attributes(fadd, &am);
+
+               set_irn_mode(fadd, mode_T);
+               res = new_rd_Proj(NULL, irg, block, fadd, mode_vfp, pn_ia32_res);
+       }
+       return res;
 }
 
 static ir_node *gen_ia32_l_FloattoLL(ir_node *node)