aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorUros Bizjak <ubizjak@gmail.com>2025-04-29 18:08:05 +0200
committerUros Bizjak <ubizjak@gmail.com>2025-04-29 18:15:03 +0200
commit69669180d29cc420b1b1ac86530a4f9573748d81 (patch)
treed39f89589fc3a0b4b5889d64c2ab04656fb6897c /gcc
parent7c2e60f67a02d17d8c2f67ba438fdb50d51bc9f4 (diff)
downloadgcc-69669180d29cc420b1b1ac86530a4f9573748d81.zip
gcc-69669180d29cc420b1b1ac86530a4f9573748d81.tar.gz
gcc-69669180d29cc420b1b1ac86530a4f9573748d81.tar.bz2
i386: Disable string insn from non-default AS for Pmode != word_mode [PR111657]
0x67 prefix is applied before segment register. That is in rep movsq %gs:(%esi), (%edi) the address is %gs + %esi. In case Pmode != word_mode (x32 with a default -maddress-mode=short) instructions should not allow segment override prefixes. Also, remove explicit addr32 prefix from asm templates because address mode can be determined from explicit instruction operands. Also note that Pmode != word_mode only with TARGET_64BIT, so the check in ix86_print_operand is not needed. PR target/111657 gcc/ChangeLog: * config/i386/i386-expand.cc (alg_usable_p): For Pmode != word_mode reject rep_prefix_{1,4,8}_byte algorithms with src_as in the non-default address space. * config/i386/i386-protos.h (ix86_check_movs): New prototype. * config/i386/i386.cc (ix86_check_movs): New function. (ix86_print_operand) [case '^']: Remove excess check for TARGET_64BIT. * config/i386/i386.md (strmov): For Pmode != word_mode expand with gen_strmov_single only when operands[3] (source) is in the default address space. (*strmovdi_rex_1) Use ix86_check_movs. Remove %^ from asm template. (*strmovsi_1): Ditto. (*strmovhi_1): DItto. (*strmovqi_1): Ditto. (*rep_movdi_rex64): Ditto. (*rep_movsi): Ditto. (*rep_movqi): Ditto. gcc/testsuite/ChangeLog: * gcc.target/i386/pr111657-1.c: Check that segment override is not generated for "rep movsq" for x32 target.
Diffstat (limited to 'gcc')
-rw-r--r--gcc/config/i386/i386-expand.cc3
-rw-r--r--gcc/config/i386/i386-protos.h1
-rw-r--r--gcc/config/i386/i386.cc23
-rw-r--r--gcc/config/i386/i386.md39
-rw-r--r--gcc/testsuite/gcc.target/i386/pr111657-1.c3
5 files changed, 44 insertions, 25 deletions
diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index f1cc85b..7f0fdb6 100644
--- a/gcc/config/i386/i386-expand.cc
+++ b/gcc/config/i386/i386-expand.cc
@@ -8933,7 +8933,8 @@ alg_usable_p (enum stringop_alg alg, bool memset,
if (fixed_regs[CX_REG]
|| fixed_regs[DI_REG]
|| (memset ? fixed_regs[AX_REG] : fixed_regs[SI_REG])
- || !ADDR_SPACE_GENERIC_P (dst_as))
+ || !ADDR_SPACE_GENERIC_P (dst_as)
+ || !(ADDR_SPACE_GENERIC_P (src_as) || Pmode == word_mode))
return false;
}
return true;
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index c59b5a6..e85b925 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -186,6 +186,7 @@ extern void ix86_expand_v2di_ashiftrt (rtx[]);
extern rtx ix86_replace_reg_with_reg (rtx, rtx, rtx);
extern rtx ix86_find_base_term (rtx);
extern bool ix86_check_movabs (rtx, int);
+extern bool ix86_check_movs (rtx, int);
extern bool ix86_check_no_addr_space (rtx);
extern void ix86_split_idivmod (machine_mode, rtx[], bool);
extern bool ix86_hardreg_mov_ok (rtx, rtx);
diff --git a/gcc/config/i386/i386.cc b/gcc/config/i386/i386.cc
index bfd9cac..2f84033 100644
--- a/gcc/config/i386/i386.cc
+++ b/gcc/config/i386/i386.cc
@@ -5180,6 +5180,27 @@ ix86_check_movabs (rtx insn, int opnum)
return volatile_ok || !MEM_VOLATILE_P (mem);
}
+/* Return true if XVECEXP idx of INSN satisfies MOVS arguments. */
+bool
+ix86_check_movs (rtx insn, int idx)
+{
+ rtx pat = PATTERN (insn);
+ gcc_assert (GET_CODE (pat) == PARALLEL);
+
+ rtx set = XVECEXP (pat, 0, idx);
+ gcc_assert (GET_CODE (set) == SET);
+
+ rtx dst = SET_DEST (set);
+ gcc_assert (MEM_P (dst));
+
+ rtx src = SET_SRC (set);
+ gcc_assert (MEM_P (src));
+
+ return (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (dst))
+ && (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (src))
+ || Pmode == word_mode));
+}
+
/* Return false if INSN contains a MEM with a non-default address space. */
bool
ix86_check_no_addr_space (rtx insn)
@@ -14296,7 +14317,7 @@ ix86_print_operand (FILE *file, rtx x, int code)
return;
case '^':
- if (TARGET_64BIT && Pmode != word_mode)
+ if (Pmode != word_mode)
fputs ("addr32 ", file);
return;
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 962e7ab..44ee94a 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -25599,7 +25599,9 @@
* since string insns cannot override the destination segment. */
if ((TARGET_SINGLE_STRINGOP || optimize_insn_for_size_p ())
&& !(fixed_regs[SI_REG] || fixed_regs[DI_REG])
- && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (operands[1])))
+ && ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (operands[1]))
+ && (ADDR_SPACE_GENERIC_P (MEM_ADDR_SPACE (operands[3]))
+ || Pmode == word_mode))
{
emit_insn (gen_strmov_singleop (operands[0], operands[1],
operands[2], operands[3],
@@ -25634,15 +25636,14 @@
(const_int 8)))]
"TARGET_64BIT
&& !(fixed_regs[SI_REG] || fixed_regs[DI_REG])
- && ADDR_SPACE_GENERIC_P
- (MEM_ADDR_SPACE (SET_DEST (XVECEXP (PATTERN (insn), 0, 0))))"
+ && ix86_check_movs (insn, 0)"
{
rtx exp = XVECEXP (PATTERN (insn), 0, 0);
operands[0] = SET_DEST (exp);
operands[1] = SET_SRC (exp);
- return "%^movsq\t{%1, %0|%0, %1}";
+ return "movsq\t{%1, %0|%0, %1}";
}
[(set_attr "type" "str")
(set_attr "memory" "both")
@@ -25658,15 +25659,14 @@
(plus:P (match_dup 3)
(const_int 4)))]
"!(fixed_regs[SI_REG] || fixed_regs[DI_REG])
- && ADDR_SPACE_GENERIC_P
- (MEM_ADDR_SPACE (SET_DEST (XVECEXP (PATTERN (insn), 0, 0))))"
+ && ix86_check_movs (insn, 0)"
{
rtx exp = XVECEXP (PATTERN (insn), 0, 0);
operands[0] = SET_DEST (exp);
operands[1] = SET_SRC (exp);
- return "%^movs{l|d}\t{%1, %0|%0, %1}";
+ return "movs{l|d}\t{%1, %0|%0, %1}";
}
[(set_attr "type" "str")
(set_attr "memory" "both")
@@ -25682,15 +25682,14 @@
(plus:P (match_dup 3)
(const_int 2)))]
"!(fixed_regs[SI_REG] || fixed_regs[DI_REG])
- && ADDR_SPACE_GENERIC_P
- (MEM_ADDR_SPACE (SET_DEST (XVECEXP (PATTERN (insn), 0, 0))))"
+ && ix86_check_movs (insn, 0)"
{
rtx exp = XVECEXP (PATTERN (insn), 0, 0);
operands[0] = SET_DEST (exp);
operands[1] = SET_SRC (exp);
- return "%^movsw\t{%1, %0|%0, %1}";
+ return "movsw\t{%1, %0|%0, %1}";
}
[(set_attr "type" "str")
(set_attr "memory" "both")
@@ -25706,15 +25705,14 @@
(plus:P (match_dup 3)
(const_int 1)))]
"!(fixed_regs[SI_REG] || fixed_regs[DI_REG])
- && ADDR_SPACE_GENERIC_P
- (MEM_ADDR_SPACE (SET_DEST (XVECEXP (PATTERN (insn), 0, 0))))"
+ && ix86_check_movs (insn, 0)"
{
rtx exp = XVECEXP (PATTERN (insn), 0, 0);
operands[0] = SET_DEST (exp);
operands[1] = SET_SRC (exp);
- return "%^movsb\t{%1, %0|%0, %1}";
+ return "movsb\t{%1, %0|%0, %1}";
}
[(set_attr "type" "str")
(set_attr "memory" "both")
@@ -25754,15 +25752,14 @@
(use (match_dup 5))]
"TARGET_64BIT
&& !(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])
- && ADDR_SPACE_GENERIC_P
- (MEM_ADDR_SPACE (SET_DEST (XVECEXP (PATTERN (insn), 0, 3))))"
+ && ix86_check_movs (insn, 3)"
{
rtx exp = XVECEXP (PATTERN (insn), 0, 3);
operands[0] = SET_DEST (exp);
operands[1] = SET_SRC (exp);
- return "%^rep{%;} movsq\t{%1, %0|%0, %1}";
+ return "rep{%;} movsq\t{%1, %0|%0, %1}";
}
[(set_attr "type" "str")
(set_attr "prefix_rep" "1")
@@ -25782,15 +25779,14 @@
(mem:BLK (match_dup 4)))
(use (match_dup 5))]
"!(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])
- && ADDR_SPACE_GENERIC_P
- (MEM_ADDR_SPACE (SET_DEST (XVECEXP (PATTERN (insn), 0, 3))))"
+ && ix86_check_movs (insn, 3)"
{
rtx exp = XVECEXP (PATTERN (insn), 0, 3);
operands[0] = SET_DEST (exp);
operands[1] = SET_SRC (exp);
- return "%^rep{%;} movs{l|d}\t{%1, %0|%0, %1}";
+ return "rep{%;} movs{l|d}\t{%1, %0|%0, %1}";
}
[(set_attr "type" "str")
(set_attr "prefix_rep" "1")
@@ -25808,15 +25804,14 @@
(mem:BLK (match_dup 4)))
(use (match_dup 5))]
"!(fixed_regs[CX_REG] || fixed_regs[SI_REG] || fixed_regs[DI_REG])
- && ADDR_SPACE_GENERIC_P
- (MEM_ADDR_SPACE (SET_DEST (XVECEXP (PATTERN (insn), 0, 3))))"
+ && ix86_check_movs (insn, 3)"
{
rtx exp = XVECEXP (PATTERN (insn), 0, 3);
operands[0] = SET_DEST (exp);
operands[1] = SET_SRC (exp);
- return "%^rep{%;} movsb\t{%1, %0|%0, %1}";
+ return "rep{%;} movsb\t{%1, %0|%0, %1}";
}
[(set_attr "type" "str")
(set_attr "prefix_rep" "1")
diff --git a/gcc/testsuite/gcc.target/i386/pr111657-1.c b/gcc/testsuite/gcc.target/i386/pr111657-1.c
index 69117b7..99acd1f 100644
--- a/gcc/testsuite/gcc.target/i386/pr111657-1.c
+++ b/gcc/testsuite/gcc.target/i386/pr111657-1.c
@@ -8,4 +8,5 @@ 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:" } } */
+/* { dg-final { scan-assembler "rep\[; \t\]+movs(l|q)\[ \t\]+%gs:" { target { ! x32 } } } } */
+/* { dg-final { scan-assembler-not "rep\[; \t\]+movs(l|q)\[ \t\]+%gs:" { target x32 } } } */