On 20/05/14 16:52, Jakub Jelinek wrote:
> On Tue, May 20, 2014 at 12:27:31PM +1000, Kugan wrote:
>> 1.  Handling NOP_EXPR or CONVERT_EXPR that are in the IL because they
>> are required for type correctness. We have two cases here:
>>
>> A) Mode is smaller than word_mode. This is usually from where the
>> zero/sign extensions are showing up in final assembly.
>> For example :
>> int = (int) short
>> which usually expands to
>>  (set (reg:SI )
>>           (sext:SI (subreg:HI (reg:SI ))))
>> We can expand  this
>>  (set (reg:SI ) (((reg:SI ))))
>>
>> If following is true:
>> 1. Value stored in RHS and LHS are of the same signedness
>> 2. Type can hold the value. i.e., In cases like char = (char) short, we
>> check that the value in short is representable char type. (i.e. look at
>> the value range in RHS SSA_NAME and see if that can be represented in
>> types of LHS without overflowing)
>>
>> Subreg here is not a paradoxical subreg. We are removing the subreg and
>> zero/sign extend here.
>>
>> I am assuming here that QI/HI registers are represented in SImode
>> (basically word_mode) with zero/sign extend is used as in
>> (zero_extend:SI (subreg:HI (reg:SI 117)).
> 
> Wouldn't it be better to just set proper flags on the SUBREG based on value
> range info (SUBREG_PROMOTED_VAR_P and SUBREG_PROMOTED_UNSIGNED_P)?
> Then not only the optimizers could eliminate in zext/sext when possible, but
> all other optimizations could benefit from that.

Thanks for the comments. Here is an attempt (attached) that sets
SUBREG_PROMOTED_VAR_P based on value range into. Is this the good place
to do this ?

Thanks,
Kugan
diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
index b7f6360..d23ae76 100644
--- a/gcc/cfgexpand.c
+++ b/gcc/cfgexpand.c
@@ -3120,6 +3120,60 @@ expand_return (tree retval)
     }
 }
 
+
+static bool
+is_assign_promotion_redundant (struct separate_ops *ops)
+{
+  double_int type_min, type_max;
+  double_int min, max;
+  bool uns = TYPE_UNSIGNED (ops->type);
+  double_int msb;
+
+  /* We remove extension for integral stmts.  */
+  if (!INTEGRAL_TYPE_P (ops->type))
+    return false;
+
+  if (TREE_CODE_CLASS (ops->code) == tcc_unary)
+    {
+      switch (ops->code)
+       {
+       case CONVERT_EXPR:
+       case NOP_EXPR:
+
+         /* Get the value range.  */
+         if (TREE_CODE (ops->op0) != SSA_NAME
+             || POINTER_TYPE_P (TREE_TYPE (ops->op0))
+             || get_range_info (ops->op0, &min, &max) != VR_RANGE)
+           return false;
+
+         msb = double_int_one.rshift (TYPE_PRECISION (TREE_TYPE (ops->op0)));
+         if (!uns && min.cmp (msb, uns) == 1
+             && max.cmp (msb, uns) == 1)
+           {
+             min = min.sext (TYPE_PRECISION (TREE_TYPE (ops->op0)));
+             max = max.sext (TYPE_PRECISION (TREE_TYPE (ops->op0)));
+           }
+
+         /* Signedness of LHS and RHS should match or value range of RHS
+            should be all positive values to make zero/sign extension 
redundant.  */
+         if ((uns != TYPE_UNSIGNED (TREE_TYPE (ops->op0)))
+              && (min.cmp (double_int_zero, TYPE_UNSIGNED (TREE_TYPE 
(ops->op0))) == -1))
+           return false;
+
+         type_max = tree_to_double_int (TYPE_MAX_VALUE (ops->type));
+         type_min = tree_to_double_int (TYPE_MIN_VALUE (ops->type));
+
+         /* If rhs value range fits lhs type, zero/sign extension is
+           redundant.  */
+         if (max.cmp (type_max, uns) != 1
+             && (type_min.cmp (min, uns)) != 1)
+           return true;
+       }
+    }
+
+  return false;
+}
+
 /* A subroutine of expand_gimple_stmt, expanding one gimple statement
    STMT that doesn't require special handling for outgoing edges.  That
    is no tailcalls and no GIMPLE_COND.  */
@@ -3240,6 +3294,12 @@ expand_gimple_stmt_1 (gimple stmt)
              }
            ops.location = gimple_location (stmt);
 
+           if (promoted && is_assign_promotion_redundant (&ops))
+             {
+               promoted = false;
+               SUBREG_PROMOTED_VAR_P (target) = 0;
+             }
+
            /* If we want to use a nontemporal store, force the value to
               register first.  If we store into a promoted register,
               don't directly expand to target.  */

Reply via email to