summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog17
-rw-r--r--gcc/config/mips/mips-protos.h2
-rw-r--r--gcc/config/mips/mips.c68
-rw-r--r--gcc/config/mips/mips.md11
-rw-r--r--gcc/config/mips/predicates.md10
5 files changed, 68 insertions, 40 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index a2e4f6ae352..63d49c35a9d 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,22 @@
2007-08-08 Richard Sandiford <richard@codesourcery.com>
+ * config/mips/mips-protos.h (mips_split_symbol): Add a mode and
+ an "rtx *" argument. Return a bool.
+ * config/mips/mips.c (mips_split_symbol): Accept arbitrary source
+ values and return true if they can be split. Take the same kind of
+ mode argument as mips_symbol_insns. Add a "lo_sum_out" parameter
+ and store the lo_sum there if nonnull. Use the symbol type to
+ determine whether a $gp or HIGH is needed.
+ (mips_legitimize_address): Update call to mips_split_symbol and
+ simplify accordingly.
+ (mips_legitimize_const_move): Likewise.
+ * config/mips/mips.md: In the combine define_split,
+ check mips_split_symbol instead of splittable_symbolic_operand.
+ Update use of mips_split_symbol in the generator code.
+ * config/mips/predicates.md (splittable_symbolic_operand): Delete.
+
+2007-08-08 Richard Sandiford <richard@codesourcery.com>
+
* config/mips/mips.c (mips_symbolic_address_p): Delete.
(mips_symbol_insns_1): New function, split out from...
(mips_symbol_insns): ...here. Take a mode argument. Treat loads
diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h
index 13cbfbfc341..d2f501740f0 100644
--- a/gcc/config/mips/mips-protos.h
+++ b/gcc/config/mips/mips-protos.h
@@ -171,7 +171,7 @@ extern int mips_idiv_insns (void);
extern int fp_register_operand (rtx, enum machine_mode);
extern int lo_operand (rtx, enum machine_mode);
extern bool mips_legitimate_address_p (enum machine_mode, rtx, int);
-extern rtx mips_split_symbol (rtx, rtx);
+extern bool mips_split_symbol (rtx, rtx, enum machine_mode, rtx *);
extern rtx mips_unspec_address (rtx, enum mips_symbol_type);
extern bool mips_legitimize_address (rtx *, enum machine_mode);
extern void mips_move_integer (rtx, rtx, unsigned HOST_WIDE_INT);
diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c
index b8e013e984d..2b620fbb20b 100644
--- a/gcc/config/mips/mips.c
+++ b/gcc/config/mips/mips.c
@@ -2113,24 +2113,50 @@ mips_force_temporary (rtx dest, rtx value)
}
-/* Return a LO_SUM expression for ADDR. TEMP is as for mips_force_temporary
- and is used to load the high part into a register. */
+/* If MODE is MAX_MACHINE_MODE, ADDR appears as a move operand, otherwise
+ it appears in a MEM of that mode. Return true if ADDR is a legitimate
+ constant in that context and can be split into a high part and a LO_SUM.
+ If so, and if LO_SUM_OUT is nonnull, emit the high part and return
+ the LO_SUM in *LO_SUM_OUT. Leave *LO_SUM_OUT unchanged otherwise.
-rtx
-mips_split_symbol (rtx temp, rtx addr)
+ TEMP is as for mips_force_temporary and is used to load the high
+ part into a register. */
+
+bool
+mips_split_symbol (rtx temp, rtx addr, enum machine_mode mode, rtx *lo_sum_out)
{
+ enum mips_symbol_context context;
+ enum mips_symbol_type symbol_type;
rtx high;
- if (!TARGET_MIPS16)
- high = mips_force_temporary (temp, gen_rtx_HIGH (Pmode, copy_rtx (addr)));
- else if (!can_create_pseudo_p ())
+ context = (mode == MAX_MACHINE_MODE
+ ? SYMBOL_CONTEXT_LEA
+ : SYMBOL_CONTEXT_MEM);
+ if (!mips_symbolic_constant_p (addr, context, &symbol_type)
+ || mips_symbol_insns (symbol_type, mode) == 0
+ || !mips_split_p[symbol_type])
+ return false;
+
+ if (lo_sum_out)
{
- emit_insn (gen_load_const_gp (copy_rtx (temp)));
- high = temp;
+ if (symbol_type == SYMBOL_GP_RELATIVE)
+ {
+ if (!can_create_pseudo_p ())
+ {
+ emit_insn (gen_load_const_gp (copy_rtx (temp)));
+ high = temp;
+ }
+ else
+ high = mips16_gp_pseudo_reg ();
+ }
+ else
+ {
+ high = gen_rtx_HIGH (Pmode, copy_rtx (addr));
+ high = mips_force_temporary (temp, high);
+ }
+ *lo_sum_out = gen_rtx_LO_SUM (Pmode, high, addr);
}
- else
- high = mips16_gp_pseudo_reg ();
- return gen_rtx_LO_SUM (Pmode, high, addr);
+ return true;
}
@@ -2321,8 +2347,6 @@ mips_legitimize_tls_address (rtx loc)
bool
mips_legitimize_address (rtx *xloc, enum machine_mode mode)
{
- enum mips_symbol_type symbol_type;
-
if (mips_tls_operand_p (*xloc))
{
*xloc = mips_legitimize_tls_address (*xloc);
@@ -2330,13 +2354,8 @@ mips_legitimize_address (rtx *xloc, enum machine_mode mode)
}
/* See if the address can split into a high part and a LO_SUM. */
- if (mips_symbolic_constant_p (*xloc, SYMBOL_CONTEXT_MEM, &symbol_type)
- && mips_symbol_insns (symbol_type, mode) > 0
- && mips_split_p[symbol_type])
- {
- *xloc = mips_split_symbol (0, *xloc);
- return true;
- }
+ if (mips_split_symbol (NULL, *xloc, mode, xloc))
+ return true;
if (GET_CODE (*xloc) == PLUS && GET_CODE (XEXP (*xloc, 1)) == CONST_INT)
{
@@ -2505,9 +2524,9 @@ mips_legitimize_const_move (enum machine_mode mode, rtx dest, rtx src)
}
/* Split moves of symbolic constants into high/low pairs. */
- if (splittable_symbolic_operand (src, mode))
+ if (mips_split_symbol (dest, src, MAX_MACHINE_MODE, &src))
{
- emit_insn (gen_rtx_SET (VOIDmode, dest, mips_split_symbol (dest, src)));
+ emit_insn (gen_rtx_SET (VOIDmode, dest, src));
return;
}
@@ -2534,8 +2553,7 @@ mips_legitimize_const_move (enum machine_mode mode, rtx dest, rtx src)
/* When using explicit relocs, constant pool references are sometimes
not legitimate addresses. */
- if (!memory_operand (src, VOIDmode))
- src = replace_equiv_address (src, mips_split_symbol (dest, XEXP (src, 0)));
+ mips_split_symbol (dest, XEXP (src, 0), mode, &XEXP (src, 0));
emit_move_insn (dest, src);
}
diff --git a/gcc/config/mips/mips.md b/gcc/config/mips/mips.md
index e522f4e44ec..2e3d52243cf 100644
--- a/gcc/config/mips/mips.md
+++ b/gcc/config/mips/mips.md
@@ -3299,11 +3299,14 @@
;; Likewise, for symbolic operands.
(define_split
[(set (match_operand:P 0 "register_operand")
- (match_operand:P 1 "splittable_symbolic_operand"))
+ (match_operand:P 1))
(clobber (match_operand:P 2 "register_operand"))]
- ""
- [(set (match_dup 0) (match_dup 1))]
- { operands[1] = mips_split_symbol (operands[2], operands[1]); })
+ "mips_split_symbol (operands[2], operands[1], MAX_MACHINE_MODE, NULL)"
+ [(set (match_dup 0) (match_dup 3))]
+{
+ mips_split_symbol (operands[2], operands[1],
+ MAX_MACHINE_MODE, &operands[3]);
+})
;; 64-bit integer moves
diff --git a/gcc/config/mips/predicates.md b/gcc/config/mips/predicates.md
index 1171291f508..308dd636f57 100644
--- a/gcc/config/mips/predicates.md
+++ b/gcc/config/mips/predicates.md
@@ -154,16 +154,6 @@
return !LUI_INT (op) && !SMALL_INT (op) && !SMALL_INT_UNSIGNED (op);
})
-;; A legitimate symbolic operand that takes more than one instruction
-;; to load.
-(define_predicate "splittable_symbolic_operand"
- (match_code "const,symbol_ref,label_ref")
-{
- enum mips_symbol_type symbol_type;
- return (mips_symbolic_constant_p (op, SYMBOL_CONTEXT_LEA, &symbol_type)
- && mips_split_p[symbol_type]);
-})
-
(define_predicate "move_operand"
(match_operand 0 "general_operand")
{