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.