2018-04-28 Uros Bizjak <ubiz...@gmail.com> PR target/84431 * config/i386/i386.md (*ashl<dwi>3_doubleword_mask): New pattern. (*ashl<dwi>3_doubleword_mask_1): Ditto. (*<shift_insn><dwi>3_doubleword_mask): Ditto. (*<shift_insn><dwi>3_doubleword_mask_1): Ditto.
testsuite/ChangeLog: 2018-04-28 Uros Bizjak <ubiz...@gmail.com> PR target/84431 * gcc.target/i386/pr84431.c: New test. Bootstrapped and regression tested on x86_64-linux-gnu {,-m32}. Committed to mainline SVN. Uros.
Index: config/i386/i386.md =================================================================== --- config/i386/i386.md (revision 259701) +++ config/i386/i386.md (working copy) @@ -10357,6 +10357,77 @@ "" "ix86_expand_binary_operator (ASHIFT, <MODE>mode, operands); DONE;") +(define_insn_and_split "*ashl<dwi>3_doubleword_mask" + [(set (match_operand:<DWI> 0 "register_operand") + (ashift:<DWI> + (match_operand:<DWI> 1 "register_operand") + (subreg:QI + (and:SI + (match_operand:SI 2 "register_operand" "c") + (match_operand:SI 3 "const_int_operand")) 0))) + (clobber (reg:CC FLAGS_REG))] + "INTVAL (operands[3]) <= (<MODE_SIZE> * BITS_PER_UNIT)-1 + && can_create_pseudo_p ()" + "#" + "&& 1" + [(parallel + [(set (match_dup 6) + (ior:DWIH (ashift:DWIH (match_dup 6) (match_dup 2)) + (lshiftrt:DWIH (match_dup 5) + (minus:QI (match_dup 8) (match_dup 2))))) + (clobber (reg:CC FLAGS_REG))]) + (parallel + [(set (match_dup 4) + (ashift:DWIH (match_dup 5) (match_dup 2))) + (clobber (reg:CC FLAGS_REG))])] +{ + split_double_mode (<DWI>mode, &operands[0], 2, &operands[4], &operands[6]); + + operands[8] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT); + + if (INTVAL (operands[3]) < (<MODE_SIZE> * BITS_PER_UNIT)-1) + emit_insn (gen_andsi3 (operands[2], operands[2], operands[3])); + + operands[2] = gen_lowpart (QImode, operands[2]); + + if (!rtx_equal_p (operands[6], operands[7])) + emit_move_insn (operands[6], operands[7]); +}) + +(define_insn_and_split "*ashl<dwi>3_doubleword_mask_1" + [(set (match_operand:<DWI> 0 "register_operand") + (ashift:<DWI> + (match_operand:<DWI> 1 "register_operand") + (and:QI + (match_operand:QI 2 "register_operand" "c") + (match_operand:QI 3 "const_int_operand")))) + (clobber (reg:CC FLAGS_REG))] + "INTVAL (operands[3]) <= (<MODE_SIZE> * BITS_PER_UNIT)-1 + && can_create_pseudo_p ()" + "#" + "&& 1" + [(parallel + [(set (match_dup 6) + (ior:DWIH (ashift:DWIH (match_dup 6) (match_dup 2)) + (lshiftrt:DWIH (match_dup 5) + (minus:QI (match_dup 8) (match_dup 2))))) + (clobber (reg:CC FLAGS_REG))]) + (parallel + [(set (match_dup 4) + (ashift:DWIH (match_dup 5) (match_dup 2))) + (clobber (reg:CC FLAGS_REG))])] +{ + split_double_mode (<DWI>mode, &operands[0], 2, &operands[4], &operands[6]); + + operands[8] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT); + + if (INTVAL (operands[3]) < (<MODE_SIZE> * BITS_PER_UNIT)-1) + emit_insn (gen_andqi3 (operands[2], operands[2], operands[3])); + + if (!rtx_equal_p (operands[6], operands[7])) + emit_move_insn (operands[6], operands[7]); +}) + (define_insn "*ashl<mode>3_doubleword" [(set (match_operand:DWI 0 "register_operand" "=&r") (ashift:DWI (match_operand:DWI 1 "reg_or_pm1_operand" "0n") @@ -11038,6 +11109,77 @@ "" [(set_attr "isa" "*,bmi2")]) +(define_insn_and_split "*<shift_insn><dwi>3_doubleword_mask" + [(set (match_operand:<DWI> 0 "register_operand") + (any_shiftrt:<DWI> + (match_operand:<DWI> 1 "register_operand") + (subreg:QI + (and:SI + (match_operand:SI 2 "register_operand" "c") + (match_operand:SI 3 "const_int_operand")) 0))) + (clobber (reg:CC FLAGS_REG))] + "INTVAL (operands[3]) <= (<MODE_SIZE> * BITS_PER_UNIT)-1 + && can_create_pseudo_p ()" + "#" + "&& 1" + [(parallel + [(set (match_dup 4) + (ior:DWIH (lshiftrt:DWIH (match_dup 4) (match_dup 2)) + (ashift:DWIH (match_dup 7) + (minus:QI (match_dup 8) (match_dup 2))))) + (clobber (reg:CC FLAGS_REG))]) + (parallel + [(set (match_dup 6) + (any_shiftrt:DWIH (match_dup 7) (match_dup 2))) + (clobber (reg:CC FLAGS_REG))])] +{ + split_double_mode (<DWI>mode, &operands[0], 2, &operands[4], &operands[6]); + + operands[8] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT); + + if (INTVAL (operands[3]) < (<MODE_SIZE> * BITS_PER_UNIT)-1) + emit_insn (gen_andsi3 (operands[2], operands[2], operands[3])); + + operands[2] = gen_lowpart (QImode, operands[2]); + + if (!rtx_equal_p (operands[4], operands[5])) + emit_move_insn (operands[4], operands[5]); +}) + +(define_insn_and_split "*<shift_insn><dwi>3_doubleword_mask_1" + [(set (match_operand:<DWI> 0 "register_operand") + (any_shiftrt:<DWI> + (match_operand:<DWI> 1 "register_operand") + (and:QI + (match_operand:QI 2 "register_operand" "c") + (match_operand:QI 3 "const_int_operand")))) + (clobber (reg:CC FLAGS_REG))] + "INTVAL (operands[3]) <= (<MODE_SIZE> * BITS_PER_UNIT)-1 + && can_create_pseudo_p ()" + "#" + "&& 1" + [(parallel + [(set (match_dup 4) + (ior:DWIH (lshiftrt:DWIH (match_dup 4) (match_dup 2)) + (ashift:DWIH (match_dup 7) + (minus:QI (match_dup 8) (match_dup 2))))) + (clobber (reg:CC FLAGS_REG))]) + (parallel + [(set (match_dup 6) + (any_shiftrt:DWIH (match_dup 7) (match_dup 2))) + (clobber (reg:CC FLAGS_REG))])] +{ + split_double_mode (<DWI>mode, &operands[0], 2, &operands[4], &operands[6]); + + operands[8] = GEN_INT (<MODE_SIZE> * BITS_PER_UNIT); + + if (INTVAL (operands[3]) < (<MODE_SIZE> * BITS_PER_UNIT)-1) + emit_insn (gen_andqi3 (operands[2], operands[2], operands[3])); + + if (!rtx_equal_p (operands[4], operands[5])) + emit_move_insn (operands[4], operands[5]); +}) + (define_insn_and_split "*<shift_insn><mode>3_doubleword" [(set (match_operand:DWI 0 "register_operand" "=&r") (any_shiftrt:DWI (match_operand:DWI 1 "register_operand" "0") Index: testsuite/gcc.target/i386/pr84431.c =================================================================== --- testsuite/gcc.target/i386/pr84431.c (nonexistent) +++ testsuite/gcc.target/i386/pr84431.c (working copy) @@ -0,0 +1,19 @@ +/* PR target/84431 */ +/* { dg-do compile } */ +/* { dg-options "-O2" } */ + +#ifdef __SIZEOF_INT128__ +typedef unsigned __int128 U; +typedef signed __int128 S; +# define M 63 +#else +typedef unsigned long long U; +typedef signed long long S; +# define M 31 +#endif + +S f1 (S a, int s) { return a >> (s & M); } +U f2 (U a, int s) { return a >> (s & M); } +U f3 (U a, int s) { return a << (s & M); } + +/* { dg-final { scan-assembler-not "and" } } */