@@ -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);
@@ -10537,6 +10537,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;
+}
/* Initialize the table of extra 80387 mathematical constants. */
@@ -25660,7 +25674,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;
@@ -25669,12 +25683,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;
}
@@ -25682,7 +25703,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;
@@ -25714,7 +25736,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)
@@ -25730,17 +25752,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
@@ -25763,7 +25785,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;
@@ -25783,7 +25806,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;
@@ -25800,7 +25823,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;
@@ -25817,7 +25840,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;
@@ -25825,7 +25848,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);
}
@@ -26031,6 +26054,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);
@@ -26068,11 +26092,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;
@@ -26686,6 +26714,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);
@@ -16159,6 +16159,10 @@
(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
@@ -16199,7 +16203,8 @@
(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")
@@ -16214,7 +16219,8 @@
(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")
@@ -16229,7 +16235,8 @@
(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")
@@ -16245,7 +16252,8 @@
(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")
@@ -16280,7 +16288,8 @@
(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")
@@ -16299,7 +16308,8 @@
(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")
@@ -16316,7 +16326,8 @@
(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")
@@ -16356,6 +16367,10 @@
(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);
@@ -16391,7 +16406,8 @@
(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")
@@ -16404,7 +16420,8 @@
(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")
@@ -16417,7 +16434,8 @@
(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")
@@ -16430,7 +16448,8 @@
(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")
@@ -16462,7 +16481,8 @@
(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")
@@ -16479,7 +16499,8 @@
(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")
@@ -16495,7 +16516,8 @@
(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")
@@ -16616,7 +16638,8 @@
(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")
@@ -16656,7 +16679,8 @@
(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")
@@ -16697,7 +16721,8 @@
(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")