}
/* Accept anything that can be used as the source operand for a prefetch
- instruction. */
+ instruction with a cache-control completer. */
int
-prefetch_operand (rtx op, enum machine_mode mode)
+prefetch_cc_operand (rtx op, enum machine_mode mode)
{
if (GET_CODE (op) != MEM)
return 0;
+ op = XEXP (op, 0);
+
+ /* We must reject virtual registers as we don't allow REG+D. */
+ if (op == virtual_incoming_args_rtx
+ || op == virtual_stack_vars_rtx
+ || op == virtual_stack_dynamic_rtx
+ || op == virtual_outgoing_args_rtx
+ || op == virtual_cfa_rtx)
+ return 0;
+
+ if (!REG_P (op) && !IS_INDEX_ADDR_P (op))
+ return 0;
+
/* Until problems with management of the REG_POINTER flag are resolved,
we need to delay creating prefetch insns with unscaled indexed addresses
until CSE is not expected. */
if (!TARGET_NO_SPACE_REGS
&& !cse_not_expected
- && GET_CODE (XEXP (op, 0)) == PLUS
- && REG_P (XEXP (XEXP (op, 0), 0))
- && REG_P (XEXP (XEXP (op, 0), 1)))
+ && GET_CODE (op) == PLUS
+ && REG_P (XEXP (op, 0)))
return 0;
- return memory_address_p (mode, XEXP (op, 0));
+ return memory_address_p (mode, op);
+}
+
+/* Accept anything that can be used as the source operand for a prefetch
+ instruction with no cache-control completer. */
+int
+prefetch_nocc_operand (rtx op, enum machine_mode mode)
+{
+ if (GET_CODE (op) != MEM)
+ return 0;
+
+ op = XEXP (op, 0);
+
+ /* Until problems with management of the REG_POINTER flag are resolved,
+ we need to delay creating prefetch insns with unscaled indexed addresses
+ until CSE is not expected. */
+ if (!TARGET_NO_SPACE_REGS
+ && !cse_not_expected
+ && GET_CODE (op) == PLUS
+ && REG_P (XEXP (op, 0))
+ && REG_P (XEXP (op, 1)))
+ return 0;
+
+ return memory_address_p (mode, op);
}
/* Accept REG and any CONST_INT that can be moved in one instruction into a
`T' is for floating-point loads and stores.
- `U' is the constant 63. */
+ `U' is the constant 63.
+
+ `W' is a register indirect memory operand. We could allow short
+ displacements but GO_IF_LEGITIMATE_ADDRESS can't tell when a
+ long displacement is valid. This is only used for prefetch
+ instructions with the `sl' completer. */
#define EXTRA_CONSTRAINT(OP, C) \
((C) == 'Q' ? \
&& !symbolic_memory_operand (OP, VOIDmode) \
&& !IS_LO_SUM_DLT_ADDR_P (XEXP (OP, 0)) \
&& !IS_INDEX_ADDR_P (XEXP (OP, 0)))) \
+ : ((C) == 'W' ? \
+ (GET_CODE (OP) == MEM \
+ && REG_P (XEXP (OP, 0)) \
+ && REG_OK_FOR_BASE_P (XEXP (OP, 0))) \
: ((C) == 'A' ? \
(GET_CODE (OP) == MEM \
&& IS_LO_SUM_DLT_ADDR_P (XEXP (OP, 0))) \
: ((C) == 'S' ? \
(GET_CODE (OP) == CONST_INT && INTVAL (OP) == 31) \
: ((C) == 'U' ? \
- (GET_CODE (OP) == CONST_INT && INTVAL (OP) == 63) : 0))))))
+ (GET_CODE (OP) == CONST_INT && INTVAL (OP) == 63) : 0)))))))
/* The macros REG_OK_FOR..._P assume that the arg is a REG rtx
CONST_DOUBLE}}, \
{"move_dest_operand", {SUBREG, REG, MEM}}, \
{"move_src_operand", {SUBREG, REG, CONST_INT, MEM}}, \
- {"prefetch_operand", {MEM}}, \
+ {"prefetch_cc_operand", {MEM}}, \
+ {"prefetch_nocc_operand", {MEM}}, \
{"reg_or_cint_move_operand", {SUBREG, REG, CONST_INT}}, \
{"pic_label_operand", {LABEL_REF, CONST}}, \
{"fp_reg_operand", {REG}}, \
(match_operand 2 "const_int_operand" "")]
"TARGET_PA_20"
{
- /* The PA 2.0 prefetch instructions only support short displacements
- when a cache control completer needs to be supplied. Thus, we
- can't use LO_SUM DLT addresses with the spatial locality completer. */
- if (operands[2] == const0_rtx && IS_LO_SUM_DLT_ADDR_P (operands[0]))
- FAIL;
+ int locality = INTVAL (operands[2]);
- /* We change operand0 to a MEM as we don't have the infrastructure to
- output all the supported address modes for ldw/ldd but we do have
- it for MEMs. */
- operands[0] = gen_rtx_MEM (Pmode, operands[0]);
-
- if (!TARGET_NO_SPACE_REGS
- && !cse_not_expected
- && GET_CODE (XEXP (operands[0], 0)) == PLUS
- && REG_P (XEXP (XEXP (operands[0], 0), 0))
- && REG_P (XEXP (XEXP (operands[0], 0), 1)))
- operands[0]
- = replace_equiv_address (operands[0],
- copy_to_mode_reg (Pmode,
- XEXP (operands[0], 0)));
+ if (locality < 0 || locality > 3)
+ abort ();
- if (TARGET_64BIT)
- emit_insn (gen_prefetch_64 (operands[0], operands[1], operands[2]));
- else
- emit_insn (gen_prefetch_32 (operands[0], operands[1], operands[2]));
- DONE;
-})
+ /* Change operand[0] to a MEM as we don't have the infrastructure
+ to output all the supported address modes for ldw/ldd when we use
+ the address directly. However, we do have it for MEMs. */
+ operands[0] = gen_rtx_MEM (QImode, operands[0]);
-(define_insn "prefetch_64"
- [(prefetch (match_operand:DI 0 "prefetch_operand" "A,RQ")
- (match_operand:DI 1 "const_int_operand" "n,n")
- (match_operand:DI 2 "const_int_operand" "n,n"))]
- "TARGET_64BIT
- && (operands[2] != const0_rtx
- || GET_CODE (XEXP (operands[0], 0)) != PLUS
- || GET_CODE (XEXP (XEXP (operands[0], 0), 1)) != CONST_INT
- || INT_5_BITS (XEXP (XEXP (operands[0], 0), 1)))"
-{
- /* The SL completor indicates good spatial locality but poor temporal
- locality. The ldw instruction with a target of general register 0
- prefetches a cache line for a read. The ldd instruction prefetches
- a cache line for a write. */
- static const char * const instr[2][2][2] = {
+ /* If the address isn't valid for the prefetch, replace it. */
+ if (locality)
{
- {
- "",
- "ldw RT'%A0,%%r0",
- },
- {
- "",
- "ldd RT'%A0,%%r0",
- },
- },
+ if (!prefetch_nocc_operand (operands[0], QImode))
+ operands[0]
+ = replace_equiv_address (operands[0],
+ copy_to_mode_reg (Pmode,
+ XEXP (operands[0], 0)));
+ emit_insn (gen_prefetch_nocc (operands[0], operands[1], operands[2]));
+ }
+ else
{
- {
- "ldw%M0,sl %0,%%r0",
- "ldw%M0 %0,%%r0",
- },
- {
- "ldd%M0,sl %0,%%r0",
- "ldd%M0 %0,%%r0",
- }
+ if (!prefetch_cc_operand (operands[0], QImode))
+ operands[0]
+ = replace_equiv_address (operands[0],
+ copy_to_mode_reg (Pmode,
+ XEXP (operands[0], 0)));
+ emit_insn (gen_prefetch_cc (operands[0], operands[1], operands[2]));
}
+ DONE;
+})
+
+(define_insn "prefetch_cc"
+ [(prefetch (match_operand:QI 0 "prefetch_cc_operand" "RW")
+ (match_operand:SI 1 "const_int_operand" "n")
+ (match_operand:SI 2 "const_int_operand" "n"))]
+ "TARGET_PA_20 && operands[2] == const0_rtx"
+{
+ /* The SL cache-control completor indicates good spatial locality but
+ poor temporal locality. The ldw instruction with a target of general
+ register 0 prefetches a cache line for a read. The ldd instruction
+ prefetches a cache line for a write. */
+ static const char * const instr[2] = {
+ "ldw%M0,sl %0,%%r0",
+ "ldd%M0,sl %0,%%r0"
};
int read_or_write = INTVAL (operands[1]);
- int locality = INTVAL (operands[2]);
- if ((which_alternative != 0 && which_alternative != 1)
- || (read_or_write != 0 && read_or_write != 1)
- || (locality < 0 || locality > 3))
+ if (read_or_write < 0 || read_or_write > 1)
abort ();
- if (which_alternative == 0 && locality == 0)
- abort ();
-
- return instr [which_alternative][read_or_write][locality == 0 ? 0 : 1];
+ return instr [read_or_write];
}
[(set_attr "type" "load")
(set_attr "length" "4")])
-(define_insn "prefetch_32"
- [(prefetch (match_operand:SI 0 "prefetch_operand" "A,RQ")
+(define_insn "prefetch_nocc"
+ [(prefetch (match_operand:QI 0 "prefetch_nocc_operand" "A,RQ")
(match_operand:SI 1 "const_int_operand" "n,n")
(match_operand:SI 2 "const_int_operand" "n,n"))]
- "TARGET_PA_20
- && (operands[2] != const0_rtx
- || GET_CODE (XEXP (operands[0], 0)) != PLUS
- || GET_CODE (XEXP (XEXP (operands[0], 0), 1)) != CONST_INT
- || INT_5_BITS (XEXP (XEXP (operands[0], 0), 1)))"
-{
- /* The SL completor indicates good spatial locality but poor temporal
- locality. The ldw instruction with a target of general register 0
- prefetches a cache line for a read. The ldd instruction prefetches
- a cache line for a write. */
- static const char * const instr[2][2][2] = {
+ "TARGET_PA_20 && operands[2] != const0_rtx"
+{
+ /* The ldw instruction with a target of general register 0 prefetches
+ a cache line for a read. The ldd instruction prefetches a cache line
+ for a write. */
+ static const char * const instr[2][2] = {
{
- {
- "",
- "ldw RT'%A0,%%r0",
- },
- {
- "",
- "ldd RT'%A0,%%r0",
- },
+ "ldw RT'%A0,%%r0",
+ "ldd RT'%A0,%%r0",
},
{
- {
- "ldw%M0,sl %0,%%r0",
- "ldw%M0 %0,%%r0",
- },
- {
- "ldd%M0,sl %0,%%r0",
- "ldd%M0 %0,%%r0",
- }
+ "ldw%M0 %0,%%r0",
+ "ldd%M0 %0,%%r0",
}
};
int read_or_write = INTVAL (operands[1]);
- int locality = INTVAL (operands[2]);
if ((which_alternative != 0 && which_alternative != 1)
- || (read_or_write != 0 && read_or_write != 1)
- || (locality < 0 || locality > 3))
- abort ();
-
- if (which_alternative == 0 && locality == 0)
+ || (read_or_write < 0 || read_or_write > 1))
abort ();
- return instr [which_alternative][read_or_write][locality == 0 ? 0 : 1];
+ return instr [which_alternative][read_or_write];
}
[(set_attr "type" "load")
(set_attr "length" "4")])