+2007-03-01 Richard Sandiford <richard@codesourcery.com>
+
+ * Makefile.in (rtlanal.o): Depend on tree.h.
+ * rtl.h (offset_within_section_p, split_const): Declare.
+ * rtlanal.c: Include tree.h.
+ (offset_within_block_p): New function, taken from
+ mips_offset_within_object_p.
+ (split_const): New function, taken from mips_split_const.
+ * config/m68k/m68k-protos.h (m68k_illegitimate_symbolic_constant_p):
+ Declare.
+ * config/m68k/m68k.h (M68K_OFFSETS_MUST_BE_WITHIN_SECTIONS_P): Define.
+ (CONSTANT_ADDRESS_P): Only accept legitimate constants.
+ (LEGITIMATE_CONSTANT_P): Check m68k_illegitimate_symbolic_constant_p.
+ * config/m68k/m68k.c (TARGET_CANNOT_FORCE_CONST_MEM): Define.
+ (m68k_illegitimate_symbolic_constant_p): New function.
+ * config/m68k/m68k.md (movsi): Remove misleading predicates.
+ If M68K_OFFSETS_MUST_BE_WITHIN_SECTIONS_P and the source is a
+ symbolic constant that might be outside the symbol's section,
+ move the symbol first and then add the offset.
+ * config/m68k/uclinux.h (M68K_OFFSETS_MUST_BE_WITHIN_SECTIONS_P):
+ Override.
+ * config/mips/mips.c (mips_split_const): Delete.
+ (mips_offset_within_object_p): Delete.
+ (mips_symbolic_constant_p): Use offset_within_section_p and
+ split_const instead of mips_offset_within_object_p and
+ mips_split_const.
+ (mips_cannot_force_const_mem, mips_const_insns, mips_unspec_address)
+ (mips_legitimize_const_move, print_operand_reloc)
+ (mips_dangerous_for_la25_p): Use split_const instead of
+ mips_split_const.
+
2007-02-28 Eric Christopher <echristo@apple.com>
* Makefile.in (install-include-dir): Don't rm -rf include.
$(BCONFIG_H) $(REAL_H)
rtlanal.o : rtlanal.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) toplev.h \
$(RTL_H) hard-reg-set.h $(TM_P_H) insn-config.h $(RECOG_H) $(REAL_H) \
- $(FLAGS_H) $(REGS_H) output.h $(TARGET_H) $(FUNCTION_H)
+ $(FLAGS_H) $(REGS_H) output.h $(TARGET_H) $(FUNCTION_H) $(TREE_H)
varasm.o : varasm.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) $(TREE_H) \
$(RTL_H) $(FLAGS_H) $(FUNCTION_H) $(EXPR_H) hard-reg-set.h $(REGS_H) \
extern void print_operand_address (FILE *, rtx);
extern void print_operand (FILE *, rtx, int);
extern void notice_update_cc (rtx, rtx);
+extern bool m68k_illegitimate_symbolic_constant_p (rtx);
extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
extern int valid_dbcc_comparison_p_2 (rtx, enum machine_mode);
extern rtx m68k_libcall_value (enum machine_mode);
#undef TARGET_STRUCT_VALUE_RTX
#define TARGET_STRUCT_VALUE_RTX m68k_struct_value_rtx
+#undef TARGET_CANNOT_FORCE_CONST_MEM
+#define TARGET_CANNOT_FORCE_CONST_MEM m68k_illegitimate_symbolic_constant_p
+
static const struct attribute_spec m68k_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
return "btst %0,%1";
}
\f
+/* Return true if X is an illegitimate symbolic constant. */
+
+bool
+m68k_illegitimate_symbolic_constant_p (rtx x)
+{
+ rtx base, offset;
+
+ if (M68K_OFFSETS_MUST_BE_WITHIN_SECTIONS_P)
+ {
+ split_const (x, &base, &offset);
+ if (GET_CODE (base) == SYMBOL_REF
+ && !offset_within_block_p (base, INTVAL (offset)))
+ return true;
+ }
+ return false;
+}
+
/* Legitimize PIC addresses. If the address is already
position-independent, we return ORIG. Newly generated
position-independent addresses go to REG. If we need more
/* 1 if X is an address register */
#define ADDRESS_REG_P(X) (REG_P (X) && REGNO_OK_FOR_BASE_P (REGNO (X)))
\f
+/* True if SYMBOL + OFFSET constants must refer to something within
+ SYMBOL's section. */
+#ifndef M68K_OFFSETS_MUST_BE_WITHIN_SECTIONS_P
+#define M68K_OFFSETS_MUST_BE_WITHIN_SECTIONS_P 0
+#endif
#define MAX_REGS_PER_ADDRESS 2
-#define CONSTANT_ADDRESS_P(X) \
- (GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
- || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \
- || GET_CODE (X) == HIGH)
+#define CONSTANT_ADDRESS_P(X) \
+ ((GET_CODE (X) == LABEL_REF || GET_CODE (X) == SYMBOL_REF \
+ || GET_CODE (X) == CONST_INT || GET_CODE (X) == CONST \
+ || GET_CODE (X) == HIGH) \
+ && LEGITIMATE_CONSTANT_P (X))
/* Nonzero if the constant value X is a legitimate general operand.
It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. */
-#define LEGITIMATE_CONSTANT_P(X) (GET_MODE (X) != XFmode)
+#define LEGITIMATE_CONSTANT_P(X) \
+ (GET_MODE (X) != XFmode \
+ && !m68k_illegitimate_symbolic_constant_p (X))
#ifndef REG_OK_STRICT
#define PCREL_GENERAL_OPERAND_OK 0
;; In both the PIC and non-PIC cases the patterns generated will
;; matched by the next define_insn.
(define_expand "movsi"
- [(set (match_operand:SI 0 "nonimmediate_operand" "")
- (match_operand:SI 1 "general_operand" ""))]
+ [(set (match_operand:SI 0 "" "")
+ (match_operand:SI 1 "" ""))]
""
{
+ rtx tmp, base, offset;
+
if (flag_pic && !TARGET_PCREL && symbolic_operand (operands[1], SImode))
{
/* The source is an address which requires PIC relocation.
operands[0] = gen_rtx_MEM (SImode,
force_reg (SImode, XEXP (operands[0], 0)));
}
+ if (M68K_OFFSETS_MUST_BE_WITHIN_SECTIONS_P)
+ {
+ split_const (operands[1], &base, &offset);
+ if (GET_CODE (base) == SYMBOL_REF
+ && !offset_within_block_p (base, INTVAL (offset)))
+ {
+ tmp = no_new_pseudos ? operands[0] : gen_reg_rtx (SImode);
+ emit_move_insn (tmp, base);
+ emit_insn (gen_addsi3 (operands[0], tmp, offset));
+ DONE;
+ }
+ }
})
;; General case of fullword move. The register constraints
/* -msep-data is the default PIC mode on this target. */
#define DRIVER_SELF_SPECS \
"%{fpie|fPIE|fpic|fPIC:%{!msep-data:%{!mid-shared-library: -msep-data}}}"
+
+/* The uclinux binary format relies on relocations against a segment being
+ within that segment. Conservatively apply this rule to individual
+ sections. */
+#undef M68K_OFFSETS_MUST_BE_WITHIN_SECTIONS_P
+#define M68K_OFFSETS_MUST_BE_WITHIN_SECTIONS_P 1
struct mips_sim;
static enum mips_symbol_type mips_classify_symbol (rtx);
-static void mips_split_const (rtx, rtx *, HOST_WIDE_INT *);
-static bool mips_offset_within_object_p (rtx, HOST_WIDE_INT);
static bool mips_valid_base_register_p (rtx, enum machine_mode, int);
static bool mips_symbolic_address_p (enum mips_symbol_type, enum machine_mode);
static bool mips_classify_address (struct mips_address_info *, rtx,
return SYMBOL_GENERAL;
}
-
-/* Split X into a base and a constant offset, storing them in *BASE
- and *OFFSET respectively. */
-
-static void
-mips_split_const (rtx x, rtx *base, HOST_WIDE_INT *offset)
-{
- *offset = 0;
-
- if (GET_CODE (x) == CONST)
- {
- x = XEXP (x, 0);
- if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
- {
- *offset += INTVAL (XEXP (x, 1));
- x = XEXP (x, 0);
- }
- }
- *base = x;
-}
-
-
-/* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
- to the same object as SYMBOL, or to the same object_block. */
-
-static bool
-mips_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset)
-{
- if (GET_CODE (symbol) != SYMBOL_REF)
- return false;
-
- if (CONSTANT_POOL_ADDRESS_P (symbol)
- && offset >= 0
- && offset < (int) GET_MODE_SIZE (get_pool_mode (symbol)))
- return true;
-
- if (SYMBOL_REF_DECL (symbol) != 0
- && offset >= 0
- && offset < int_size_in_bytes (TREE_TYPE (SYMBOL_REF_DECL (symbol))))
- return true;
-
- if (SYMBOL_REF_HAS_BLOCK_INFO_P (symbol)
- && SYMBOL_REF_BLOCK (symbol)
- && SYMBOL_REF_BLOCK_OFFSET (symbol) >= 0
- && ((unsigned HOST_WIDE_INT) offset + SYMBOL_REF_BLOCK_OFFSET (symbol)
- < (unsigned HOST_WIDE_INT) SYMBOL_REF_BLOCK (symbol)->size))
- return true;
-
- return false;
-}
-
-
/* Return true if X is a symbolic constant that can be calculated in
the same way as a bare symbol. If it is, store the type of the
symbol in *SYMBOL_TYPE. */
bool
mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type)
{
- HOST_WIDE_INT offset;
+ rtx offset;
- mips_split_const (x, &x, &offset);
+ split_const (x, &x, &offset);
if (UNSPEC_ADDRESS_P (x))
*symbol_type = UNSPEC_ADDRESS_TYPE (x);
else if (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF)
else
return false;
- if (offset == 0)
+ if (offset == const0_rtx)
return true;
/* Check whether a nonzero offset is valid for the underlying
sign-extended. In this case we can't allow an arbitrary offset
in case the 32-bit value X + OFFSET has a different sign from X. */
if (Pmode == DImode && !ABI_HAS_64BIT_SYMBOLS)
- return mips_offset_within_object_p (x, offset);
+ return offset_within_block_p (x, INTVAL (offset));
/* In other cases the relocations can handle any offset. */
return true;
case SYMBOL_SMALL_DATA:
/* Make sure that the offset refers to something within the
- underlying object. This should guarantee that the final
+ same object block. This should guarantee that the final
PC- or GP-relative offset is within the 16-bit limit. */
- return mips_offset_within_object_p (x, offset);
+ return offset_within_block_p (x, INTVAL (offset));
case SYMBOL_GOT_LOCAL:
case SYMBOL_GOTOFF_PAGE:
/* The linker should provide enough local GOT entries for a
16-bit offset. Larger offsets may lead to GOT overflow. */
- return SMALL_OPERAND (offset);
+ return SMALL_INT (offset);
case SYMBOL_GOT_GLOBAL:
case SYMBOL_GOTOFF_GLOBAL:
static bool
mips_cannot_force_const_mem (rtx x)
{
- rtx base;
- HOST_WIDE_INT offset;
+ rtx base, offset;
if (!TARGET_MIPS16)
{
if (GET_CODE (x) == CONST_INT)
return true;
- mips_split_const (x, &base, &offset);
- if (symbolic_operand (base, VOIDmode) && SMALL_OPERAND (offset))
+ split_const (x, &base, &offset);
+ if (symbolic_operand (base, VOIDmode) && SMALL_INT (offset))
return true;
}
{
struct mips_integer_op codes[MIPS_MAX_INTEGER_OPS];
enum mips_symbol_type symbol_type;
- HOST_WIDE_INT offset;
+ rtx offset;
switch (GET_CODE (x))
{
/* Otherwise try splitting the constant into a base and offset.
16-bit offsets can be added using an extra addiu. Larger offsets
must be calculated separately and then added to the base. */
- mips_split_const (x, &x, &offset);
+ split_const (x, &x, &offset);
if (offset != 0)
{
int n = mips_const_insns (x);
if (n != 0)
{
- if (SMALL_OPERAND (offset))
+ if (SMALL_INT (offset))
return n + 1;
else
- return n + 1 + mips_build_integer (codes, offset);
+ return n + 1 + mips_build_integer (codes, INTVAL (offset));
}
}
return 0;
rtx
mips_unspec_address (rtx address, enum mips_symbol_type symbol_type)
{
- rtx base;
- HOST_WIDE_INT offset;
+ rtx base, offset;
- mips_split_const (address, &base, &offset);
+ split_const (address, &base, &offset);
base = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, base),
UNSPEC_ADDRESS_FIRST + symbol_type);
- return plus_constant (gen_rtx_CONST (Pmode, base), offset);
+ if (offset != const0_rtx)
+ base = gen_rtx_PLUS (Pmode, base, offset);
+ return gen_rtx_CONST (Pmode, base);
}
static void
mips_legitimize_const_move (enum machine_mode mode, rtx dest, rtx src)
{
- rtx base;
- HOST_WIDE_INT offset;
+ rtx base, offset;
/* Split moves of big integers into smaller pieces. */
if (splittable_const_int_operand (src, mode))
/* If we have (const (plus symbol offset)), load the symbol first
and then add in the offset. This is usually better than forcing
the constant into memory, at least in non-mips16 code. */
- mips_split_const (src, &base, &offset);
+ split_const (src, &base, &offset);
if (!TARGET_MIPS16
- && offset != 0
- && (!no_new_pseudos || SMALL_OPERAND (offset)))
+ && offset != const0_rtx
+ && (!no_new_pseudos || SMALL_INT (offset)))
{
base = mips_force_temporary (dest, base);
- emit_move_insn (dest, mips_add_offset (0, base, offset));
+ emit_move_insn (dest, mips_add_offset (0, base, INTVAL (offset)));
return;
}
{
enum mips_symbol_type symbol_type;
const char *p;
- rtx base;
- HOST_WIDE_INT offset;
+ rtx base, offset;
if (!mips_symbolic_constant_p (op, &symbol_type) || relocs[symbol_type] == 0)
fatal_insn ("PRINT_OPERAND, invalid operand for relocation", op);
/* If OP uses an UNSPEC address, we want to print the inner symbol. */
- mips_split_const (op, &base, &offset);
+ split_const (op, &base, &offset);
if (UNSPEC_ADDRESS_P (base))
- op = plus_constant (UNSPEC_ADDRESS (base), offset);
+ op = plus_constant (UNSPEC_ADDRESS (base), INTVAL (offset));
fputs (relocs[symbol_type], file);
output_addr_const (file, op);
bool
mips_dangerous_for_la25_p (rtx x)
{
- HOST_WIDE_INT offset;
+ rtx offset;
if (TARGET_EXPLICIT_RELOCS)
return false;
- mips_split_const (x, &x, &offset);
+ split_const (x, &x, &offset);
return global_got_operand (x, VOIDmode);
}
extern int rtx_addr_varies_p (rtx, int);
extern HOST_WIDE_INT get_integer_term (rtx);
extern rtx get_related_value (rtx);
+extern bool offset_within_block_p (rtx, HOST_WIDE_INT);
+extern void split_const (rtx, rtx *, rtx *);
extern int reg_mentioned_p (rtx, rtx);
extern int count_occurrences (rtx, rtx, int);
extern int reg_referenced_p (rtx, rtx);
#include "real.h"
#include "regs.h"
#include "function.h"
+#include "tree.h"
/* Information about a subreg of a hard register. */
struct subreg_info
return 0;
}
\f
+/* Return true if SYMBOL is a SYMBOL_REF and OFFSET + SYMBOL points
+ to somewhere in the same object or object_block as SYMBOL. */
+
+bool
+offset_within_block_p (rtx symbol, HOST_WIDE_INT offset)
+{
+ tree decl;
+
+ if (GET_CODE (symbol) != SYMBOL_REF)
+ return false;
+
+ if (offset == 0)
+ return true;
+
+ if (offset > 0)
+ {
+ if (CONSTANT_POOL_ADDRESS_P (symbol)
+ && offset < (int) GET_MODE_SIZE (get_pool_mode (symbol)))
+ return true;
+
+ decl = SYMBOL_REF_DECL (symbol);
+ if (decl && offset < int_size_in_bytes (TREE_TYPE (decl)))
+ return true;
+ }
+
+ if (SYMBOL_REF_HAS_BLOCK_INFO_P (symbol)
+ && SYMBOL_REF_BLOCK (symbol)
+ && SYMBOL_REF_BLOCK_OFFSET (symbol) >= 0
+ && ((unsigned HOST_WIDE_INT) offset + SYMBOL_REF_BLOCK_OFFSET (symbol)
+ < (unsigned HOST_WIDE_INT) SYMBOL_REF_BLOCK (symbol)->size))
+ return true;
+
+ return false;
+}
+
+/* Split X into a base and a constant offset, storing them in *BASE_OUT
+ and *OFFSET_OUT respectively. */
+
+void
+split_const (rtx x, rtx *base_out, rtx *offset_out)
+{
+ if (GET_CODE (x) == CONST)
+ {
+ x = XEXP (x, 0);
+ if (GET_CODE (x) == PLUS && GET_CODE (XEXP (x, 1)) == CONST_INT)
+ {
+ *base_out = XEXP (x, 0);
+ *offset_out = XEXP (x, 1);
+ return;
+ }
+ }
+ *base_out = x;
+ *offset_out = const0_rtx;
+}
+\f
/* Return the number of places FIND appears within X. If COUNT_DEST is
zero, we do not count occurrences inside the destination of a SET. */