re PR target/82361 (Useless "mov eax, eax" in generated code)
authorJakub Jelinek <jakub@redhat.com>
Sat, 30 Sep 2017 08:10:15 +0000 (10:10 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Sat, 30 Sep 2017 08:10:15 +0000 (10:10 +0200)
PR target/82361
* config/i386/i386.md
(TARGET_USE_8BIT_IDIV zext divmodsi4 splitter): New define_split.
(divmodsi4_zext_1, divmodsi4_zext_2, *divmodsi4_zext_1,
*divmodsi4_zext_2): New define_insn_and_split.
(*divmodsi4_noext_zext_1, *divmodsi4_noext_zext_2): New define_insn.
(TARGET_USE_8BIT_IDIV zext udivmodsi4 splitter): New define_split.
(udivmodsi4_zext_1, udivmodsi4_zext_2, *udivmodsi4_zext_1,
*udivmodsi4_zext_2, *udivmodsi4_pow2_zext_1, *udivmodsi4_pow2_zext_2):
New define_insn_and_split.
(*udivmodsi4_noext_zext_1, *udivmodsi4_noext_zext_2): New define_insn.
* config/i386/i386.c (ix86_split_idivmod): Handle operands[0] or
operands[1] having DImode when mode is SImode.

* gcc.target/i386/pr82361-1.c: New test.
* gcc.target/i386/pr82361-2.c: New test.

From-SVN: r253317

gcc/ChangeLog
gcc/config/i386/i386.c
gcc/config/i386/i386.md
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/i386/pr82361-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/i386/pr82361-2.c [new file with mode: 0644]

index 7cae1deeef859acdf102f6eb9d4e11f7f113ecc8..65cfd80bfafe129007451f55d79e998ff336a8b6 100644 (file)
@@ -1,5 +1,19 @@
 2017-09-30  Jakub Jelinek  <jakub@redhat.com>
 
+       PR target/82361
+       * config/i386/i386.md
+       (TARGET_USE_8BIT_IDIV zext divmodsi4 splitter): New define_split.
+       (divmodsi4_zext_1, divmodsi4_zext_2, *divmodsi4_zext_1,
+       *divmodsi4_zext_2): New define_insn_and_split.
+       (*divmodsi4_noext_zext_1, *divmodsi4_noext_zext_2): New define_insn.
+       (TARGET_USE_8BIT_IDIV zext udivmodsi4 splitter): New define_split.
+       (udivmodsi4_zext_1, udivmodsi4_zext_2, *udivmodsi4_zext_1,
+       *udivmodsi4_zext_2, *udivmodsi4_pow2_zext_1, *udivmodsi4_pow2_zext_2):
+       New define_insn_and_split.
+       (*udivmodsi4_noext_zext_1, *udivmodsi4_noext_zext_2): New define_insn.
+       * config/i386/i386.c (ix86_split_idivmod): Handle operands[0] or
+       operands[1] having DImode when mode is SImode.
+
        * config/i386/i386.c (ix86_split_idivmod): Use mode instead of
        always SImode for DIV and MOD in REG_EQUAL notes.
 
index 4a212153e4b9c207d4a807d07a268ceed9a6239d..519336e0ed18897beb59bba8a0e01807078224c3 100644 (file)
@@ -21927,9 +21927,22 @@ ix86_split_idivmod (machine_mode mode, rtx operands[],
   switch (mode)
     {
     case E_SImode:
-      gen_divmod4_1 = signed_p ? gen_divmodsi4_1 : gen_udivmodsi4_1;
+      if (GET_MODE (operands[0]) == SImode)
+       {
+         if (GET_MODE (operands[1]) == SImode)
+           gen_divmod4_1 = signed_p ? gen_divmodsi4_1 : gen_udivmodsi4_1;
+         else
+           gen_divmod4_1
+             = signed_p ? gen_divmodsi4_zext_2 : gen_udivmodsi4_zext_2;
+         gen_zero_extend = gen_zero_extendqisi2;
+       }
+      else
+       {
+         gen_divmod4_1
+           = signed_p ? gen_divmodsi4_zext_1 : gen_udivmodsi4_zext_1;
+         gen_zero_extend = gen_zero_extendqidi2;
+       }
       gen_test_ccno_1 = gen_testsi_ccno_1;
-      gen_zero_extend = gen_zero_extendqisi2;
       break;
     case E_DImode:
       gen_divmod4_1 = signed_p ? gen_divmoddi4_1 : gen_udivmoddi4_1;
@@ -21988,16 +22001,24 @@ ix86_split_idivmod (machine_mode mode, rtx operands[],
       div = gen_rtx_UDIV (mode, operands[2], operands[3]);
       mod = gen_rtx_UMOD (mode, operands[2], operands[3]);
     }
+  if (mode == SImode)
+    {
+      if (GET_MODE (operands[0]) != SImode)
+       div = gen_rtx_ZERO_EXTEND (DImode, div);
+      if (GET_MODE (operands[1]) != SImode)
+       mod = gen_rtx_ZERO_EXTEND (DImode, mod);
+    }
 
   /* Extract remainder from AH.  */
-  tmp1 = gen_rtx_ZERO_EXTRACT (mode, tmp0, GEN_INT (8), GEN_INT (8));
+  tmp1 = gen_rtx_ZERO_EXTRACT (GET_MODE (operands[1]),
+                              tmp0, GEN_INT (8), GEN_INT (8));
   if (REG_P (operands[1]))
     insn = emit_move_insn (operands[1], tmp1);
   else
     {
       /* Need a new scratch register since the old one has result
         of 8bit divide.  */
-      scratch = gen_reg_rtx (mode);
+      scratch = gen_reg_rtx (GET_MODE (operands[1]));
       emit_move_insn (scratch, tmp1);
       insn = emit_move_insn (operands[1], scratch);
     }
index 8786ee4036af5e1e70d459df04be3b04577f2dd7..99497a9f65425a4a9a9dfc6b935e027a73f733f5 100644 (file)
   [(const_int 0)]
   "ix86_split_idivmod (<MODE>mode, operands, true); DONE;")
 
+(define_split
+  [(set (match_operand:DI 0 "register_operand")
+       (zero_extend:DI
+         (div:SI (match_operand:SI 2 "register_operand")
+                 (match_operand:SI 3 "nonimmediate_operand"))))
+   (set (match_operand:SI 1 "register_operand")
+       (mod:SI (match_dup 2) (match_dup 3)))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_USE_8BIT_IDIV
+   && TARGET_QIMODE_MATH
+   && can_create_pseudo_p ()
+   && !optimize_insn_for_size_p ()"
+  [(const_int 0)]
+  "ix86_split_idivmod (SImode, operands, true); DONE;")
+
+(define_split
+  [(set (match_operand:DI 1 "register_operand")
+       (zero_extend:DI
+         (mod:SI (match_operand:SI 2 "register_operand")
+                 (match_operand:SI 3 "nonimmediate_operand"))))
+   (set (match_operand:SI 0 "register_operand")
+       (div:SI  (match_dup 2) (match_dup 3)))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_USE_8BIT_IDIV
+   && TARGET_QIMODE_MATH
+   && can_create_pseudo_p ()
+   && !optimize_insn_for_size_p ()"
+  [(const_int 0)]
+  "ix86_split_idivmod (SImode, operands, true); DONE;")
+
 (define_insn_and_split "divmod<mode>4_1"
   [(set (match_operand:SWI48 0 "register_operand" "=a")
        (div:SWI48 (match_operand:SWI48 2 "register_operand" "0")
   [(set_attr "type" "multi")
    (set_attr "mode" "<MODE>")])
 
+(define_insn_and_split "divmodsi4_zext_1"
+  [(set (match_operand:DI 0 "register_operand" "=a")
+       (zero_extend:DI
+         (div:SI (match_operand:SI 2 "register_operand" "0")
+                 (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+   (set (match_operand:SI 1 "register_operand" "=&d")
+       (mod:SI (match_dup 2) (match_dup 3)))
+   (unspec [(const_int 0)] UNSPEC_DIV_ALREADY_SPLIT)
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT"
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 1)
+                  (ashiftrt:SI (match_dup 4) (match_dup 5)))
+             (clobber (reg:CC FLAGS_REG))])
+   (parallel [(set (match_dup 0)
+                  (zero_extend:DI (div:SI (match_dup 2) (match_dup 3))))
+             (set (match_dup 1)
+                  (mod:SI (match_dup 2) (match_dup 3)))
+             (use (match_dup 1))
+             (clobber (reg:CC FLAGS_REG))])]
+{
+  operands[5] = GEN_INT (GET_MODE_BITSIZE (SImode)-1);
+
+  if (optimize_function_for_size_p (cfun) || TARGET_USE_CLTD)
+    operands[4] = operands[2];
+  else
+    {
+      /* Avoid use of cltd in favor of a mov+shift.  */
+      emit_move_insn (operands[1], operands[2]);
+      operands[4] = operands[1];
+    }
+}
+  [(set_attr "type" "multi")
+   (set_attr "mode" "SI")])
+
+(define_insn_and_split "divmodsi4_zext_2"
+  [(set (match_operand:DI 1 "register_operand" "=&d")
+       (zero_extend:DI
+         (mod:SI (match_operand:SI 2 "register_operand" "0")
+                 (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+   (set (match_operand:SI 0 "register_operand" "=a")
+       (div:SI (match_dup 2) (match_dup 3)))
+   (unspec [(const_int 0)] UNSPEC_DIV_ALREADY_SPLIT)
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT"
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 6)
+                  (ashiftrt:SI (match_dup 4) (match_dup 5)))
+             (clobber (reg:CC FLAGS_REG))])
+   (parallel [(set (match_dup 1)
+                  (zero_extend:DI (mod:SI (match_dup 2) (match_dup 3))))
+             (set (match_dup 0)
+                  (div:SI (match_dup 2) (match_dup 3)))
+             (use (match_dup 6))
+             (clobber (reg:CC FLAGS_REG))])]
+{
+  operands[5] = GEN_INT (GET_MODE_BITSIZE (SImode)-1);
+  operands[6] = gen_lowpart (SImode, operands[1]);
+
+  if (optimize_function_for_size_p (cfun) || TARGET_USE_CLTD)
+    operands[4] = operands[2];
+  else
+    {
+      /* Avoid use of cltd in favor of a mov+shift.  */
+      emit_move_insn (operands[6], operands[2]);
+      operands[4] = operands[6];
+    }
+}
+  [(set_attr "type" "multi")
+   (set_attr "mode" "SI")])
+
 (define_insn_and_split "*divmod<mode>4"
   [(set (match_operand:SWIM248 0 "register_operand" "=a")
        (div:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
   [(set_attr "type" "multi")
    (set_attr "mode" "<MODE>")])
 
+(define_insn_and_split "*divmodsi4_zext_1"
+  [(set (match_operand:DI 0 "register_operand" "=a")
+       (zero_extend:DI
+         (div:SI (match_operand:SI 2 "register_operand" "0")
+                 (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+   (set (match_operand:SI 1 "register_operand" "=&d")
+       (mod:SI (match_dup 2) (match_dup 3)))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT"
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 1)
+                  (ashiftrt:SI (match_dup 4) (match_dup 5)))
+             (clobber (reg:CC FLAGS_REG))])
+   (parallel [(set (match_dup 0)
+                  (zero_extend:DI (div:SI (match_dup 2) (match_dup 3))))
+             (set (match_dup 1)
+                  (mod:SI (match_dup 2) (match_dup 3)))
+             (use (match_dup 1))
+             (clobber (reg:CC FLAGS_REG))])]
+{
+  operands[5] = GEN_INT (GET_MODE_BITSIZE (SImode)-1);
+
+  if (optimize_function_for_size_p (cfun) || TARGET_USE_CLTD)
+    operands[4] = operands[2];
+  else
+    {
+      /* Avoid use of cltd in favor of a mov+shift.  */
+      emit_move_insn (operands[1], operands[2]);
+      operands[4] = operands[1];
+    }
+}
+  [(set_attr "type" "multi")
+   (set_attr "mode" "SI")])
+
+(define_insn_and_split "*divmodsi4_zext_2"
+  [(set (match_operand:DI 1 "register_operand" "=&d")
+       (zero_extend:DI
+         (mod:SI (match_operand:SI 2 "register_operand" "0")
+                 (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+   (set (match_operand:SI 0 "register_operand" "=a")
+       (div:SI (match_dup 2) (match_dup 3)))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT"
+  "#"
+  "reload_completed"
+  [(parallel [(set (match_dup 6)
+                  (ashiftrt:SI (match_dup 4) (match_dup 5)))
+             (clobber (reg:CC FLAGS_REG))])
+   (parallel [(set (match_dup 1)
+                  (zero_extend:DI (mod:SI (match_dup 2) (match_dup 3))))
+             (set (match_dup 0)
+                  (div:SI (match_dup 2) (match_dup 3)))
+             (use (match_dup 6))
+             (clobber (reg:CC FLAGS_REG))])]
+{
+  operands[5] = GEN_INT (GET_MODE_BITSIZE (SImode)-1);
+  operands[6] = gen_lowpart (SImode, operands[1]);
+
+  if (optimize_function_for_size_p (cfun) || TARGET_USE_CLTD)
+    operands[4] = operands[2];
+  else
+    {
+      /* Avoid use of cltd in favor of a mov+shift.  */
+      emit_move_insn (operands[6], operands[2]);
+      operands[4] = operands[6];
+    }
+}
+  [(set_attr "type" "multi")
+   (set_attr "mode" "SI")])
+
 (define_insn "*divmod<mode>4_noext"
   [(set (match_operand:SWIM248 0 "register_operand" "=a")
        (div:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
   [(set_attr "type" "idiv")
    (set_attr "mode" "<MODE>")])
 
+(define_insn "*divmodsi4_noext_zext_1"
+  [(set (match_operand:DI 0 "register_operand" "=a")
+       (zero_extend:DI
+         (div:SI (match_operand:SI 2 "register_operand" "0")
+                 (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+   (set (match_operand:SI 1 "register_operand" "=d")
+       (mod:SI (match_dup 2) (match_dup 3)))
+   (use (match_operand:SI 4 "register_operand" "1"))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT"
+  "idiv{l}\t%3"
+  [(set_attr "type" "idiv")
+   (set_attr "mode" "SI")])
+
+(define_insn "*divmodsi4_noext_zext_2"
+  [(set (match_operand:DI 1 "register_operand" "=d")
+       (zero_extend:DI
+         (mod:SI (match_operand:SI 2 "register_operand" "0")
+                 (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+   (set (match_operand:SI 0 "register_operand" "=a")
+       (div:SI (match_dup 2) (match_dup 3)))
+   (use (match_operand:SI 4 "register_operand" "1"))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT"
+  "idiv{l}\t%3"
+  [(set_attr "type" "idiv")
+   (set_attr "mode" "SI")])
+
 (define_expand "divmodqi4"
   [(parallel [(set (match_operand:QI 0 "register_operand")
                   (div:QI
   [(const_int 0)]
   "ix86_split_idivmod (<MODE>mode, operands, false); DONE;")
 
+(define_split
+  [(set (match_operand:DI 0 "register_operand")
+       (zero_extend:DI
+         (udiv:SI (match_operand:SI 2 "register_operand")
+                  (match_operand:SI 3 "nonimmediate_operand"))))
+   (set (match_operand:SI 1 "register_operand")
+       (umod:SI (match_dup 2) (match_dup 3)))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT
+   && TARGET_USE_8BIT_IDIV
+   && TARGET_QIMODE_MATH
+   && can_create_pseudo_p ()
+   && !optimize_insn_for_size_p ()"
+  [(const_int 0)]
+  "ix86_split_idivmod (SImode, operands, false); DONE;")
+
+(define_split
+  [(set (match_operand:DI 1 "register_operand")
+       (zero_extend:DI
+         (umod:SI (match_operand:SI 2 "register_operand")
+                  (match_operand:SI 3 "nonimmediate_operand"))))
+   (set (match_operand:SI 0 "register_operand")
+       (udiv:SI (match_dup 2) (match_dup 3)))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT
+   && TARGET_USE_8BIT_IDIV
+   && TARGET_QIMODE_MATH
+   && can_create_pseudo_p ()
+   && !optimize_insn_for_size_p ()"
+  [(const_int 0)]
+  "ix86_split_idivmod (SImode, operands, false); DONE;")
+
 (define_insn_and_split "udivmod<mode>4_1"
   [(set (match_operand:SWI48 0 "register_operand" "=a")
        (udiv:SWI48 (match_operand:SWI48 2 "register_operand" "0")
   [(set_attr "type" "multi")
    (set_attr "mode" "<MODE>")])
 
+(define_insn_and_split "udivmodsi4_zext_1"
+  [(set (match_operand:DI 0 "register_operand" "=a")
+       (zero_extend:DI
+         (udiv:SI (match_operand:SI 2 "register_operand" "0")
+                  (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+   (set (match_operand:SI 1 "register_operand" "=&d")
+       (umod:SI (match_dup 2) (match_dup 3)))
+   (unspec [(const_int 0)] UNSPEC_DIV_ALREADY_SPLIT)
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT"
+  "#"
+  "reload_completed"
+  [(set (match_dup 1) (const_int 0))
+   (parallel [(set (match_dup 0)
+                  (zero_extend:DI (udiv:SI (match_dup 2) (match_dup 3))))
+             (set (match_dup 1)
+                  (umod:SI (match_dup 2) (match_dup 3)))
+             (use (match_dup 1))
+             (clobber (reg:CC FLAGS_REG))])]
+  ""
+  [(set_attr "type" "multi")
+   (set_attr "mode" "SI")])
+
+(define_insn_and_split "udivmodsi4_zext_2"
+  [(set (match_operand:DI 1 "register_operand" "=&d")
+       (zero_extend:DI
+         (umod:SI (match_operand:SI 2 "register_operand" "0")
+                (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+   (set (match_operand:SI 0 "register_operand" "=a")
+       (udiv:SI (match_dup 2) (match_dup 3)))
+   (unspec [(const_int 0)] UNSPEC_DIV_ALREADY_SPLIT)
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT"
+  "#"
+  "reload_completed"
+  [(set (match_dup 4) (const_int 0))
+   (parallel [(set (match_dup 1)
+                  (zero_extend:DI (umod:SI (match_dup 2) (match_dup 3))))
+             (set (match_dup 0)
+                  (udiv:SI (match_dup 2) (match_dup 3)))
+             (use (match_dup 4))
+             (clobber (reg:CC FLAGS_REG))])]
+  "operands[4] = gen_lowpart (SImode, operands[1]);"
+  [(set_attr "type" "multi")
+   (set_attr "mode" "SI")])
+
 (define_insn_and_split "*udivmod<mode>4"
   [(set (match_operand:SWIM248 0 "register_operand" "=a")
        (udiv:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
   [(set_attr "type" "multi")
    (set_attr "mode" "<MODE>")])
 
+(define_insn_and_split "*udivmodsi4_zext_1"
+  [(set (match_operand:DI 0 "register_operand" "=a")
+       (zero_extend:DI
+         (udiv:SI (match_operand:SI 2 "register_operand" "0")
+                  (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+   (set (match_operand:SI 1 "register_operand" "=&d")
+       (umod:SI (match_dup 2) (match_dup 3)))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT"
+  "#"
+  "reload_completed"
+  [(set (match_dup 1) (const_int 0))
+   (parallel [(set (match_dup 0)
+                  (zero_extend:DI (udiv:SI (match_dup 2) (match_dup 3))))
+             (set (match_dup 1)
+                  (umod:SI (match_dup 2) (match_dup 3)))
+             (use (match_dup 1))
+             (clobber (reg:CC FLAGS_REG))])]
+  ""
+  [(set_attr "type" "multi")
+   (set_attr "mode" "SI")])
+
+(define_insn_and_split "*udivmodsi4_zext_2"
+  [(set (match_operand:DI 1 "register_operand" "=&d")
+       (zero_extend:DI
+         (umod:SI (match_operand:SI 2 "register_operand" "0")
+                  (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+   (set (match_operand:SI 0 "register_operand" "=a")
+       (udiv:SI (match_dup 2) (match_dup 3)))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT"
+  "#"
+  "reload_completed"
+  [(set (match_dup 4) (const_int 0))
+   (parallel [(set (match_dup 1)
+                  (zero_extend:DI (umod:SI (match_dup 2) (match_dup 3))))
+             (set (match_dup 0)
+                  (udiv:SI (match_dup 2) (match_dup 3)))
+             (use (match_dup 4))
+             (clobber (reg:CC FLAGS_REG))])]
+  "operands[4] = gen_lowpart (SImode, operands[1]);"
+  [(set_attr "type" "multi")
+   (set_attr "mode" "SI")])
+
 ;; Optimize division or modulo by constant power of 2, if the constant
 ;; materializes only after expansion.
 (define_insn_and_split "*udivmod<mode>4_pow2"
   [(set_attr "type" "multi")
    (set_attr "mode" "<MODE>")])
 
+(define_insn_and_split "*udivmodsi4_pow2_zext_1"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (zero_extend:DI
+         (udiv:SI (match_operand:SI 2 "register_operand" "0")
+                  (match_operand:SI 3 "const_int_operand" "n"))))
+   (set (match_operand:SI 1 "register_operand" "=r")
+       (umod:SI (match_dup 2) (match_dup 3)))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT
+   && IN_RANGE (INTVAL (operands[3]), 2, HOST_WIDE_INT_UC (0x80000000))
+   && (UINTVAL (operands[3]) & (UINTVAL (operands[3]) - 1)) == 0"
+  "#"
+  "&& 1"
+  [(set (match_dup 1) (match_dup 2))
+   (parallel [(set (match_dup 0)
+                  (zero_extend:DI (lshiftrt:SI (match_dup 2) (match_dup 4))))
+             (clobber (reg:CC FLAGS_REG))])
+   (parallel [(set (match_dup 1) (and:SI (match_dup 1) (match_dup 5)))
+             (clobber (reg:CC FLAGS_REG))])]
+{
+  int v = exact_log2 (UINTVAL (operands[3]));
+  operands[4] = GEN_INT (v);
+  operands[5] = GEN_INT ((HOST_WIDE_INT_1U << v) - 1);
+}
+  [(set_attr "type" "multi")
+   (set_attr "mode" "SI")])
+
+(define_insn_and_split "*udivmodsi4_pow2_zext_2"
+  [(set (match_operand:DI 1 "register_operand" "=r")
+       (zero_extend:DI
+         (umod:SI (match_operand:SI 2 "register_operand" "0")
+                  (match_operand:SI 3 "const_int_operand" "n"))))
+   (set (match_operand:SI 0 "register_operand" "=r")
+       (umod:SI (match_dup 2) (match_dup 3)))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT
+   && IN_RANGE (INTVAL (operands[3]), 2, HOST_WIDE_INT_UC (0x80000000))
+   && (UINTVAL (operands[3]) & (UINTVAL (operands[3]) - 1)) == 0"
+  "#"
+  "&& 1"
+  [(set (match_dup 1) (match_dup 2))
+   (parallel [(set (match_dup 0) (lshiftrt:SI (match_dup 2) (match_dup 4)))
+             (clobber (reg:CC FLAGS_REG))])
+   (parallel [(set (match_dup 1)
+                  (zero_extend:DI (and:SI (match_dup 1) (match_dup 5))))
+             (clobber (reg:CC FLAGS_REG))])]
+{
+  int v = exact_log2 (UINTVAL (operands[3]));
+  operands[4] = GEN_INT (v);
+  operands[5] = GEN_INT ((HOST_WIDE_INT_1U << v) - 1);
+}
+  [(set_attr "type" "multi")
+   (set_attr "mode" "SI")])
+
 (define_insn "*udivmod<mode>4_noext"
   [(set (match_operand:SWIM248 0 "register_operand" "=a")
        (udiv:SWIM248 (match_operand:SWIM248 2 "register_operand" "0")
   [(set_attr "type" "idiv")
    (set_attr "mode" "<MODE>")])
 
+(define_insn "*udivmodsi4_noext_zext_1"
+  [(set (match_operand:DI 0 "register_operand" "=a")
+       (zero_extend:DI
+         (udiv:SI (match_operand:SI 2 "register_operand" "0")
+                  (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+   (set (match_operand:SI 1 "register_operand" "=d")
+       (umod:SI (match_dup 2) (match_dup 3)))
+   (use (match_operand:SI 4 "register_operand" "1"))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT"
+  "div{l}\t%3"
+  [(set_attr "type" "idiv")
+   (set_attr "mode" "SI")])
+
+(define_insn "*udivmodsi4_noext_zext_2"
+  [(set (match_operand:DI 1 "register_operand" "=d")
+       (zero_extend:DI
+         (umod:SI (match_operand:SI 2 "register_operand" "0")
+                  (match_operand:SI 3 "nonimmediate_operand" "rm"))))
+   (set (match_operand:SI 0 "register_operand" "=a")
+       (udiv:SI (match_dup 2) (match_dup 3)))
+   (use (match_operand:SI 4 "register_operand" "1"))
+   (clobber (reg:CC FLAGS_REG))]
+  "TARGET_64BIT"
+  "div{l}\t%3"
+  [(set_attr "type" "idiv")
+   (set_attr "mode" "SI")])
+
 (define_expand "udivmodqi4"
   [(parallel [(set (match_operand:QI 0 "register_operand")
                   (udiv:QI
index e5c660058080600229fde389bb9f41c6ffbf8fdf..ebcfb1b518179f039d5734ccfcb0abfa0ce88ca8 100644 (file)
@@ -1,3 +1,9 @@
+2017-09-30  Jakub Jelinek  <jakub@redhat.com>
+
+       PR target/82361
+       * gcc.target/i386/pr82361-1.c: New test.
+       * gcc.target/i386/pr82361-2.c: New test.
+
 2017-09-29  Yury Gribov  <tetra2005@gmail.com>
 
        PR middle-end/82319
diff --git a/gcc/testsuite/gcc.target/i386/pr82361-1.c b/gcc/testsuite/gcc.target/i386/pr82361-1.c
new file mode 100644 (file)
index 0000000..fbef3c9
--- /dev/null
@@ -0,0 +1,53 @@
+/* PR target/82361 */
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-O2 -mtune=generic -masm=att -mno-8bit-idiv" } */
+/* We should be able to optimize all %eax to %rax zero extensions, because
+   div and idiv instructions with 32-bit operands zero-extend both results.   */
+/* { dg-final { scan-assembler-not "movl\t%eax, %eax" } } */
+/* FIXME: We are still not able to optimize the modulo in f1/f2, only manage
+   one.  */
+/* { dg-final { scan-assembler-times "movl\t%edx, %edx" 2 } } */
+
+void
+f1 (unsigned int a, unsigned int b)
+{
+  unsigned long long c = a / b;
+  unsigned long long d = a % b;
+  asm volatile ("" : : "r" (c), "r" (d));
+}
+
+void
+f2 (int a, int b)
+{
+  unsigned long long c = (unsigned int) (a / b);
+  unsigned long long d = (unsigned int) (a % b);
+  asm volatile ("" : : "r" (c), "r" (d));
+}
+
+void
+f3 (unsigned int a, unsigned int b)
+{
+  unsigned long long c = a / b;
+  asm volatile ("" : : "r" (c));
+}
+
+void
+f4 (int a, int b)
+{
+  unsigned long long c = (unsigned int) (a / b);
+  asm volatile ("" : : "r" (c));
+}
+
+void
+f5 (unsigned int a, unsigned int b)
+{
+  unsigned long long d = a % b;
+  asm volatile ("" : : "r" (d));
+}
+
+void
+f6 (int a, int b)
+{
+  unsigned long long d = (unsigned int) (a % b);
+  asm volatile ("" : : "r" (d));
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr82361-2.c b/gcc/testsuite/gcc.target/i386/pr82361-2.c
new file mode 100644 (file)
index 0000000..c1e484d
--- /dev/null
@@ -0,0 +1,10 @@
+/* PR target/82361 */
+/* { dg-do compile { target lp64 } } */
+/* { dg-options "-O2 -mtune=generic -masm=att -m8bit-idiv" } */
+/* We should be able to optimize all %eax to %rax zero extensions, because
+   div and idiv instructions with 32-bit operands zero-extend both results.   */
+/* { dg-final { scan-assembler-not "movl\t%eax, %eax" } } */
+/* Ditto %edx to %rdx zero extensions.  */
+/* { dg-final { scan-assembler-not "movl\t%edx, %edx" } } */
+
+#include "pr82361-1.c"