https://gcc.gnu.org/bugzilla/show_bug.cgi?id=120019

--- Comment #7 from Uroš Bizjak <ubizjak at gmail dot com> ---
Comment on attachment 61270
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=61270
Proposed patch

># HG changeset patch
># Parent  45d1a47b563d28797adaefc1f063c6e3d2541ec3
>i386: Fix rep movs[qldb] handling with Solaris/x86 as
>
>diff --git a/gcc/config.in b/gcc/config.in
>--- a/gcc/config.in
>+++ b/gcc/config.in
>@@ -526,6 +526,12 @@
> #endif
> 
> 
>+/* Define if the assembler supports movs operands. */
>+#ifndef USED_FOR_TARGET
>+#undef HAVE_AS_IX86_MOVS_OPERANDS
>+#endif

We should avoid above complication with asm support detection and always use
explicit prefixes.

>+
> /* Define if your assembler supports the .quad directive. */
> #ifndef USED_FOR_TARGET
> #undef HAVE_AS_IX86_QUAD
>diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
>--- a/gcc/config/i386/i386.cc
>+++ b/gcc/config/i386/i386.cc
>@@ -13829,6 +13829,7 @@ print_reg (rtx x, int code, FILE *file)
>    H -- print a memory address offset by 8; used for sse high-parts
>    Y -- print condition for XOP pcom* instruction.
>    V -- print naked full integer register name without %.
>+   v -- print address space prefix unless HAVE_AS_IX86_MOVS_OPERANDS

Better say "-- print segment override prefix"

>    + -- print a branch hint as 'cs' or 'ds' prefix
>    ; -- print a semicolon (after prefixes due to bug in older gas).
>    ~ -- print "i" if TARGET_AVX2, "f" otherwise.
>@@ -14334,6 +14335,25 @@ ix86_print_operand (FILE *file, rtx x, i
> 
>         return;
> 
>+      case 'v':
>+#ifndef HAVE_AS_IX86_MOVS_OPERANDS
>+        if (MEM_P (x) && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (x)))
>+          return;
>+
>+        switch (MEM_ADDR_SPACE (x))
>+          {
>+          case ADDR_SPACE_SEG_FS:
>+            fputs ("fs ", file);
>+            break;
>+          case ADDR_SPACE_SEG_GS:
>+            fputs ("gs ", file);
>+            break;
>+          default:
>+            gcc_unreachable ();
>+          }
>+#endif

We can perhaps also report operand lossage for invalid operands:

if (MEM_P (x))
  {
    switch (MEM_ADDR_SPACE (x))
      {
        ...
        case ADDR_SPACE_GENERIC:
          break;
        default:
          gcc_unreachable ();
      }
   }
  else
   output_operand_lossage ("operand is not a memory reference, invalid operand
code 'v'");


>+        return;
>+
>       case '*':
>         if (ASSEMBLER_DIALECT == ASM_ATT)
>           putc ('*', file);
>diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
>--- a/gcc/config/i386/i386.h
>+++ b/gcc/config/i386/i386.h
>@@ -3039,6 +3039,12 @@ extern enum attr_cpu ix86_schedule;
> #define LIBGCC2_UNWIND_ATTRIBUTE __attribute__((target ("no-mmx,no-sse")))
> #endif
> 
>+#ifdef HAVE_AS_IX86_MOVS_OPERANDS
>+#define MOVS_OPERANDS "\t{%1, %0|%0, %1}"
>+#else
>+#define MOVS_OPERANDS ""
>+#endif

The above is not needed when explicit prefixes are always used

> /*
> Local variables:
> version-control: t
>diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
>--- a/gcc/config/i386/i386.md
>+++ b/gcc/config/i386/i386.md
>@@ -58,6 +58,7 @@
> ;; H -- print a memory address offset by 8; used for sse high-parts
> ;; K -- print HLE lock prefix
> ;; Y -- print condition for XOP pcom* instruction.
>+;; v -- print address space prefix unless HAVE_AS_IX86_MOVS_OPERANDS

As above.

> ;; + -- print a branch hint as 'cs' or 'ds' prefix
> ;; ; -- print a semicolon (after prefixes due to bug in older gas).
> ;; ~ -- print "i" if TARGET_AVX2, "f" otherwise.
>@@ -25643,7 +25644,7 @@
>   operands[0] = SET_DEST (exp);
>   operands[1] = SET_SRC (exp);
> 
>-  return "movsq\t{%1, %0|%0, %1}";
>+  return "movsq" MOVS_OPERANDS;

This also needs to output addr32 prefix (%^) and the new segment override
prefix:

return "%^%v1movsq"

> }
>   [(set_attr "type" "str")
>    (set_attr "memory" "both")
>@@ -25666,7 +25667,7 @@
>   operands[0] = SET_DEST (exp);
>   operands[1] = SET_SRC (exp);
> 
>-  return "movs{l|d}\t{%1, %0|%0, %1}";
>+  return "movs{l|d}" MOVS_OPERANDS;

Also here and for other instructions.

> }
>   [(set_attr "type" "str")
>    (set_attr "memory" "both")
>@@ -25689,7 +25690,7 @@
>   operands[0] = SET_DEST (exp);
>   operands[1] = SET_SRC (exp);
> 
>-  return "movsw\t{%1, %0|%0, %1}";
>+  return "movsw" MOVS_OPERANDS;
> }
>   [(set_attr "type" "str")
>    (set_attr "memory" "both")
>@@ -25712,7 +25713,7 @@
>   operands[0] = SET_DEST (exp);
>   operands[1] = SET_SRC (exp);
> 
>-  return "movsb\t{%1, %0|%0, %1}";
>+  return "movsb" MOVS_OPERANDS;
> }
>   [(set_attr "type" "str")
>    (set_attr "memory" "both")
>@@ -25759,7 +25760,7 @@
>   operands[0] = SET_DEST (exp);
>   operands[1] = SET_SRC (exp);
> 
>-  return "rep{%;} movsq\t{%1, %0|%0, %1}";
>+  return "%^%v1rep{%;} movsq" MOVS_OPERANDS;

On a related note, ";" after prefix is a historic relict which should probably
be removed.

> }
>   [(set_attr "type" "str")
>    (set_attr "prefix_rep" "1")
>@@ -25786,7 +25787,7 @@
>   operands[0] = SET_DEST (exp);
>   operands[1] = SET_SRC (exp);
> 
>-  return "rep{%;} movs{l|d}\t{%1, %0|%0, %1}";
>+  return "%^%v1rep{%;} movs{l|d}" MOVS_OPERANDS;
> }
>   [(set_attr "type" "str")
>    (set_attr "prefix_rep" "1")
>@@ -25811,7 +25812,7 @@
>   operands[0] = SET_DEST (exp);
>   operands[1] = SET_SRC (exp);
> 
>-  return "rep{%;} movsb\t{%1, %0|%0, %1}";
>+  return "%^%v1rep{%;} movsb" MOVS_OPERANDS;
> }
>   [(set_attr "type" "str")
>    (set_attr "prefix_rep" "1")
>diff --git a/gcc/configure b/gcc/configure
>--- a/gcc/configure
>+++ b/gcc/configure
>@@ -29646,6 +29646,38 @@ if test $gcc_cv_as_ix86_rep_lock_prefix 
> fi
> 
> 
>+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for movs 
>operands" >&5
>+$as_echo_n "checking assembler for movs operands... " >&6; }
>+if ${gcc_cv_as_ix86_movs_operands+:} false; then :
>+  $as_echo_n "(cached) " >&6
>+else
>+  gcc_cv_as_ix86_movs_operands=no
>+  if test x$gcc_cv_as != x; then
>+    $as_echo 'movsl (%esi), (%edi)' > conftest.s
>+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags  -o conftest.o conftest.s >&5'
>+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
>+  (eval $ac_try) 2>&5
>+  ac_status=$?
>+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
>+  test $ac_status = 0; }; }
>+    then
>+      gcc_cv_as_ix86_movs_operands=yes
>+    else
>+      echo "configure: failed program was" >&5
>+      cat conftest.s >&5
>+    fi
>+    rm -f conftest.o conftest.s
>+  fi
>+fi
>+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: 
>$gcc_cv_as_ix86_movs_operands" >&5
>+$as_echo "$gcc_cv_as_ix86_movs_operands" >&6; }
>+if test $gcc_cv_as_ix86_movs_operands = yes; then
>+
>+$as_echo "#define HAVE_AS_IX86_MOVS_OPERANDS 1" >>confdefs.h
>+
>+fi
>+
>+
>     { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for ud2 
> mnemonic" >&5
> $as_echo_n "checking assembler for ud2 mnemonic... " >&6; }
> if ${gcc_cv_as_ix86_ud2+:} false; then :
>diff --git a/gcc/configure.ac b/gcc/configure.ac
>--- a/gcc/configure.ac
>+++ b/gcc/configure.ac
>@@ -4970,6 +4970,12 @@ foo:    nop
>         [AC_DEFINE(HAVE_AS_IX86_REP_LOCK_PREFIX, 1,
>           [Define if the assembler supports 'rep <insn>, lock <insn>'.])])
> 
>+    gcc_GAS_CHECK_FEATURE([movs operands],
>+        gcc_cv_as_ix86_movs_operands,,
>+      [movsl (%esi), (%edi)],,
>+        [AC_DEFINE(HAVE_AS_IX86_MOVS_OPERANDS, 1,
>+          [Define if the assembler supports movs operands.])])
>+
>     gcc_GAS_CHECK_FEATURE([ud2 mnemonic],
>       gcc_cv_as_ix86_ud2,,
>       [ud2],,
>diff --git a/gcc/testsuite/gcc.target/i386/pr111657-1.c 
>b/gcc/testsuite/gcc.target/i386/pr111657-1.c
>--- a/gcc/testsuite/gcc.target/i386/pr111657-1.c
>+++ b/gcc/testsuite/gcc.target/i386/pr111657-1.c
>@@ -8,5 +8,6 @@ struct a { uword arr[30]; };
> __seg_gs struct a m;
> void bar (struct a *dst) { *dst = m; }
> 
>-/* { dg-final { scan-assembler "rep\[; \t\]+movs(l|q)\[ \t\]+%gs:" { target { 
>! x32 } } } } */
>+/* { dg-final { scan-assembler "rep\[; \t\]+movs(l|q)\[ \t\]+%gs:" { target { 
>{ ! x32 } && { ! { *-*-solaris2* && { ! gas } } } } } } } */

>+/* { dg-final { scan-assembler "gs\[ \t\]+rep\[; \t\]+movs(l|q)" { target { 
>*-*-solaris2* && { ! gas } } } } } */

We should always scan for the above string.

> /* { dg-final { scan-assembler-not "rep\[; \t\]+movs(l|q)\[ \t\]+%gs:" { 
> target x32 } } } */

And here check that the above string is *not* present. x32 should not use
instructions with segment overrides.

Reply via email to