i386: Disallow address spaces with string insns
authorRichard Henderson <rth@redhat.com>
Mon, 9 Nov 2015 09:19:59 +0000 (01:19 -0800)
committerRichard Henderson <rth@gcc.gnu.org>
Mon, 9 Nov 2015 09:19:59 +0000 (01:19 -0800)
While cmps and movs allow a segment override of the ds:esi
source, the es:edi source/destination cannot be overriden.
Simplify things in the backend for now by disallowing
segments for string insns entirely.

* config/i386/i386.c (ix86_check_no_addr_space): New.
(decide_alg): Add have_as parameter.
(alg_usable_p): Likewise; disable rep algorithms if set.
(ix86_expand_set_or_movmem): Notice if either MEM has a
non-default address space.
(ix86_expand_strlen): Likewise.
* config/i386/i386.md (strmov, strset): Likewise.
(*strmovdi_rex_1): Use ix86_check_no_addr_space.
(*strmovsi_1, *strmovqi_1, *rep_movdi_rex64, *rep_movsi, *rep_movqi,
*strsetdi_rex_1, *strsetsi_1, *strsethi_1, *strsetqi_1,
*rep_stosdi_rex64, *rep_stossi, *rep_stosqi, *cmpstrnqi_nz_1,
*cmpstrnqi_1, *strlenqi_1): Likewise.

From-SVN: r230002

gcc/ChangeLog
gcc/config/i386/i386-protos.h
gcc/config/i386/i386.c
gcc/config/i386/i386.md

index 15b3159af5ab2a30e0f3715dcf9993a82c0b091b..c7e5728d29ff3ba1d3b9ded662d35e9905c2896f 100644 (file)
@@ -1,5 +1,18 @@
 2015-11-09  Richard Henderson  <rth@redhat.com>
 
+       * config/i386/i386.c (ix86_check_no_addr_space): New.
+       (decide_alg): Add have_as parameter.
+       (alg_usable_p): Likewise; disable rep algorithms if set.
+       (ix86_expand_set_or_movmem): Notice if either MEM has a
+       non-default address space.
+       (ix86_expand_strlen): Likewise.
+       * config/i386/i386.md (strmov, strset): Likewise.
+       (*strmovdi_rex_1): Use ix86_check_no_addr_space.
+       (*strmovsi_1, *strmovqi_1, *rep_movdi_rex64, *rep_movsi, *rep_movqi,
+       *strsetdi_rex_1, *strsetsi_1, *strsethi_1, *strsetqi_1,
+       *rep_stosdi_rex64, *rep_stossi, *rep_stosqi, *cmpstrnqi_nz_1,
+       *cmpstrnqi_1, *strlenqi_1): Likewise.
+
        * config/i386/i386.md (*movabs<mode>_1): Print the full memory rtx.
        (*movabs<mode>_2): Likewise.
 
index 6a17ef40a2e707a93a903787e07f3d8ed58038be..5e46833ff3a82d46c52f50ebfc7c0514afa0e397 100644 (file)
@@ -141,6 +141,7 @@ extern void ix86_split_ashr (rtx *, rtx, machine_mode);
 extern void ix86_split_lshr (rtx *, rtx, machine_mode);
 extern rtx ix86_find_base_term (rtx);
 extern bool ix86_check_movabs (rtx, int);
+extern bool ix86_check_no_addr_space (rtx);
 extern void ix86_split_idivmod (machine_mode, rtx[], bool);
 
 extern rtx assign_386_stack_local (machine_mode, enum ix86_stack_slot);
index bb37abaf119abfe10457e8c5309a29d7cbbda651..159e1d19a10ba7de81a6bb4155e35af0d958505b 100644 (file)
@@ -10538,6 +10538,20 @@ ix86_check_movabs (rtx insn, int opnum)
   gcc_assert (MEM_P (mem));
   return volatile_ok || !MEM_VOLATILE_P (mem);
 }
+
+/* Return false if INSN contains a MEM with a non-default address space.  */
+bool
+ix86_check_no_addr_space (rtx insn)
+{
+  subrtx_var_iterator::array_type array;
+  FOR_EACH_SUBRTX_VAR (iter, array, PATTERN (insn), ALL)
+    {
+      rtx x = *iter;
+      if (MEM_P (x) && !ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x)))
+       return false;
+    }
+  return true;
+}
 \f
 /* Initialize the table of extra 80387 mathematical constants.  */
 
@@ -25665,7 +25679,7 @@ expand_set_or_movmem_constant_prologue (rtx dst, rtx *srcp, rtx destreg,
 /* Return true if ALG can be used in current context.  
    Assume we expand memset if MEMSET is true.  */
 static bool
-alg_usable_p (enum stringop_alg alg, bool memset)
+alg_usable_p (enum stringop_alg alg, bool memset, bool have_as)
 {
   if (alg == no_stringop)
     return false;
@@ -25674,12 +25688,19 @@ alg_usable_p (enum stringop_alg alg, bool memset)
   /* Algorithms using the rep prefix want at least edi and ecx;
      additionally, memset wants eax and memcpy wants esi.  Don't
      consider such algorithms if the user has appropriated those
-     registers for their own purposes. */
+     registers for their own purposes, or if we have a non-default
+     address space, since some string insns cannot override the segment.  */
   if (alg == rep_prefix_1_byte
       || alg == rep_prefix_4_byte
       || alg == rep_prefix_8_byte)
-    return !(fixed_regs[CX_REG] || fixed_regs[DI_REG]
-             || (memset ? fixed_regs[AX_REG] : fixed_regs[SI_REG]));
+    {
+      if (have_as)
+       return false;
+      if (fixed_regs[CX_REG]
+         || fixed_regs[DI_REG]
+         || (memset ? fixed_regs[AX_REG] : fixed_regs[SI_REG]))
+       return false;
+    }
   return true;
 }
 
@@ -25687,7 +25708,8 @@ alg_usable_p (enum stringop_alg alg, bool memset)
 static enum stringop_alg
 decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size,
            unsigned HOST_WIDE_INT min_size, unsigned HOST_WIDE_INT max_size,
-           bool memset, bool zero_memset, int *dynamic_check, bool *noalign)
+           bool memset, bool zero_memset, bool have_as,
+           int *dynamic_check, bool *noalign)
 {
   const struct stringop_algs * algs;
   bool optimize_for_speed;
@@ -25719,7 +25741,7 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size,
   for (i = 0; i < MAX_STRINGOP_ALGS; i++)
     {
       enum stringop_alg candidate = algs->size[i].alg;
-      bool usable = alg_usable_p (candidate, memset);
+      bool usable = alg_usable_p (candidate, memset, have_as);
       any_alg_usable_p |= usable;
 
       if (candidate != libcall && candidate && usable)
@@ -25735,17 +25757,17 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size,
 
   /* If user specified the algorithm, honnor it if possible.  */
   if (ix86_stringop_alg != no_stringop
-      && alg_usable_p (ix86_stringop_alg, memset))
+      && alg_usable_p (ix86_stringop_alg, memset, have_as))
     return ix86_stringop_alg;
   /* rep; movq or rep; movl is the smallest variant.  */
   else if (!optimize_for_speed)
     {
       *noalign = true;
       if (!count || (count & 3) || (memset && !zero_memset))
-       return alg_usable_p (rep_prefix_1_byte, memset)
+       return alg_usable_p (rep_prefix_1_byte, memset, have_as)
               ? rep_prefix_1_byte : loop_1_byte;
       else
-       return alg_usable_p (rep_prefix_4_byte, memset)
+       return alg_usable_p (rep_prefix_4_byte, memset, have_as)
               ? rep_prefix_4_byte : loop;
     }
   /* Very tiny blocks are best handled via the loop, REP is expensive to
@@ -25768,7 +25790,8 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size,
            {
              enum stringop_alg candidate = algs->size[i].alg;
 
-             if (candidate != libcall && alg_usable_p (candidate, memset))
+             if (candidate != libcall
+                 && alg_usable_p (candidate, memset, have_as))
                {
                  alg = candidate;
                  alg_noalign = algs->size[i].noalign;
@@ -25788,7 +25811,7 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size,
                  else if (!any_alg_usable_p)
                    break;
                }
-             else if (alg_usable_p (candidate, memset))
+             else if (alg_usable_p (candidate, memset, have_as))
                {
                  *noalign = algs->size[i].noalign;
                  return candidate;
@@ -25805,7 +25828,7 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size,
      choice in ix86_costs.  */
   if ((TARGET_INLINE_ALL_STRINGOPS || TARGET_INLINE_STRINGOPS_DYNAMICALLY)
       && (algs->unknown_size == libcall
-         || !alg_usable_p (algs->unknown_size, memset)))
+         || !alg_usable_p (algs->unknown_size, memset, have_as)))
     {
       enum stringop_alg alg;
 
@@ -25822,7 +25845,7 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size,
       if (max <= 0)
        max = 4096;
       alg = decide_alg (count, max / 2, min_size, max_size, memset,
-                       zero_memset, dynamic_check, noalign);
+                       zero_memset, have_as, dynamic_check, noalign);
       gcc_assert (*dynamic_check == -1);
       if (TARGET_INLINE_STRINGOPS_DYNAMICALLY)
        *dynamic_check = max;
@@ -25830,7 +25853,7 @@ decide_alg (HOST_WIDE_INT count, HOST_WIDE_INT expected_size,
        gcc_assert (alg != libcall);
       return alg;
     }
-  return (alg_usable_p (algs->unknown_size, memset)
+  return (alg_usable_p (algs->unknown_size, memset, have_as)
          ? algs->unknown_size : libcall);
 }
 
@@ -26036,6 +26059,7 @@ ix86_expand_set_or_movmem (rtx dst, rtx src, rtx count_exp, rtx val_exp,
   unsigned HOST_WIDE_INT max_size = -1;
   unsigned HOST_WIDE_INT probable_max_size = -1;
   bool misaligned_prologue_used = false;
+  bool have_as;
 
   if (CONST_INT_P (align_exp))
     align = INTVAL (align_exp);
@@ -26073,11 +26097,15 @@ ix86_expand_set_or_movmem (rtx dst, rtx src, rtx count_exp, rtx val_exp,
   if (count > (HOST_WIDE_INT_1U << 30))
     return false;
 
+  have_as = !ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (dst));
+  if (!issetmem)
+    have_as |= !ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (src));
+
   /* Step 0: Decide on preferred algorithm, desired alignment and
      size of chunks to be copied by main loop.  */
   alg = decide_alg (count, expected_size, min_size, probable_max_size,
                    issetmem,
-                   issetmem && val_exp == const0_rtx,
+                   issetmem && val_exp == const0_rtx, have_as,
                    &dynamic_check, &noalign);
   if (alg == libcall)
     return false;
@@ -26691,6 +26719,9 @@ ix86_expand_strlen (rtx out, rtx src, rtx eoschar, rtx align)
       /* Can't use this if the user has appropriated eax, ecx, or edi.  */
       if (fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])
         return false;
+      /* Can't use this for non-default address spaces.  */
+      if (!ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (src)))
+       return false;
 
       scratch2 = gen_reg_rtx (Pmode);
       scratch3 = gen_reg_rtx (Pmode);
index ccb672d84914d4c1431fc83f4bd082d5531473cd..2cb94fec34ee3d0fead945dd920752865a7af0a0 100644 (file)
              (clobber (reg:CC FLAGS_REG))])]
   ""
 {
+  /* Can't use this for non-default address spaces.  */
+  if (!ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (operands[3])))
+    FAIL;
+
   rtx adjust = GEN_INT (GET_MODE_SIZE (GET_MODE (operands[1])));
 
   /* If .md ever supports :P for Pmode, these can be directly
        (plus:P (match_dup 3)
                (const_int 8)))]
   "TARGET_64BIT
-   && !(fixed_regs[SI_REG] || fixed_regs[DI_REG])"
+   && !(fixed_regs[SI_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^movsq"
   [(set_attr "type" "str")
    (set_attr "memory" "both")
    (set (match_operand:P 1 "register_operand" "=S")
        (plus:P (match_dup 3)
                (const_int 4)))]
-  "!(fixed_regs[SI_REG] || fixed_regs[DI_REG])"
+  "!(fixed_regs[SI_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^movs{l|d}"
   [(set_attr "type" "str")
    (set_attr "memory" "both")
    (set (match_operand:P 1 "register_operand" "=S")
        (plus:P (match_dup 3)
                (const_int 2)))]
-  "!(fixed_regs[SI_REG] || fixed_regs[DI_REG])"
+  "!(fixed_regs[SI_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^movsw"
   [(set_attr "type" "str")
    (set_attr "memory" "both")
        (plus:P (match_dup 3)
                (const_int 1)))]
   "!(fixed_regs[SI_REG] || fixed_regs[DI_REG])"
-  "%^movsb"
+  "%^movsb
+   && ix86_check_no_addr_space (insn)"
   [(set_attr "type" "str")
    (set_attr "memory" "both")
    (set (attr "prefix_rex")
        (mem:BLK (match_dup 4)))
    (use (match_dup 5))]
   "TARGET_64BIT
-   && !(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
+   && !(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^rep{%;} movsq"
   [(set_attr "type" "str")
    (set_attr "prefix_rep" "1")
    (set (mem:BLK (match_dup 3))
        (mem:BLK (match_dup 4)))
    (use (match_dup 5))]
-  "!(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
+  "!(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^rep{%;} movs{l|d}"
   [(set_attr "type" "str")
    (set_attr "prefix_rep" "1")
    (set (mem:BLK (match_dup 3))
        (mem:BLK (match_dup 4)))
    (use (match_dup 5))]
-  "!(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
+  "!(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^rep{%;} movsb"
   [(set_attr "type" "str")
    (set_attr "prefix_rep" "1")
              (clobber (reg:CC FLAGS_REG))])]
   ""
 {
+  /* Can't use this for non-default address spaces.  */
+  if (!ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (operands[1])))
+    FAIL;
+
   if (GET_MODE (operands[1]) != GET_MODE (operands[2]))
     operands[1] = adjust_address_nv (operands[1], GET_MODE (operands[2]), 0);
 
                (const_int 8)))
    (unspec [(const_int 0)] UNSPEC_STOS)]
   "TARGET_64BIT
-   && !(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
+   && !(fixed_regs[AX_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^stosq"
   [(set_attr "type" "str")
    (set_attr "memory" "store")
        (plus:P (match_dup 1)
                (const_int 4)))
    (unspec [(const_int 0)] UNSPEC_STOS)]
-  "!(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
+  "!(fixed_regs[AX_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^stos{l|d}"
   [(set_attr "type" "str")
    (set_attr "memory" "store")
        (plus:P (match_dup 1)
                (const_int 2)))
    (unspec [(const_int 0)] UNSPEC_STOS)]
-  "!(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
+  "!(fixed_regs[AX_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^stosw"
   [(set_attr "type" "str")
    (set_attr "memory" "store")
        (plus:P (match_dup 1)
                (const_int 1)))
    (unspec [(const_int 0)] UNSPEC_STOS)]
-  "!(fixed_regs[AX_REG] || fixed_regs[DI_REG])"
+  "!(fixed_regs[AX_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^stosb"
   [(set_attr "type" "str")
    (set_attr "memory" "store")
    (use (match_operand:DI 2 "register_operand" "a"))
    (use (match_dup 4))]
   "TARGET_64BIT
-   && !(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])"
+   && !(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^rep{%;} stosq"
   [(set_attr "type" "str")
    (set_attr "prefix_rep" "1")
        (const_int 0))
    (use (match_operand:SI 2 "register_operand" "a"))
    (use (match_dup 4))]
-  "!(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])"
+  "!(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^rep{%;} stos{l|d}"
   [(set_attr "type" "str")
    (set_attr "prefix_rep" "1")
        (const_int 0))
    (use (match_operand:QI 2 "register_operand" "a"))
    (use (match_dup 4))]
-  "!(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])"
+  "!(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^rep{%;} stosb"
   [(set_attr "type" "str")
    (set_attr "prefix_rep" "1")
    (clobber (match_operand:P 0 "register_operand" "=S"))
    (clobber (match_operand:P 1 "register_operand" "=D"))
    (clobber (match_operand:P 2 "register_operand" "=c"))]
-  "!(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
+  "!(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^repz{%;} cmpsb"
   [(set_attr "type" "str")
    (set_attr "mode" "QI")
    (clobber (match_operand:P 0 "register_operand" "=S"))
    (clobber (match_operand:P 1 "register_operand" "=D"))
    (clobber (match_operand:P 2 "register_operand" "=c"))]
-  "!(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])"
+  "!(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^repz{%;} cmpsb"
   [(set_attr "type" "str")
    (set_attr "mode" "QI")
                   (match_operand:P 4 "register_operand" "0")] UNSPEC_SCAS))
    (clobber (match_operand:P 1 "register_operand" "=D"))
    (clobber (reg:CC FLAGS_REG))]
-  "!(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])"
+  "!(fixed_regs[AX_REG] || fixed_regs[CX_REG] || fixed_regs[DI_REG])
+   && ix86_check_no_addr_space (insn)"
   "%^repnz{%;} scasb"
   [(set_attr "type" "str")
    (set_attr "mode" "QI")