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. */