sparc: implement float->unsigned conversions
authorMatthias Braun <matze@braunis.de>
Wed, 11 Jan 2012 18:35:05 +0000 (19:35 +0100)
committerMatthias Braun <matze@braunis.de>
Thu, 19 Jan 2012 09:46:26 +0000 (10:46 +0100)
ir/be/sparc/bearch_sparc.c

index cfd45bb..4dc330f 100644 (file)
@@ -247,6 +247,71 @@ static void rewrite_unsigned_float_Conv(ir_node *node)
        }
 }
 
+/**
+ * rewrite float->unsigned conversions.
+ * Sparc has no instruction for this so instead we do the following:
+ *
+ * if (x >= 2147483648.) {
+ *   converted ^= (int)(x-2147483648.) ^ 0x80000000;
+ * } else {
+ *   converted = (int)x;
+ * }
+ * return (unsigned)converted;
+ */
+static void rewrite_float_unsigned_Conv(ir_node *node)
+{
+       ir_graph *irg         = get_irn_irg(node);
+       dbg_info *dbgi        = get_irn_dbg_info(node);
+       ir_node  *lower_block = get_nodes_block(node);
+
+       part_block(node);
+
+       {
+               ir_node   *block       = get_nodes_block(node);
+               ir_node   *float_x     = get_Conv_op(node);
+               ir_mode   *mode_u      = get_irn_mode(node);
+               ir_mode   *mode_s      = find_signed_mode(mode_u);
+               ir_mode   *mode_f      = get_irn_mode(float_x);
+               ir_tarval *limit       = new_tarval_from_double(2147483648., mode_f);
+               ir_node   *limitc      = new_r_Const(irg, limit);
+               ir_node   *cmp         = new_rd_Cmp(dbgi, block, float_x, limitc,
+                                                   ir_relation_greater_equal);
+               ir_node   *cond        = new_rd_Cond(dbgi, block, cmp);
+               ir_node   *proj_true   = new_r_Proj(cond, mode_X, pn_Cond_true);
+               ir_node   *proj_false  = new_r_Proj(cond, mode_X, pn_Cond_false);
+               ir_node   *in_true[1]  = { proj_true };
+               ir_node   *in_false[1] = { proj_false };
+               ir_node   *true_block  = new_r_Block(irg, ARRAY_SIZE(in_true), in_true);
+               ir_node   *false_block = new_r_Block(irg, ARRAY_SIZE(in_false),in_false);
+               ir_node   *true_jmp    = new_r_Jmp(true_block);
+               ir_node   *false_jmp   = new_r_Jmp(false_block);
+
+               ir_tarval *correction  = new_tarval_from_long(0x80000000l, mode_s);
+               ir_node   *c_const     = new_r_Const(irg, correction);
+               ir_node   *sub         = new_rd_Sub(dbgi, true_block, float_x, limitc,
+                                                   mode_f);
+               ir_node   *sub_conv    = new_rd_Conv(dbgi, true_block, sub, mode_s);
+               ir_node   *xor         = new_rd_Eor(dbgi, true_block, sub_conv, c_const,
+                                                   mode_s);
+
+               ir_node   *converted   = new_rd_Conv(dbgi, false_block, float_x,mode_s);
+
+               ir_node  *lower_in[2] = { true_jmp, false_jmp };
+               ir_node  *phi_in[2]   = { xor, converted };
+               ir_node  *phi;
+               ir_node  *res_conv;
+
+               set_irn_in(lower_block, ARRAY_SIZE(lower_in), lower_in);
+               phi = new_r_Phi(lower_block, ARRAY_SIZE(phi_in), phi_in, mode_s);
+               assert(get_Block_phis(lower_block) == NULL);
+               set_Block_phis(lower_block, phi);
+               set_Phi_next(phi, NULL);
+
+               res_conv = new_rd_Conv(dbgi, lower_block, phi, mode_u);
+               exchange(node, res_conv);
+       }
+}
+
 static int sparc_rewrite_Conv(ir_node *node, void *ctx)
 {
        ir_mode *to_mode   = get_irn_mode(node);
@@ -255,11 +320,17 @@ static int sparc_rewrite_Conv(ir_node *node, void *ctx)
        (void) ctx;
 
        if (mode_is_float(to_mode) && mode_is_int(from_mode)
-                       && get_mode_size_bits(from_mode) == 32
-                       && !mode_is_signed(from_mode)) {
+           && get_mode_size_bits(from_mode) == 32
+           && !mode_is_signed(from_mode)) {
                rewrite_unsigned_float_Conv(node);
                return 1;
        }
+       if (mode_is_float(from_mode) && mode_is_int(to_mode)
+           && get_mode_size_bits(to_mode) == 32
+           && !mode_is_signed(to_mode)) {
+           rewrite_float_unsigned_Conv(node);
+           return 1;
+       }
 
        return 0;
 }