diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 97076399d2b..69978a31686 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,17 @@ +2007-03-06 Richard Sandiford + + PR target/28181 + * config/m68k/m68k-protos.h (m68k_secondary_reload_class): Declare. + (m68k_preferred_reload_class): Likewise. + * config/m68k/m68k.h (HARD_REGNO_MODE_OK): Remove duplicated comment. + (SECONDARY_RELOAD_CLASS): Define. + (PREFERRED_RELOAD_CLASS): Use m68k_preferred_reload_class. + (LIMIT_RELOAD_CLASS): Delete. + * config/m68k/m68k.c (m68k_regno_mode_ok): Don't prevent address + registers from storing bytes. + (m68k_secondary_reload_class): New function. + (m68k_preferred_reload_class): Likewise. + 2007-03-06 Richard Sandiford * config/m68k/m68k.c (m68k_save_reg): Remove special case for diff --git a/gcc/config/m68k/m68k-protos.h b/gcc/config/m68k/m68k-protos.h index 185e7bc8809..b3b78a15adb 100644 --- a/gcc/config/m68k/m68k-protos.h +++ b/gcc/config/m68k/m68k-protos.h @@ -69,6 +69,9 @@ extern const char *m68k_output_movem (rtx *, rtx, HOST_WIDE_INT, bool); #endif /* RTX_CODE */ extern bool m68k_regno_mode_ok (int, enum machine_mode); +extern enum reg_class m68k_secondary_reload_class (enum reg_class, + enum machine_mode, rtx); +extern enum reg_class m68k_preferred_reload_class (rtx, enum reg_class); extern int flags_in_68881 (void); extern void m68k_expand_prologue (void); extern bool m68k_use_return_insn (void); diff --git a/gcc/config/m68k/m68k.c b/gcc/config/m68k/m68k.c index e491beb38fc..b702f85e47f 100644 --- a/gcc/config/m68k/m68k.c +++ b/gcc/config/m68k/m68k.c @@ -4153,9 +4153,10 @@ m68k_hard_regno_rename_ok (unsigned int old_reg ATTRIBUTE_UNUSED, return 1; } -/* Value is true if hard register REGNO can hold a value of machine-mode MODE. - On the 68000, the cpu registers can hold any mode except bytes in address - registers, but the 68881 registers can hold only SFmode or DFmode. */ +/* Value is true if hard register REGNO can hold a value of machine-mode + MODE. On the 68000, we let the cpu registers can hold any mode, but + restrict the 68881 registers to floating-point modes. */ + bool m68k_regno_mode_ok (int regno, enum machine_mode mode) { @@ -4167,10 +4168,6 @@ m68k_regno_mode_ok (int regno, enum machine_mode mode) } else if (ADDRESS_REGNO_P (regno)) { - /* Address Registers, can't hold bytes, can hold aggregate if - fits in. */ - if (GET_MODE_SIZE (mode) == 1) - return false; if (regno + GET_MODE_SIZE (mode) / 4 <= 16) return true; } @@ -4186,6 +4183,66 @@ m68k_regno_mode_ok (int regno, enum machine_mode mode) return false; } +/* Implement SECONDARY_RELOAD_CLASS. */ + +enum reg_class +m68k_secondary_reload_class (enum reg_class rclass, + enum machine_mode mode, rtx x) +{ + int regno; + + regno = true_regnum (x); + + /* If one operand of a movqi is an address register, the other + operand must be a general register or constant. Other types + of operand must be reloaded through a data register. */ + if (GET_MODE_SIZE (mode) == 1 + && reg_classes_intersect_p (rclass, ADDR_REGS) + && !(INT_REGNO_P (regno) || CONSTANT_P (x))) + return DATA_REGS; + + /* PC-relative addresses must be loaded into an address register first. */ + if (TARGET_PCREL + && !reg_class_subset_p (rclass, ADDR_REGS) + && symbolic_operand (x, VOIDmode)) + return ADDR_REGS; + + return NO_REGS; +} + +/* Implement PREFERRED_RELOAD_CLASS. */ + +enum reg_class +m68k_preferred_reload_class (rtx x, enum reg_class rclass) +{ + enum reg_class secondary_class; + + /* If RCLASS might need a secondary reload, try restricting it to + a class that doesn't. */ + secondary_class = m68k_secondary_reload_class (rclass, GET_MODE (x), x); + if (secondary_class != NO_REGS + && reg_class_subset_p (secondary_class, rclass)) + return secondary_class; + + /* Prefer to use moveq for in-range constants. */ + if (GET_CODE (x) == CONST_INT + && reg_class_subset_p (DATA_REGS, rclass) + && IN_RANGE (INTVAL (x), -0x80, 0x7f)) + return DATA_REGS; + + /* ??? Do we really need this now? */ + if (GET_CODE (x) == CONST_DOUBLE + && GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT) + { + if (TARGET_HARD_FLOAT && reg_class_subset_p (FP_REGS, rclass)) + return FP_REGS; + + return NO_REGS; + } + + return rclass; +} + /* Return floating point values in a 68881 register. This makes 68881 code a little bit faster. It also makes -msoft-float code incompatible with hard-float code, so people have to be careful not to mix the two. diff --git a/gcc/config/m68k/m68k.h b/gcc/config/m68k/m68k.h index c4b1e14842c..9d7843d7b94 100644 --- a/gcc/config/m68k/m68k.h +++ b/gcc/config/m68k/m68k.h @@ -401,13 +401,12 @@ Boston, MA 02110-1301, USA. */ #define HARD_REGNO_RENAME_OK(OLD_REG, NEW_REG) \ m68k_hard_regno_rename_ok (OLD_REG, NEW_REG) -/* Value is true if hard register REGNO can hold a value of machine-mode MODE. - On the 68000, the cpu registers can hold any mode except bytes in - address registers, the 68881 registers can hold only SFmode or DFmode. */ - #define HARD_REGNO_MODE_OK(REGNO, MODE) \ m68k_regno_mode_ok ((REGNO), (MODE)) +#define SECONDARY_RELOAD_CLASS(CLASS, MODE, X) \ + m68k_secondary_reload_class (CLASS, MODE, X) + #define MODES_TIEABLE_P(MODE1, MODE2) \ (! TARGET_HARD_FLOAT \ || ((GET_MODE_CLASS (MODE1) == MODE_FLOAT \ @@ -544,34 +543,8 @@ extern enum reg_class regno_reg_class[]; ? const_call_operand (OP, VOIDmode) \ : 0) -/* On the m68k, use a data reg if possible when the - value is a constant in the range where moveq could be used - and we ensure that QImodes are reloaded into data regs. */ -#define PREFERRED_RELOAD_CLASS(X,CLASS) \ - ((GET_CODE (X) == CONST_INT \ - && (unsigned) (INTVAL (X) + 0x80) < 0x100 \ - && (CLASS) != ADDR_REGS) \ - ? DATA_REGS \ - : (GET_MODE (X) == QImode && (CLASS) != ADDR_REGS) \ - ? DATA_REGS \ - : (GET_CODE (X) == CONST_DOUBLE \ - && GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT) \ - ? (TARGET_HARD_FLOAT && (CLASS == FP_REGS || CLASS == DATA_OR_FP_REGS) \ - ? FP_REGS : NO_REGS) \ - : (TARGET_PCREL \ - && (GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == CONST \ - || GET_CODE (X) == LABEL_REF)) \ - ? ADDR_REGS \ - : (CLASS)) - -/* Force QImode output reloads from subregs to be allocated to data regs, - since QImode stores from address regs are not supported. We make the - assumption that if the class is not ADDR_REGS, then it must be a superset - of DATA_REGS. */ -#define LIMIT_RELOAD_CLASS(MODE, CLASS) \ - (((MODE) == QImode && (CLASS) != ADDR_REGS) \ - ? DATA_REGS \ - : (CLASS)) +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + m68k_preferred_reload_class (X, CLASS) /* On the m68k, this is the size of MODE in words, except in the FP regs, where a single reg is always enough. */ diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 7753a04e5ae..849ec240bfd 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,7 @@ +2007-03-06 Richard Sandiford + + * gcc.c-torture/compile/m68k-byte-addr.c: New test. + 2007-03-05 Kaveh R. Ghazi * gcc.dg/torture/builtin-convert-4.c: New test. diff --git a/gcc/testsuite/gcc.c-torture/compile/m68k-byte-addr.c b/gcc/testsuite/gcc.c-torture/compile/m68k-byte-addr.c new file mode 100644 index 00000000000..88667a461ec --- /dev/null +++ b/gcc/testsuite/gcc.c-torture/compile/m68k-byte-addr.c @@ -0,0 +1,20 @@ +/* This testcase triggered an attempt to reload a byte value into an + address register. */ +extern volatile unsigned char x[]; + +#define DECLARE(I) orig##I, inc##I +#define READ(I) orig##I = x[I] +#define INC(I) inc##I = orig##I + 1 +#define WRITE1(I) x[I] = orig##I +#define WRITE2(I) x[I] = inc##I + +#define REPEAT(X) X(0), X(1), X(2), X(3), X(4), X(5), X(6), X(7), X(8) + +void foo (void) +{ + unsigned char REPEAT (DECLARE); + REPEAT (READ); + REPEAT (INC); + REPEAT (WRITE1); + REPEAT (WRITE2); +}