Message ID | 1482247.PF6A0dtnAY@polaris |
---|---|
State | New |
Headers | show |
On 23/11/2016 10:35, Eric Botcazou wrote: > I now wonder > whether this also matters for !WORD_REGISTER_OPERATIONS targets, e.g. x86: > > (set (reg1:DI) ... > ... > (set (reg1:QI) (expression:QI)) > ... > (set (reg2:DI) (any_extend:DI (reg1:QI))) > ... > (use (reg1:DI)) > > where the use reads well-defined upper bits from the very first set. Does it really do that with a (set (reg1:QI)), as opposed to a (set (strict_low_part (subreg:QI (reg1:DI)))? Paolo
> Does it really do that with a (set (reg1:QI)), as opposed to a > (set (strict_low_part (subreg:QI (reg1:DI)))? That's the question (note that REE runs after register allocation). -- Eric Botcazou
On 23/11/2016 11:26, Eric Botcazou wrote: >> Does it really do that with a (set (reg1:QI)), as opposed to a >> (set (strict_low_part (subreg:QI (reg1:DI)))? > > That's the question (note that REE runs after register allocation). IIRC, strict_low_part is required even after register allocation, and patterns such as this one in config/i386/i386.md seem to confirm it: (define_split [(set (match_operand:SWI248 0 "any_QIreg_operand") (and:SWI248 (match_dup 0) (const_int -256))) (clobber (reg:CC FLAGS_REG))] "(!TARGET_PARTIAL_REG_STALL || optimize_function_for_size_p (cfun)) && reload_completed" [(set (strict_low_part (match_dup 1)) (const_int 0))] "operands[1] = gen_lowpart (QImode, operands[0]);") (Note the "&& reload_completed"). Thanks, Paolo
On 11/23/2016 11:18 AM, Paolo Bonzini wrote: > > > On 23/11/2016 10:35, Eric Botcazou wrote: >> I now wonder >> whether this also matters for !WORD_REGISTER_OPERATIONS targets, e.g. x86: >> >> (set (reg1:DI) ... >> ... >> (set (reg1:QI) (expression:QI)) >> ... >> (set (reg2:DI) (any_extend:DI (reg1:QI))) >> ... >> (use (reg1:DI)) >> >> where the use reads well-defined upper bits from the very first set. > > Does it really do that with a (set (reg1:QI)), as opposed to a > (set (strict_low_part (subreg:QI (reg1:DI)))? It would need strict_low_part unless we're dealing with subwords. I think the patch should maybe check for that in the !W_R_O case. Does WORD_REGISTER_OPERATIONS really buy much on targets that use it? This sort of situation seems very surprising and unfortunate. Bernd
On 11/23/2016 05:26 AM, Bernd Schmidt wrote: > On 11/23/2016 11:18 AM, Paolo Bonzini wrote: >> >> >> On 23/11/2016 10:35, Eric Botcazou wrote: >>> I now wonder >>> whether this also matters for !WORD_REGISTER_OPERATIONS targets, e.g. >>> x86: >>> >>> (set (reg1:DI) ... >>> ... >>> (set (reg1:QI) (expression:QI)) >>> ... >>> (set (reg2:DI) (any_extend:DI (reg1:QI))) >>> ... >>> (use (reg1:DI)) >>> >>> where the use reads well-defined upper bits from the very first set. >> >> Does it really do that with a (set (reg1:QI)), as opposed to a >> (set (strict_low_part (subreg:QI (reg1:DI)))? > > It would need strict_low_part unless we're dealing with subwords. I > think the patch should maybe check for that in the !W_R_O case. > > Does WORD_REGISTER_OPERATIONS really buy much on targets that use it? > This sort of situation seems very surprising and unfortunate. It certainly was helpful on the PA back in the day. Less sure on modern systems. jeff
On 11/23/2016 03:32 AM, Paolo Bonzini wrote: > > > On 23/11/2016 11:26, Eric Botcazou wrote: >>> Does it really do that with a (set (reg1:QI)), as opposed to a >>> (set (strict_low_part (subreg:QI (reg1:DI)))? >> >> That's the question (note that REE runs after register allocation). > > IIRC, strict_low_part is required even after register allocation, and > patterns such as this one in config/i386/i386.md seem to confirm it: Right. The strict_low_part is required after register allocation. Without the strict_low_part, the contents of the bits outside the mode of the strict_low_part are undefined. Jeff
> It would need strict_low_part unless we're dealing with subwords. I > think the patch should maybe check for that in the !W_R_O case. The code already does the check, it simply won't mess with strict_low_part. > Does WORD_REGISTER_OPERATIONS really buy much on targets that use it? Yes, it makes it possible for the combiner to eliminate 2 redundant extensions on Alpha for the reduced testcase provided by Uros (that's why there is the mode mismatch). And it's even more helpful if the loads are not explicitly extended, like on SPARC (in combination with LOAD_EXTEND_OP of course). -- Eric Botcazou
Index: ree.c =================================================================== --- ree.c (revision 242632) +++ ree.c (working copy) @@ -499,6 +499,35 @@ get_defs (rtx_insn *insn, rtx reg, vec<r return ref_chain; } +/* Get all the reaching uses of an instruction. The uses are desired for REG + set in INSN. Return use list or NULL if a use is missing or irregular. */ + +static struct df_link * +get_uses (rtx_insn *insn, rtx reg) +{ + df_ref def; + struct df_link *ref_chain, *ref_link; + + FOR_EACH_INSN_DEF (def, insn) + if (REGNO (DF_REF_REG (def)) == REGNO (reg)) + break; + + gcc_assert (def != NULL); + + ref_chain = DF_REF_CHAIN (def); + + for (ref_link = ref_chain; ref_link; ref_link = ref_link->next) + { + /* Problem getting some use for this instruction. */ + if (ref_link->ref == NULL) + return NULL; + if (DF_REF_CLASS (ref_link->ref) != DF_REF_REGULAR) + return NULL; + } + + return ref_chain; +} + /* Return true if INSN is (SET (reg REGNO (def_reg)) (if_then_else (cond) (REG x1) (REG x2))) and store x1 and x2 in REG_1 and REG_2. */ @@ -827,6 +856,24 @@ combine_reaching_defs (ext_cand *cand, c if (reg_overlap_mentioned_p (tmp_reg, SET_DEST (PATTERN (cand->insn)))) return false; + /* We must make sure that changing the mode of SRC_REG as destination + register will not affect its reaching uses, which may read its value + in a larger mode because either 1) DEF_INSN implicitly sets it in + word mode for WORD_REGISTER_OPERATIONS targets or 2) DEF_INSN does + not modify its upper bits for !WORD_REGISTER_OPERATIONS targets. */ + const unsigned int prec + = GET_MODE_PRECISION (GET_MODE (SET_DEST (*dest_sub_rtx))); + if (prec < BITS_PER_WORD) + { + struct df_link *uses = get_uses (def_insn, src_reg); + if (!uses) + return false; + + for (df_link *use = uses; use; use = use->next) + if (GET_MODE_PRECISION (GET_MODE (*DF_REF_LOC (use->ref))) > prec) + return false; + } + /* The destination register of the extension insn must not be used or set between the def_insn and cand->insn exclusive. */ if (reg_used_between_p (SET_DEST (PATTERN (cand->insn)),