re PR rtl-optimization/82628 (wrong code at -Os on x86_64-linux-gnu in the 32-bit...
authorJakub Jelinek <jakub@redhat.com>
Mon, 23 Oct 2017 14:58:23 +0000 (16:58 +0200)
committerJakub Jelinek <jakub@gcc.gnu.org>
Mon, 23 Oct 2017 14:58:23 +0000 (16:58 +0200)
PR target/82628
* config/i386/predicates.md (x86_64_dwzext_immediate_operand): New.
* config/i386/constraints.md (Wf): New constraint.
* config/i386/i386.md (UNSPEC_SBB): New unspec.
(cmp<dwi>_doubleword): Removed.
(sub<mode>3_carry_ccc, *sub<mode>3_carry_ccc_1): New patterns.
(sub<mode>3_carry_ccgz): Use unspec instead of compare.
* config/i386/i386.c (ix86_expand_branch) <case E_TImode>: Don't
expand with cmp<dwi>_doubleword.  For LTU and GEU use
sub<mode>3_carry_ccc instead of sub<mode>3_carry_ccgz and use CCCmode.

From-SVN: r254011

gcc/ChangeLog
gcc/config/i386/constraints.md
gcc/config/i386/i386.c
gcc/config/i386/i386.md
gcc/config/i386/predicates.md

index 5a458a27cd4e8a5dee359a21fb6f41fc84f45602..cc64d7d3a2a2cf2079fd0e82236e92a4916545ac 100644 (file)
@@ -1,5 +1,16 @@
 2017-10-23  Jakub Jelinek  <jakub@redhat.com>
 
+       PR target/82628
+       * config/i386/predicates.md (x86_64_dwzext_immediate_operand): New.
+       * config/i386/constraints.md (Wf): New constraint.
+       * config/i386/i386.md (UNSPEC_SBB): New unspec.
+       (cmp<dwi>_doubleword): Removed.
+       (sub<mode>3_carry_ccc, *sub<mode>3_carry_ccc_1): New patterns.
+       (sub<mode>3_carry_ccgz): Use unspec instead of compare.
+       * config/i386/i386.c (ix86_expand_branch) <case E_TImode>: Don't
+       expand with cmp<dwi>_doubleword.  For LTU and GEU use
+       sub<mode>3_carry_ccc instead of sub<mode>3_carry_ccgz and use CCCmode.
+
        * common.opt (gcolumn-info): Enable by default.
        * doc/invoke.texi (gcolumn-info): Document new default.
 
index 98c05c9ebabfb2aac782d87d935ffa8b1b89156d..619b465f0597d3c259c9eb8505af094512fc4ba6 100644 (file)
    of it satisfies the e constraint."
   (match_operand 0 "x86_64_hilo_int_operand"))
 
+(define_constraint "Wf"
+  "32-bit signed integer constant zero extended from word size
+   to double word size."
+  (match_operand 0 "x86_64_dwzext_immediate_operand"))
+
 (define_constraint "Z"
   "32-bit unsigned integer constant, or a symbolic reference known
    to fit that range (for immediate operands in zero-extending x86-64
index ff0f6f89f9134640fd98dc50299101cbcff5b1aa..5840a2736850ea6d975a5083dbd29c972197ef93 100644 (file)
@@ -22378,27 +22378,45 @@ ix86_expand_branch (enum rtx_code code, rtx op0, rtx op1, rtx label)
        switch (code)
          {
          case LE: case LEU: case GT: case GTU:
-           std::swap (op0, op1);
+           std::swap (lo[0], lo[1]);
+           std::swap (hi[0], hi[1]);
            code = swap_condition (code);
            /* FALLTHRU */
 
          case LT: case LTU: case GE: case GEU:
            {
-             rtx (*cmp_insn) (rtx, rtx, rtx);
+             rtx (*cmp_insn) (rtx, rtx);
+             rtx (*sbb_insn) (rtx, rtx, rtx);
+             bool uns = (code == LTU || code == GEU);
 
              if (TARGET_64BIT)
-               cmp_insn = gen_cmpti_doubleword;
+               {
+                 cmp_insn = gen_cmpdi_1;
+                 sbb_insn
+                   = uns ? gen_subdi3_carry_ccc : gen_subdi3_carry_ccgz;
+               }
              else
-               cmp_insn = gen_cmpdi_doubleword;
+               {
+                 cmp_insn = gen_cmpsi_1;
+                 sbb_insn
+                   = uns ? gen_subsi3_carry_ccc : gen_subsi3_carry_ccgz;
+               }
+
+             if (!nonimmediate_operand (lo[0], submode))
+               lo[0] = force_reg (submode, lo[0]);
+             if (!x86_64_general_operand (lo[1], submode))
+               lo[1] = force_reg (submode, lo[1]);
 
-             if (!register_operand (op0, mode))
-               op0 = force_reg (mode, op0);
-             if (!x86_64_hilo_general_operand (op1, mode))
-               op1 = force_reg (mode, op1);
+             if (!register_operand (hi[0], submode))
+               hi[0] = force_reg (submode, hi[0]);
+             if ((uns && !nonimmediate_operand (hi[1], submode))
+                 || (!uns && !x86_64_general_operand (hi[1], submode)))
+               hi[1] = force_reg (submode, hi[1]);
 
-             emit_insn (cmp_insn (gen_rtx_SCRATCH (mode), op0, op1));
+             emit_insn (cmp_insn (lo[0], lo[1]));
+             emit_insn (sbb_insn (gen_rtx_SCRATCH (submode), hi[0], hi[1]));
 
-             tmp = gen_rtx_REG (CCGZmode, FLAGS_REG);
+             tmp = gen_rtx_REG (uns ? CCCmode : CCGZmode, FLAGS_REG);
 
              ix86_expand_branch (code, tmp, const0_rtx, label);
              return;
index 1fc4a38b82c2b5897585e702ac1e0864cb848e2c..57d258298aa919be0cd557375f3cc509313a875c 100644 (file)
   UNSPEC_STOS
   UNSPEC_PEEPSIB
   UNSPEC_INSN_FALSE_DEP
+  UNSPEC_SBB
 
   ;; For SSE/MMX support:
   UNSPEC_FIX_NOTRUNC
        (compare:CC (match_operand:SWI48 0 "nonimmediate_operand")
                    (match_operand:SWI48 1 "<general_operand>")))])
 
-(define_insn_and_split "cmp<dwi>_doubleword"
-  [(set (reg:CCGZ FLAGS_REG)
-       (compare:CCGZ
-         (match_operand:<DWI> 1 "register_operand" "0")
-         (match_operand:<DWI> 2 "x86_64_hilo_general_operand" "ro<di>")))
-   (clobber (match_scratch:<DWI> 0 "=r"))]
-  ""
-  "#"
-  "reload_completed"
-  [(set (reg:CC FLAGS_REG)
-       (compare:CC (match_dup 1) (match_dup 2)))
-   (parallel [(set (reg:CCGZ FLAGS_REG)
-                  (compare: CCGZ
-                    (match_dup 4)
-                    (plus:DWIH
-                      (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0))
-                      (match_dup 5))))
-             (clobber (match_dup 3))])]
-  "split_double_mode (<DWI>mode, &operands[0], 3, &operands[0], &operands[3]);")
-
 (define_insn "*cmp<mode>_ccno_1"
   [(set (reg FLAGS_REG)
        (compare (match_operand:SWI 0 "nonimmediate_operand" "<r>,?m<r>")
    (set_attr "pent_pair" "pu")
    (set_attr "mode" "SI")])
 
-(define_insn "*sub<mode>3_carry_ccgz"
+(define_insn "sub<mode>3_carry_ccc"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+         (zero_extend:<DWI> (match_operand:DWIH 1 "register_operand" "0"))
+         (plus:<DWI>
+           (ltu:<DWI> (reg:CC FLAGS_REG) (const_int 0))
+           (zero_extend:<DWI>
+             (match_operand:DWIH 2 "x86_64_sext_operand" "rmWe")))))
+   (clobber (match_scratch:DWIH 0 "=r"))]
+  ""
+  "sbb{<imodesuffix>}\t{%2, %0|%0, %2}"
+  [(set_attr "type" "alu")
+   (set_attr "mode" "<MODE>")])
+
+(define_insn "*sub<mode>3_carry_ccc_1"
+  [(set (reg:CCC FLAGS_REG)
+       (compare:CCC
+         (zero_extend:<DWI> (match_operand:DWIH 1 "register_operand" "0"))
+         (plus:<DWI>
+           (ltu:<DWI> (reg:CC FLAGS_REG) (const_int 0))
+           (match_operand:<DWI> 2 "x86_64_dwzext_immediate_operand" "Wf"))))
+   (clobber (match_scratch:DWIH 0 "=r"))]
+  ""
+{
+  operands[3] = simplify_subreg (<MODE>mode, operands[2], <DWI>mode, 0);
+  return "sbb{<imodesuffix>}\t{%3, %0|%0, %3}";
+}
+  [(set_attr "type" "alu")
+   (set_attr "mode" "<MODE>")])
+
+;; The sign flag is set from the
+;; (compare (match_dup 1) (plus:DWIH (ltu:DWIH ...) (match_dup 2)))
+;; result, the overflow flag likewise, but the overflow flag is also
+;; set if the (plus:DWIH (ltu:DWIH ...) (match_dup 2)) overflows.
+(define_insn "sub<mode>3_carry_ccgz"
   [(set (reg:CCGZ FLAGS_REG)
-       (compare:CCGZ
-         (match_operand:DWIH 1 "register_operand" "0")
-         (plus:DWIH
-           (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0))
-           (match_operand:DWIH 2 "x86_64_general_operand" "rme"))))
+       (unspec:CCGZ [(match_operand:DWIH 1 "register_operand" "0")
+                     (match_operand:DWIH 2 "x86_64_general_operand" "rme")
+                     (ltu:DWIH (reg:CC FLAGS_REG) (const_int 0))]
+                    UNSPEC_SBB))
    (clobber (match_scratch:DWIH 0 "=r"))]
   ""
   "sbb{<imodesuffix>}\t{%2, %0|%0, %2}"
index 4f3f1560f458e6837b6dbb6c8bba788dbf46c22f..c46dd5c83e324e110d9d7867e1a79814351e54f4 100644 (file)
     }
 })
 
+;; Return true if VALUE is a constant integer whose value is
+;; x86_64_immediate_operand value zero extended from word mode to mode.
+(define_predicate "x86_64_dwzext_immediate_operand"
+  (match_code "const_int,const_wide_int")
+{
+  switch (GET_CODE (op))
+    {
+    case CONST_INT:
+      if (!TARGET_64BIT)
+       return UINTVAL (op) <= HOST_WIDE_INT_UC (0xffffffff);
+      return UINTVAL (op) <= HOST_WIDE_INT_UC (0x7fffffff);
+
+    case CONST_WIDE_INT:
+      if (!TARGET_64BIT)
+       return false;
+      return (CONST_WIDE_INT_NUNITS (op) == 2
+             && CONST_WIDE_INT_ELT (op, 1) == 0
+             && (trunc_int_for_mode (CONST_WIDE_INT_ELT (op, 0), SImode)
+                 == (HOST_WIDE_INT) CONST_WIDE_INT_ELT (op, 0)));
+
+    default:
+      gcc_unreachable ();
+    }
+})
+
 ;; Return true if size of VALUE can be stored in a sign
 ;; extended immediate field.
 (define_predicate "x86_64_immediate_size_operand"