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