diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 61ffafb663c..120d963081d 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,34 @@ +2007-03-01 Richard Sandiford + + * 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 * Makefile.in (install-include-dir): Don't rm -rf include. diff --git a/gcc/Makefile.in b/gcc/Makefile.in index 2331ef0343c..974f6b4ba37 100644 --- a/gcc/Makefile.in +++ b/gcc/Makefile.in @@ -2314,7 +2314,7 @@ print-rtl.o : print-rtl.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(TM_H) \ $(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) \ diff --git a/gcc/config/m68k/m68k-protos.h b/gcc/config/m68k/m68k-protos.h index 85a5376826b..d0ff670639b 100644 --- a/gcc/config/m68k/m68k-protos.h +++ b/gcc/config/m68k/m68k-protos.h @@ -50,6 +50,7 @@ extern int standard_68881_constant_p (rtx); 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); diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c index 08ebbd20dac..90e2491fb73 100644 --- a/gcc/config/m68k/m68k.c +++ b/gcc/config/m68k/m68k.c @@ -191,6 +191,9 @@ int m68k_last_compare_had_fp_operands; #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 } */ @@ -1663,6 +1666,23 @@ output_btst (rtx *operands, rtx countop, rtx dataop, rtx insn, int signpos) return "btst %0,%1"; } +/* 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 diff --git a/gcc/config/m68k/m68k.h b/gcc/config/m68k/m68k.h index d8325641475..f960f3b4773 100644 --- a/gcc/config/m68k/m68k.h +++ b/gcc/config/m68k/m68k.h @@ -786,17 +786,25 @@ __transfer_from_trampoline () \ /* 1 if X is an address register */ #define ADDRESS_REG_P(X) (REG_P (X) && REGNO_OK_FOR_BASE_P (REGNO (X))) +/* 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 diff --git a/gcc/config/m68k/m68k.md b/gcc/config/m68k/m68k.md index 42e5f21dfce..a2f0cfd7044 100644 --- a/gcc/config/m68k/m68k.md +++ b/gcc/config/m68k/m68k.md @@ -627,10 +627,12 @@ ;; 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. @@ -651,6 +653,18 @@ 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 diff --git a/gcc/config/m68k/uclinux.h b/gcc/config/m68k/uclinux.h index 992c465ce10..93a9d829187 100644 --- a/gcc/config/m68k/uclinux.h +++ b/gcc/config/m68k/uclinux.h @@ -65,3 +65,9 @@ Boston, MA 02110-1301, USA. */ /* -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 diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index 37035aad58f..82b38a795ec 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -267,8 +267,6 @@ struct mips_integer_op; 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, @@ -1292,58 +1290,6 @@ mips_classify_symbol (rtx x) 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. */ @@ -1351,9 +1297,9 @@ mips_offset_within_object_p (rtx symbol, HOST_WIDE_INT offset) 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) @@ -1365,7 +1311,7 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type) else return false; - if (offset == 0) + if (offset == const0_rtx) return true; /* Check whether a nonzero offset is valid for the underlying @@ -1381,7 +1327,7 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type) 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; @@ -1397,15 +1343,15 @@ mips_symbolic_constant_p (rtx x, enum mips_symbol_type *symbol_type) 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: @@ -1595,8 +1541,7 @@ mips_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED) static bool mips_cannot_force_const_mem (rtx x) { - rtx base; - HOST_WIDE_INT offset; + rtx base, offset; if (!TARGET_MIPS16) { @@ -1612,8 +1557,8 @@ mips_cannot_force_const_mem (rtx x) 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; } @@ -1800,7 +1745,7 @@ mips_const_insns (rtx x) { 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)) { @@ -1841,16 +1786,16 @@ mips_const_insns (rtx 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; @@ -1949,13 +1894,14 @@ mips_split_symbol (rtx temp, rtx addr) 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); } @@ -2303,8 +2249,7 @@ mips_move_integer (rtx dest, rtx temp, unsigned HOST_WIDE_INT value) 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)) @@ -2329,13 +2274,13 @@ mips_legitimize_const_move (enum machine_mode mode, rtx dest, rtx src) /* 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; } @@ -5709,16 +5654,15 @@ print_operand_reloc (FILE *file, rtx op, const char **relocs) { 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); @@ -7640,12 +7584,12 @@ mips_cannot_change_mode_class (enum machine_mode from, 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); } diff --git a/gcc/rtl.h b/gcc/rtl.h index 6bf09aa14a9..41d50d4755f 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -1672,6 +1672,8 @@ extern int rtx_varies_p (rtx, int); 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); diff --git a/gcc/rtlanal.c b/gcc/rtlanal.c index 00a996e4696..cf9fd1d65af 100644 --- a/gcc/rtlanal.c +++ b/gcc/rtlanal.c @@ -37,6 +37,7 @@ Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA #include "real.h" #include "regs.h" #include "function.h" +#include "tree.h" /* Information about a subreg of a hard register. */ struct subreg_info @@ -496,6 +497,61 @@ get_related_value (rtx x) return 0; } +/* 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; +} + /* 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. */