https://gcc.gnu.org/bugzilla/show_bug.cgi?id=121306
--- Comment #11 from GCC Commits <cvs-commit at gcc dot gnu.org> --- The trunk branch has been updated by Richard Sandiford <rsand...@gcc.gnu.org>: https://gcc.gnu.org/g:5305f84c3be3de9397907dfaf151477579d91c77 commit r16-2789-g5305f84c3be3de9397907dfaf151477579d91c77 Author: Richard Sandiford <richard.sandif...@arm.com> Date: Tue Aug 5 14:42:34 2025 +0100 i386: Extend recognition of high-reg rvalues [PR121306] The i386 high-register patterns used things like: (match_operator:SWI248 2 "extract_operator" [(match_operand 0 "int248_register_operand" "Q") (const_int 8) (const_int 8)]) to match an extraction of a high register such as AH from AX/EAX/RAX. This construct is used in contexts where only the low 8 bits of the value matter. This is either done explicitly using a (subreg:QI ... 0) or implicitly by assigning to an 8-bit zero_extract destination. extract_operator therefore matches both sign_extract and zero_extract, since the signedness of the extension beyond 8 bits is irrelevant. But the fact that only the low 8 bits of the value are significant means that a shift right by 8 is as good as an extraction. Shifts right would already be used for things like: struct s { long a:8; long b:8; long c:48; }; struct s f(struct s x, long y, long z) { x.b = (y & z) >> 8; return x; } but are used more after g:965564eafb721f8000013a3112f1bba8d8fae32b. This patch therefore replaces extract_operator with a new predicate called extract_high_operator that matches both extractions and shifts. The predicate checks the extraction field and shift amount itself, so that patterns only need to match the first operand. Splitters used match_op_dup to preserve the choice of extraction. But the fact that the extractions (and now shifts) are equivalent means that we can just as easily canonicalise on one of them. (In theory, canonicalisation would also promote CSE, although that's unlikely in practice.) The patch goes for zero_extract, for consistency with destinations. gcc/ PR target/121306 * config/i386/predicates.md (extract_operator): Replace with... (extract_high_operator): ...this new predicate. * config/i386/i386.md (*cmpqi_ext<mode>_1, *cmpqi_ext<mode>_2) (*cmpqi_ext<mode>_3, *cmpqi_ext<mode>_4, *movstrictqi_ext<mode>_1) (*extzv<mode>, *insvqi_2, *extendqi<SWI24:mode>_ext_1) (*addqi_ext<mode>_1_slp, *addqi_ext<mode>_1_slp, *addqi_ext<mode>_0) (*addqi_ext2<mode>_0, *addqi_ext<mode>_1, *<insn>qi_ext<mode>_2) (*subqi_ext<mode>_1_slp, *subqi_ext<mode>_2_slp, *subqi_ext<mode>_0) (*subqi_ext2<mode>_0, *subqi_ext<mode>_1, *testqi_ext<mode>_1) (*testqi_ext<mode>_2, *<code>qi_ext<mode>_1_slp) (*<code>qi_ext<mode>_2_slp. *<code>qi_ext<mode>_0) (*<code>qi_ext2<mode>_0, *<code>qi_ext<mode>_1) (*<code>qi_ext<mode>_1_cc, *<code>qi_ext<mode>_1_cc) (*<code>qi_ext<mode>_2, *<code>qi_ext<mode>_3, *negqi_ext<mode>_1) (*one_cmplqi_ext<mode>_1, *ashlqi_ext<mode>_1, *<insn>qi_ext<mode>_1) (define_peephole2): Replace uses of extract_operator with extract_high_operator, matching only the first operand. Use zero_extract rather than match_op_dup when splitting.