diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 0e0f0eea8f1..9b4c1439034 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,85 @@ +2002-11-04 Aldy Hernandez + + * hard-reg-set.h (REG_CANNOT_CHANGE_MODE_P): New. + + * config/rs6000/rs6000.h (CLASS_CANNOT_CHANGE_MODE_P): Remove. + (CLASS_CANNOT_CHANGE_MODE): Remove. + (CANNOT_CHANGE_MODE_CLASS): New. + + * config/alpha/alpha.h: Same. + + * config/ia64/ia64.h: Same. + + * config/mips/mips.h: Same. + + * config/s390/s390.h: Same. + + * config/sh/sh.h: Same. + + * config/pa/pa64-regs.h: Same. + + * config/sh/sh-protos.h (sh_cannot_change_mode_class): Add prototype. + + * config/sh/sh.c (sh_cannot_change_mode_class): New. + + * config/mips/mips-protos.h (mips_cannot_change_mode_class): Add + prototype. + + * config/mips/mips.c (mips_cannot_change_mode_class): New. + + * doc/tm.texi (Register Classes): Remove + CLASS_CANNOT_CHANGE_MODE and CLASS_CANNOT_CHANGE_MODE_P. + Document CANNOT_CHANGE_MODE_CLASS. + + * reload.c (push_reload): Use CANNOT_CHANGE_MODE_CLASS. + (push_reload): Same. + + * simplify-rtx.c (simplify_subreg): Same. + + * reload1.c (choose_reload_regs): Same. + + * recog.c (register_operand): Same. + + * regrename.c (mode_change_ok): Change to use new + CANNOT_CHANGE_MODE_CLASS infrastructure. + + * regclass.c (cannot_change_mode_set_regs): New. + Declare subregs_of_mode. + (regclass): Use subregs_of_mode. + Remove references to reg_changes_mode. + (init_reg_sets_1): Remove class_can_change_mode and + reg_changes_mode code. + (invalid_mode_change_p): New. + (dump_regclass): Use invalid_mode_change_p instead of + class_can_change_mode. + (regclass): Same. + (record_operand_costs): Do not set reg_changes_mode. + + * local-alloc.c (struct qty): Remove changes_mode field. + (alloc_qty): Remove changes_mode initialization. + (update_qty_class): Remove set of changes_mode. + (find_free_reg): Use subregs_of_mode. + + * global.c (find_reg): Use subregs_of_mode info. + + * rtl.h (cannot_change_mode_set_regs): New prototype. + (invalid_mode_change_p): Same. + (REG_CANNOT_CHANGE_MODE_P): New macro. + + * flow.c (mark_used_regs): Calculate subregs_of_mode. Remove + REG_CHANGES_MODE. + (life_analysis): Clear subregs_of_mode. + + * combine.c (subst): Pass class to CLASS_CANNOT_CHANGE_MODE_P. + Remove use of CLASS_CANNOT_CHANGE_MODE. + (simplify_set): Same. + (gen_lowpart_for_combine): Calculate subregs_of_mode. Remove + REG_CHANGES_MODE. + + * regs.h: Add extern for subregs_of_mode; + Include hard-reg-set and basic-block. + (REG_CHANGES_MODE): Delete. + 2002-11-03 John David Anglin * jump.c (never_reached_warning): Don't set contains_insn until the diff --git a/gcc/combine.c b/gcc/combine.c index d6dfdf68d17..8ce9d10eb1d 100644 --- a/gcc/combine.c +++ b/gcc/combine.c @@ -3519,15 +3519,13 @@ subst (x, from, to, in_dest, unique_copy) ) return gen_rtx_CLOBBER (VOIDmode, const0_rtx); -#ifdef CLASS_CANNOT_CHANGE_MODE +#ifdef CANNOT_CHANGE_MODE_CLASS if (code == SUBREG && GET_CODE (to) == REG && REGNO (to) < FIRST_PSEUDO_REGISTER - && (TEST_HARD_REG_BIT - (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], - REGNO (to))) - && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (to), - GET_MODE (x))) + && REG_CANNOT_CHANGE_MODE_P (REGNO (to), + GET_MODE (to), + GET_MODE (x))) return gen_rtx_CLOBBER (VOIDmode, const0_rtx); #endif @@ -5198,13 +5196,11 @@ simplify_set (x) && (GET_MODE_SIZE (GET_MODE (src)) < GET_MODE_SIZE (GET_MODE (SUBREG_REG (src)))) #endif -#ifdef CLASS_CANNOT_CHANGE_MODE +#ifdef CANNOT_CHANGE_MODE_CLASS && ! (GET_CODE (dest) == REG && REGNO (dest) < FIRST_PSEUDO_REGISTER - && (TEST_HARD_REG_BIT - (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], - REGNO (dest))) - && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (src), - GET_MODE (SUBREG_REG (src)))) + && REG_CANNOT_CHANGE_MODE_P (REGNO (dest), + GET_MODE (src), + GET_MODE (SUBREG_REG (src)))) #endif && (GET_CODE (dest) == REG || (GET_CODE (dest) == SUBREG @@ -9937,14 +9933,13 @@ gen_lowpart_for_combine (mode, x) } result = gen_lowpart_common (mode, x); -#ifdef CLASS_CANNOT_CHANGE_MODE +#ifdef CANNOT_CHANGE_MODE_CLASS if (result != 0 && GET_CODE (result) == SUBREG && GET_CODE (SUBREG_REG (result)) == REG - && REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER - && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (result), - GET_MODE (SUBREG_REG (result)))) - REG_CHANGES_MODE (REGNO (SUBREG_REG (result))) = 1; + && REGNO (SUBREG_REG (result)) >= FIRST_PSEUDO_REGISTER) + SET_REGNO_REG_SET (&subregs_of_mode[GET_MODE (result)], + REGNO (SUBREG_REG (result))); #endif if (result) diff --git a/gcc/config/alpha/alpha.h b/gcc/config/alpha/alpha.h index 39973770d71..9e39a40395b 100644 --- a/gcc/config/alpha/alpha.h +++ b/gcc/config/alpha/alpha.h @@ -857,15 +857,10 @@ enum reg_class { #define CLASS_MAX_NREGS(CLASS, MODE) \ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) -/* If defined, gives a class of registers that cannot be used as the - operand of a SUBREG that changes the mode of the object illegally. */ +/* Return the class of registers that cannot change mode from FROM to TO. */ -#define CLASS_CANNOT_CHANGE_MODE FLOAT_REGS - -/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */ - -#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \ - (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)) +#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \ + (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) ? FLOAT_REGS : NO_REGS) /* Define the cost of moving between registers of various classes. Moving between FLOAT_REGS and anything else except float regs is expensive. diff --git a/gcc/config/ia64/ia64.h b/gcc/config/ia64/ia64.h index 578e3546644..59d6e230366 100644 --- a/gcc/config/ia64/ia64.h +++ b/gcc/config/ia64/ia64.h @@ -1008,17 +1008,11 @@ enum reg_class : ((CLASS) == FR_REGS && (MODE) == TFmode) ? 1 \ : (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) -/* If defined, gives a class of registers that cannot be used as the - operand of a SUBREG that changes the mode of the object illegally. */ - -#define CLASS_CANNOT_CHANGE_MODE FR_REGS - -/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. - In FP regs, we can't change FP values to integer values and vice +/* In FP regs, we can't change FP values to integer values and vice versa, but we can change e.g. DImode to SImode. */ -#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \ - (GET_MODE_CLASS (FROM) != GET_MODE_CLASS (TO)) +#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \ + (GET_MODE_CLASS (FROM) != GET_MODE_CLASS (TO) ? FR_REGS : NO_REGS) /* A C expression that defines the machine-dependent operand constraint letters (`I', `J', `K', .. 'P') that specify particular ranges of diff --git a/gcc/config/mips/mips-protos.h b/gcc/config/mips/mips-protos.h index df943afb3f5..d92f7e573b3 100644 --- a/gcc/config/mips/mips-protos.h +++ b/gcc/config/mips/mips-protos.h @@ -122,6 +122,8 @@ extern int mips_adjust_insn_length PARAMS ((rtx, int)); extern enum reg_class mips_secondary_reload_class PARAMS ((enum reg_class, enum machine_mode, rtx, int)); +extern enum reg_class mips_cannot_change_mode_class + PARAMS ((enum machine_mode, enum machine_mode)); extern int mips_class_max_nregs PARAMS ((enum reg_class, enum machine_mode)); extern int mips_register_move_cost PARAMS ((enum machine_mode, diff --git a/gcc/config/mips/mips.c b/gcc/config/mips/mips.c index dafa9207cad..d58affff1c2 100644 --- a/gcc/config/mips/mips.c +++ b/gcc/config/mips/mips.c @@ -8399,6 +8399,23 @@ function_arg_pass_by_reference (cum, mode, type, named) return size == -1 || size > UNITS_PER_WORD; } +/* Return the class of registers for which a mode change from FROM to TO + is invalid. */ +enum reg_class +mips_cannot_change_mode_class (from, to) + enum machine_mode from, to; +{ + if (GET_MODE_SIZE (from) != GET_MODE_SIZE (to)) + { + if (TARGET_BIG_ENDIAN) + return FP_REGS; + if (TARGET_FLOAT64) + return HI_AND_FP_REGS; + return HI_REG; + } + return NO_REGS; +} + /* This function returns the register class required for a secondary register when copying between one of the registers in CLASS, and X, using MODE. If IN_P is nonzero, the copy is going from X to the diff --git a/gcc/config/mips/mips.h b/gcc/config/mips/mips.h index 87513a2bda0..bc37a145e28 100644 --- a/gcc/config/mips/mips.h +++ b/gcc/config/mips/mips.h @@ -2343,14 +2343,8 @@ extern enum reg_class mips_char_to_class[256]; We can't allow 64-bit float registers to change from a 32-bit mode to a 64-bit mode. */ -#define CLASS_CANNOT_CHANGE_MODE \ - (TARGET_BIG_ENDIAN ? FP_REGS \ - : (TARGET_FLOAT64 ? HI_AND_FP_REGS : HI_REG)) - -/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */ - -#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \ - (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)) +#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \ + mips_cannot_change_mode_class (FROM, TO) /* Stack layout; function entry, exit and calling. */ diff --git a/gcc/config/pa/pa64-regs.h b/gcc/config/pa/pa64-regs.h index 0af4c5fb270..2d0ebe3d172 100644 --- a/gcc/config/pa/pa64-regs.h +++ b/gcc/config/pa/pa64-regs.h @@ -232,12 +232,7 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FPUPPER_REGS, FP_REGS, {0x00000000, 0x10000000}, /* SHIFT_REGS */ \ {0xfffffffe, 0x1fffffff}} /* ALL_REGS */ -/* If defined, gives a class of registers that cannot be used as the - operand of a SUBREG that changes the mode of the object illegally. */ - -#define CLASS_CANNOT_CHANGE_MODE (FP_REGS) - -/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. +/* Defines invalid mode changes. SImode loads to floating-point registers are not zero-extended. The definition for LOAD_EXTEND_OP specifies that integer loads @@ -245,8 +240,9 @@ enum reg_class { NO_REGS, R1_REGS, GENERAL_REGS, FPUPPER_REGS, FP_REGS, we inhibit changes from SImode unless they are to a mode that is identical in size. */ -#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \ - ((FROM) == SImode && GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)) +#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \ + ((FROM) == SImode && GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \ + ? FP_REGS : NO_REGS) /* Return the class number of the smallest class containing reg number REGNO. This could be a conditional expression diff --git a/gcc/config/rs6000/rs6000.h b/gcc/config/rs6000/rs6000.h index 55805490d44..39ef154f046 100644 --- a/gcc/config/rs6000/rs6000.h +++ b/gcc/config/rs6000/rs6000.h @@ -1314,16 +1314,14 @@ enum reg_class ? ((GET_MODE_SIZE (MODE) + UNITS_PER_FP_WORD - 1) / UNITS_PER_FP_WORD) \ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) -/* If defined, gives a class of registers that cannot be used as the - operand of a SUBREG that changes the mode of the object illegally. */ -#define CLASS_CANNOT_CHANGE_MODE FLOAT_REGS +/* Return a class of registers that cannot change FROM mode to TO mode. */ -/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */ +#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \ + (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) ? FLOAT_REGS \ + : (SPE_VECTOR_MODE (FROM) + SPE_VECTOR_MODE (TO)) == 1 ? GENERAL_REGS \ + : NO_REGS) -#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \ - (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)) - /* Stack layout; function entry, exit and calling. */ /* Enumeration to give which calling sequence to use. */ diff --git a/gcc/config/s390/s390.h b/gcc/config/s390/s390.h index 009f8a4bcf9..268ee2f3445 100644 --- a/gcc/config/s390/s390.h +++ b/gcc/config/s390/s390.h @@ -330,10 +330,8 @@ do \ /* If a 4-byte value is loaded into a FPR, it is placed into the *upper* half of the register, not the lower. Therefore, we cannot use SUBREGs to switch between modes in FP registers. */ -#define CLASS_CANNOT_CHANGE_MODE FP_REGS -#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \ - (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO)) - +#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \ + (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) ? FP_REGS : NO_REGS) /* Register classes. */ diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index a2152efa2f4..a729462393e 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -126,6 +126,8 @@ extern int sh_pr_n_sets PARAMS ((void)); extern int sh_hard_regno_rename_ok PARAMS ((unsigned int, unsigned int)); extern int sh_cfun_interrupt_handler_p PARAMS ((void)); extern void sh_initialize_trampoline PARAMS ((rtx, rtx, rtx)); +extern enum reg_class sh_cannot_change_mode_class + PARAMS ((enum machine_mode, enum machine_mode)); #ifdef HARD_CONST extern void fpscr_set_from_mem PARAMS ((int, HARD_REG_SET)); diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index 4e6981bfbe4..d2cc47186d9 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -7733,4 +7733,26 @@ sh_expand_binop_v2sf (code, op0, op1, op2) emit_insn ((*fn) (op0, op1, op2, op, sel1, sel1, sel1)); } +/* Return the class of registers for which a mode change from FROM to TO + is invalid. */ +enum reg_class +sh_cannot_change_mode_class (from, to) + enum machine_mode from, to; +{ + if (GET_MODE_SIZE (from) != GET_MODE_SIZE (to)) + { + if (TARGET_LITTLE_ENDIAN) + { + if (GET_MODE_SIZE (to) < 8 || GET_MODE_SIZE (from) < 8) + return DF_REGS; + } + else + { + if (GET_MODE_SIZE (from) < 8) + return DF_HI_REGS; + } + } + return NO_REGS; +} + #include "gt-sh.h" diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index d0bbbdf0805..feadbb7d841 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -1372,14 +1372,8 @@ extern const enum reg_class reg_class_from_letter[]; /* ??? We need to renumber the internal numbers for the frnn registers when in little endian in order to allow mode size changes. */ -#define CLASS_CANNOT_CHANGE_MODE (TARGET_LITTLE_ENDIAN ? DF_REGS : DF_HI_REGS) - -/* Defines illegal mode changes for CLASS_CANNOT_CHANGE_MODE. */ - -#define CLASS_CANNOT_CHANGE_MODE_P(FROM,TO) \ - (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) \ - && ((TARGET_LITTLE_ENDIAN && GET_MODE_SIZE (TO) < 8) \ - || GET_MODE_SIZE (FROM) < 8)) +#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \ + sh_cannot_change_mode_class (FROM, TO) /* Stack layout; function entry, exit and calling. */ diff --git a/gcc/doc/tm.texi b/gcc/doc/tm.texi index 5ca0836de07..b8f2b934671 100644 --- a/gcc/doc/tm.texi +++ b/gcc/doc/tm.texi @@ -2561,25 +2561,22 @@ should be the maximum value of @code{HARD_REGNO_NREGS (@var{regno}, This macro helps control the handling of multiple-word values in the reload pass. -@item CLASS_CANNOT_CHANGE_MODE -If defined, a C expression for a class that contains registers for -which the compiler may not change modes arbitrarily. - -@item CLASS_CANNOT_CHANGE_MODE_P(@var{from}, @var{to}) -A C expression that is true if, for a register in -@code{CLASS_CANNOT_CHANGE_MODE}, the requested mode punning is invalid. +@item CANNOT_CHANGE_MODE_CLASS(@var{from}, @var{to}) +If defined, a C expression that returns a register class for which +a change from mode @var{from} to mode @var{to} is invalid, otherwise the +macro returns @code{NO_REGS}. For the example, loading 32-bit integer or floating-point objects into floating-point registers on the Alpha extends them to 64 bits. Therefore loading a 64-bit object and then storing it as a 32-bit object does not store the low-order 32 bits, as would be the case for a normal -register. Therefore, @file{alpha.h} defines @code{CLASS_CANNOT_CHANGE_MODE} -as @code{FLOAT_REGS} and @code{CLASS_CANNOT_CHANGE_MODE_P} restricts -mode changes to same-size modes. +register. Therefore, @file{alpha.h} defines @code{CANNOT_CHANGE_MODE_CLASS} +as below: -Compare this to IA-64, which extends floating-point values to 82-bits, -and stores 64-bit integers in a different format than 64-bit doubles. -Therefore @code{CLASS_CANNOT_CHANGE_MODE_P} is always true. +@example +#define CANNOT_CHANGE_MODE_CLASS \ + (GET_MODE_SIZE (FROM) != GET_MODE_SIZE (TO) ? FLOAT_REGS : NO_REGS) +@end example @end table Three other special macros describe which operands fit which constraint diff --git a/gcc/flow.c b/gcc/flow.c index d9e3ae3ce40..180796268c6 100644 --- a/gcc/flow.c +++ b/gcc/flow.c @@ -414,8 +414,8 @@ life_analysis (f, file, flags) FILE *file; int flags; { -#ifdef ELIMINABLE_REGS int i; +#ifdef ELIMINABLE_REGS static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS; #endif @@ -431,6 +431,13 @@ life_analysis (f, file, flags) SET_HARD_REG_BIT (elim_reg_set, FRAME_POINTER_REGNUM); #endif + +#ifdef CANNOT_CHANGE_MODE_CLASS + if (flags & PROP_REG_INFO) + for (i=0; i < NUM_MACHINE_MODES; ++i) + INIT_REG_SET (&subregs_of_mode[i]); +#endif + if (! optimize) flags &= ~(PROP_LOG_LINKS | PROP_AUTOINC | PROP_ALLOW_CFG_CHANGES); @@ -3813,12 +3820,11 @@ mark_used_regs (pbi, x, cond, insn) break; case SUBREG: -#ifdef CLASS_CANNOT_CHANGE_MODE +#ifdef CANNOT_CHANGE_MODE_CLASS if (GET_CODE (SUBREG_REG (x)) == REG - && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER - && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (x), - GET_MODE (SUBREG_REG (x)))) - REG_CHANGES_MODE (REGNO (SUBREG_REG (x))) = 1; + && REGNO (SUBREG_REG (x)) >= FIRST_PSEUDO_REGISTER) + SET_REGNO_REG_SET (&subregs_of_mode[GET_MODE (x)], + REGNO (SUBREG_REG (x))); #endif /* While we're here, optimize this case. */ @@ -3862,13 +3868,12 @@ mark_used_regs (pbi, x, cond, insn) || GET_CODE (testreg) == SIGN_EXTRACT || GET_CODE (testreg) == SUBREG) { -#ifdef CLASS_CANNOT_CHANGE_MODE +#ifdef CANNOT_CHANGE_MODE_CLASS if (GET_CODE (testreg) == SUBREG && GET_CODE (SUBREG_REG (testreg)) == REG - && REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER - && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (testreg)), - GET_MODE (testreg))) - REG_CHANGES_MODE (REGNO (SUBREG_REG (testreg))) = 1; + && REGNO (SUBREG_REG (testreg)) >= FIRST_PSEUDO_REGISTER) + SET_REGNO_REG_SET (&subregs_of_mode[GET_MODE (testreg)], + REGNO (SUBREG_REG (testreg))); #endif /* Modifying a single register in an alternate mode diff --git a/gcc/global.c b/gcc/global.c index a1000962380..dfbe0388d01 100644 --- a/gcc/global.c +++ b/gcc/global.c @@ -974,10 +974,7 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying) int retrying; { int i, best_reg, pass; -#ifdef HARD_REG_SET - register /* Declare it register if it's a scalar. */ -#endif - HARD_REG_SET used, used1, used2; + HARD_REG_SET used, used1, used2; enum reg_class class = (alt_regs_p ? reg_alternate_class (allocno[num].reg) @@ -1001,10 +998,8 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying) IOR_HARD_REG_SET (used1, allocno[num].hard_reg_conflicts); -#ifdef CLASS_CANNOT_CHANGE_MODE - if (REG_CHANGES_MODE (allocno[num].reg)) - IOR_HARD_REG_SET (used1, - reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE]); +#ifdef CANNOT_CHANGE_MODE_CLASS + cannot_change_mode_set_regs (&used1, mode, allocno[num].reg); #endif /* Try each hard reg to see if it fits. Do this in two passes. @@ -1200,11 +1195,9 @@ find_reg (num, losers, alt_regs_p, accept_call_clobbered, retrying) && (allocno[num].calls_crossed == 0 || accept_call_clobbered || ! HARD_REGNO_CALL_PART_CLOBBERED (regno, mode)) -#ifdef CLASS_CANNOT_CHANGE_MODE - && ! (REG_CHANGES_MODE (allocno[num].reg) - && (TEST_HARD_REG_BIT - (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], - regno))) +#ifdef CANNOT_CHANGE_MODE_CLASS + && ! invalid_mode_change_p (regno, REGNO_REG_CLASS (regno), + mode) #endif ) { diff --git a/gcc/hard-reg-set.h b/gcc/hard-reg-set.h index 9cdd96835c9..712a26791f3 100644 --- a/gcc/hard-reg-set.h +++ b/gcc/hard-reg-set.h @@ -488,4 +488,11 @@ extern int n_non_fixed_regs; extern const char * reg_names[FIRST_PSEUDO_REGISTER]; +/* Given a hard REGN a FROM mode and a TO mode, return non-zero if + REGN cannot change modes between the specified modes. */ +#define REG_CANNOT_CHANGE_MODE_P(REGN, FROM, TO) \ + (TEST_HARD_REG_BIT \ + (reg_class_contents[(int) CANNOT_CHANGE_MODE_CLASS (FROM, TO)], \ + REGN)) + #endif /* ! GCC_HARD_REG_SET_H */ diff --git a/gcc/local-alloc.c b/gcc/local-alloc.c index 9c94924aec9..c2d6c0c610b 100644 --- a/gcc/local-alloc.c +++ b/gcc/local-alloc.c @@ -61,10 +61,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "config.h" #include "system.h" +#include "hard-reg-set.h" #include "rtl.h" #include "tm_p.h" #include "flags.h" -#include "hard-reg-set.h" #include "basic-block.h" #include "regs.h" #include "function.h" @@ -144,12 +144,6 @@ struct qty or -1 if none was found. */ short phys_reg; - - /* Nonzero if this quantity has been used in a SUBREG in some - way that is illegal. */ - - char changes_mode; - }; static struct qty *qty; @@ -328,7 +322,6 @@ alloc_qty (regno, mode, size, birth) qty[qtyno].alternate_class = reg_alternate_class (regno); qty[qtyno].n_refs = REG_N_REFS (regno); qty[qtyno].freq = REG_FREQ (regno); - qty[qtyno].changes_mode = REG_CHANGES_MODE (regno); } /* Main entry point of this file. */ @@ -2026,9 +2019,6 @@ update_qty_class (qtyno, reg) rclass = reg_alternate_class (reg); if (reg_class_subset_p (rclass, qty[qtyno].alternate_class)) qty[qtyno].alternate_class = rclass; - - if (REG_CHANGES_MODE (reg)) - qty[qtyno].changes_mode = 1; } /* Handle something which alters the value of an rtx REG. @@ -2182,11 +2172,7 @@ find_free_reg (class, mode, qtyno, accept_call_clobbered, just_try_suggested, int born_index, dead_index; { int i, ins; -#ifdef HARD_REG_SET - /* Declare it register if it's a scalar. */ - register -#endif - HARD_REG_SET used, first_used; + HARD_REG_SET first_used, used; #ifdef ELIMINABLE_REGS static const struct {const int from, to; } eliminables[] = ELIMINABLE_REGS; #endif @@ -2234,10 +2220,8 @@ find_free_reg (class, mode, qtyno, accept_call_clobbered, just_try_suggested, SET_HARD_REG_BIT (used, FRAME_POINTER_REGNUM); #endif -#ifdef CLASS_CANNOT_CHANGE_MODE - if (qty[qtyno].changes_mode) - IOR_HARD_REG_SET (used, - reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE]); +#ifdef CANNOT_CHANGE_MODE_CLASS + cannot_change_mode_set_regs (&used, mode, qty[qtyno].first_reg); #endif /* Normally, the registers that can be used for the first register in diff --git a/gcc/recog.c b/gcc/recog.c index 6b6117fa5c5..b40867bf7a3 100644 --- a/gcc/recog.c +++ b/gcc/recog.c @@ -1083,13 +1083,10 @@ register_operand (op, mode) if (! reload_completed && GET_CODE (sub) == MEM) return general_operand (op, mode); -#ifdef CLASS_CANNOT_CHANGE_MODE +#ifdef CANNOT_CHANGE_MODE_CLASS if (GET_CODE (sub) == REG && REGNO (sub) < FIRST_PSEUDO_REGISTER - && (TEST_HARD_REG_BIT - (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], - REGNO (sub))) - && CLASS_CANNOT_CHANGE_MODE_P (mode, GET_MODE (sub)) + && REG_CANNOT_CHANGE_MODE_P (REGNO (sub), mode, GET_MODE (sub)) && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_INT && GET_MODE_CLASS (GET_MODE (sub)) != MODE_COMPLEX_FLOAT) return 0; diff --git a/gcc/regclass.c b/gcc/regclass.c index 28c2a6f1081..20c7d3b03d1 100644 --- a/gcc/regclass.c +++ b/gcc/regclass.c @@ -26,10 +26,10 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "config.h" #include "system.h" +#include "hard-reg-set.h" #include "rtl.h" #include "expr.h" #include "tm_p.h" -#include "hard-reg-set.h" #include "flags.h" #include "basic-block.h" #include "regs.h" @@ -227,20 +227,11 @@ static char *in_inc_dec; #endif /* FORBIDDEN_INC_DEC_CLASSES */ -#ifdef CLASS_CANNOT_CHANGE_MODE - -/* These are the classes containing only registers that can be used in - a SUBREG expression that changes the mode of the register in some - way that is illegal. */ - -static int class_can_change_mode[N_REG_CLASSES]; - -/* Registers, including pseudos, which change modes in some way that - is illegal. */ - -static regset reg_changes_mode; - -#endif /* CLASS_CANNOT_CHANGE_MODE */ +#ifdef CANNOT_CHANGE_MODE_CLASS +/* All registers that have been subreged. Indexed by mode, where each + entry is a regset of registers. */ +regset_head subregs_of_mode [NUM_MACHINE_MODES]; +#endif /* Sample MEM values for use by memory_move_secondary_cost. */ @@ -549,22 +540,6 @@ init_reg_sets_1 () may_move_out_cost[m][i][j] = 65536; } } - -#ifdef CLASS_CANNOT_CHANGE_MODE - { - HARD_REG_SET c; - COMPL_HARD_REG_SET (c, reg_class_contents[CLASS_CANNOT_CHANGE_MODE]); - - for (i = 0; i < N_REG_CLASSES; i++) - { - GO_IF_HARD_REG_SUBSET (reg_class_contents[i], c, ok_class); - class_can_change_mode [i] = 0; - continue; - ok_class: - class_can_change_mode [i] = 1; - } - } -#endif /* CLASS_CANNOT_CHANGE_MODE */ } /* Compute the table of register modes. @@ -952,9 +927,9 @@ dump_regclass (dump) && (!in_inc_dec[i] || !forbidden_inc_dec_class[(enum reg_class) class]) #endif -#ifdef CLASS_CANNOT_CHANGE_MODE - && (!REGNO_REG_SET_P (reg_changes_mode, i) - || class_can_change_mode [(enum reg_class) class]) +#ifdef CANNOT_CHANGE_MODE_CLASS + && ! invalid_mode_change_p (i, (enum reg_class) class, + PSEUDO_REGNO_MODE (i)) #endif ) fprintf (dump, " %s:%i", reg_class_names[class], @@ -994,15 +969,7 @@ record_operand_costs (insn, op_costs, reg_pref) op_costs[i] = init_cost; if (GET_CODE (recog_data.operand[i]) == SUBREG) - { - rtx inner = SUBREG_REG (recog_data.operand[i]); -#ifdef CLASS_CANNOT_CHANGE_MODE - if (GET_CODE (inner) == REG - && CLASS_CANNOT_CHANGE_MODE_P (modes[i], GET_MODE (inner))) - SET_REGNO_REG_SET (reg_changes_mode, REGNO (inner)); -#endif - recog_data.operand[i] = inner; - } + recog_data.operand[i] = SUBREG_REG (recog_data.operand[i]); if (GET_CODE (recog_data.operand[i]) == MEM) record_address_regs (XEXP (recog_data.operand[i], 0), @@ -1193,10 +1160,6 @@ regclass (f, nregs, dump) costs = (struct costs *) xmalloc (nregs * sizeof (struct costs)); -#ifdef CLASS_CANNOT_CHANGE_MODE - reg_changes_mode = BITMAP_XMALLOC (); -#endif - #ifdef FORBIDDEN_INC_DEC_CLASSES in_inc_dec = (char *) xmalloc (nregs); @@ -1329,9 +1292,9 @@ regclass (f, nregs, dump) #ifdef FORBIDDEN_INC_DEC_CLASSES || (in_inc_dec[i] && forbidden_inc_dec_class[class]) #endif -#ifdef CLASS_CANNOT_CHANGE_MODE - || (REGNO_REG_SET_P (reg_changes_mode, i) - && ! class_can_change_mode [class]) +#ifdef CANNOT_CHANGE_MODE_CLASS + || invalid_mode_change_p (i, (enum reg_class) class, + PSEUDO_REGNO_MODE (i)) #endif ) ; @@ -1359,9 +1322,9 @@ regclass (f, nregs, dump) #ifdef FORBIDDEN_INC_DEC_CLASSES && ! (in_inc_dec[i] && forbidden_inc_dec_class[class]) #endif -#ifdef CLASS_CANNOT_CHANGE_MODE - && ! (REGNO_REG_SET_P (reg_changes_mode, i) - && ! class_can_change_mode [class]) +#ifdef CANNOT_CHANGE_MODE_CLASS + && ! invalid_mode_change_p (i, (enum reg_class) class, + PSEUDO_REGNO_MODE (i)) #endif ) alt = reg_class_subunion[(int) alt][class]; @@ -1394,9 +1357,6 @@ regclass (f, nregs, dump) #ifdef FORBIDDEN_INC_DEC_CLASSES free (in_inc_dec); -#endif -#ifdef CLASS_CANNOT_CHANGE_MODE - BITMAP_XFREE (reg_changes_mode); #endif free (costs); } @@ -2643,4 +2603,46 @@ regset_release_memory () bitmap_release_memory (); } +#ifdef CANNOT_CHANGE_MODE_CLASS +/* Set bits in *USED which correspond to registers which can't change + their mode from FROM to any mode in which REGNO was encountered. */ + +void +cannot_change_mode_set_regs (used, from, regno) + HARD_REG_SET *used; + enum machine_mode from; + unsigned int regno; +{ + enum machine_mode to; + enum reg_class class; + + for (to = VOIDmode; to < MAX_MACHINE_MODE; ++to) + if (REGNO_REG_SET_P (&subregs_of_mode[to], regno)) + { + class = CANNOT_CHANGE_MODE_CLASS (from, to); + if (class != NO_REGS) + IOR_HARD_REG_SET (*used, reg_class_contents [(int) class]); + } +} + +/* Return 1 if REGNO has had an invalid mode change in CLASS from FROM + mode. */ + +bool +invalid_mode_change_p (regno, class, from_mode) + unsigned int regno; + enum reg_class class; + enum machine_mode from_mode; +{ + enum machine_mode to_mode; + + for (to_mode = 0; to_mode < NUM_MACHINE_MODES; ++to_mode) + if (REGNO_REG_SET_P (&subregs_of_mode[(int) to_mode], regno) + && reg_classes_intersect_p + (class, CANNOT_CHANGE_MODE_CLASS (from_mode, to_mode))) + return 1; + return 0; +} +#endif /* CANNOT_CHANGE_MODE_CLASS */ + #include "gt-regclass.h" diff --git a/gcc/regrename.c b/gcc/regrename.c index ac1043d38b9..9b7dfd6d3c5 100644 --- a/gcc/regrename.c +++ b/gcc/regrename.c @@ -1313,10 +1313,8 @@ mode_change_ok (orig_mode, new_mode, regno) if (GET_MODE_SIZE (orig_mode) < GET_MODE_SIZE (new_mode)) return false; -#ifdef CLASS_CANNOT_CHANGE_MODE - if (TEST_HARD_REG_BIT (reg_class_contents[CLASS_CANNOT_CHANGE_MODE], regno) - && CLASS_CANNOT_CHANGE_MODE_P (orig_mode, new_mode)) - return false; +#ifdef CANNOT_CHANGE_MODE_CLASS + return !REG_CANNOT_CHANGE_MODE_P (regno, orig_mode, new_mode); #endif return true; diff --git a/gcc/regs.h b/gcc/regs.h index 0b35f07dee0..4a78212ec80 100644 --- a/gcc/regs.h +++ b/gcc/regs.h @@ -21,6 +21,8 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "varray.h" +#include "hard-reg-set.h" +#include "basic-block.h" #define REG_BYTES(R) mode_size[(int) GET_MODE (R)] @@ -64,6 +66,8 @@ typedef struct reg_info_def extern varray_type reg_n_info; +extern regset_head subregs_of_mode [NUM_MACHINE_MODES]; + /* Indexed by n, gives number of times (REG n) is used or set. */ #define REG_N_REFS(N) (VARRAY_REG (reg_n_info, N)->refs) @@ -104,13 +108,6 @@ extern varray_type reg_n_info; #define REG_N_DEATHS(N) (VARRAY_REG (reg_n_info, N)->deaths) -/* Indexed by N; says whether a pseudo register N was ever used - within a SUBREG that changes the mode of the reg in some way - that is illegal for a given class (usually floating-point) - of registers. */ - -#define REG_CHANGES_MODE(N) (VARRAY_REG (reg_n_info, N)->changes_mode) - /* Get the number of consecutive words required to hold pseudo-reg N. */ #define PSEUDO_REGNO_SIZE(N) \ diff --git a/gcc/reload.c b/gcc/reload.c index 97b35218caa..2b119886d4b 100644 --- a/gcc/reload.c +++ b/gcc/reload.c @@ -967,9 +967,10 @@ push_reload (in, out, inloc, outloc, class, if (in != 0 && GET_CODE (in) == SUBREG && (subreg_lowpart_p (in) || strict_low) -#ifdef CLASS_CANNOT_CHANGE_MODE - && (class != CLASS_CANNOT_CHANGE_MODE - || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)), inmode)) +#ifdef CANNOT_CHANGE_MODE_CLASS + && !reg_classes_intersect_p + (class, CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (in)), + inmode)) #endif && (CONSTANT_P (SUBREG_REG (in)) || GET_CODE (SUBREG_REG (in)) == PLUS @@ -1016,14 +1017,11 @@ push_reload (in, out, inloc, outloc, class, SUBREG_REG (in)) == NO_REGS)) #endif -#ifdef CLASS_CANNOT_CHANGE_MODE +#ifdef CANNOT_CHANGE_MODE_CLASS || (GET_CODE (SUBREG_REG (in)) == REG && REGNO (SUBREG_REG (in)) < FIRST_PSEUDO_REGISTER - && (TEST_HARD_REG_BIT - (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], - REGNO (SUBREG_REG (in)))) - && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (in)), - inmode)) + && REG_CANNOT_CHANGE_MODE_P + (REGNO (SUBREG_REG (in)), GET_MODE (SUBREG_REG (in)), inmode)) #endif )) { @@ -1081,10 +1079,10 @@ push_reload (in, out, inloc, outloc, class, and in that case the constraint should label it input-output.) */ if (out != 0 && GET_CODE (out) == SUBREG && (subreg_lowpart_p (out) || strict_low) -#ifdef CLASS_CANNOT_CHANGE_MODE - && (class != CLASS_CANNOT_CHANGE_MODE - || ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)), - outmode)) +#ifdef CANNOT_CHANGE_MODE_CLASS + && !reg_classes_intersect_p + (class, CANNOT_CHANGE_MODE_CLASS (GET_MODE (SUBREG_REG (out)), + outmode)) #endif && (CONSTANT_P (SUBREG_REG (out)) || strict_low @@ -1118,14 +1116,12 @@ push_reload (in, out, inloc, outloc, class, SUBREG_REG (out)) == NO_REGS)) #endif -#ifdef CLASS_CANNOT_CHANGE_MODE +#ifdef CANNOT_CHANGE_MODE_CLASS || (GET_CODE (SUBREG_REG (out)) == REG && REGNO (SUBREG_REG (out)) < FIRST_PSEUDO_REGISTER - && (TEST_HARD_REG_BIT - (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], - REGNO (SUBREG_REG (out)))) - && CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (SUBREG_REG (out)), - outmode)) + && REG_CANNOT_CHANGE_MODE_P (REGNO (SUBREG_REG (out)), + GET_MODE (SUBREG_REG (out)), + outmode)) #endif )) { diff --git a/gcc/reload1.c b/gcc/reload1.c index 65ee2749a3c..2704dadab4d 100644 --- a/gcc/reload1.c +++ b/gcc/reload1.c @@ -5490,16 +5490,15 @@ choose_reload_regs (chain) GET_MODE_CLASS (mode)); if ( -#ifdef CLASS_CANNOT_CHANGE_MODE - (TEST_HARD_REG_BIT - (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], i) - ? ! CLASS_CANNOT_CHANGE_MODE_P (GET_MODE (last_reg), - need_mode) - : (GET_MODE_SIZE (GET_MODE (last_reg)) - >= GET_MODE_SIZE (need_mode))) -#else +#ifdef CANNOT_CHANGE_MODE_CLASS + (!REG_CANNOT_CHANGE_MODE_P (i, GET_MODE (last_reg), + need_mode) + || +#endif (GET_MODE_SIZE (GET_MODE (last_reg)) >= GET_MODE_SIZE (need_mode)) +#ifdef CANNOT_CHANGE_MODE_CLASS + ) #endif && reg_reloaded_contents[i] == regno && TEST_HARD_REG_BIT (reg_reloaded_valid, i) diff --git a/gcc/rtl.h b/gcc/rtl.h index 9aada8286e5..1d71ec90ce4 100644 --- a/gcc/rtl.h +++ b/gcc/rtl.h @@ -2092,6 +2092,7 @@ extern int global_alloc PARAMS ((FILE *)); extern void dump_global_regs PARAMS ((FILE *)); #endif #ifdef HARD_CONST +/* Yes, this ifdef is silly, but HARD_REG_SET is not always defined. */ extern void retry_global_alloc PARAMS ((int, HARD_REG_SET)); #endif extern void build_insn_chain PARAMS ((rtx)); @@ -2109,6 +2110,14 @@ extern void regclass PARAMS ((rtx, int, FILE *)); extern void reg_scan PARAMS ((rtx, unsigned int, int)); extern void reg_scan_update PARAMS ((rtx, rtx, unsigned int)); extern void fix_register PARAMS ((const char *, int, int)); +#ifdef HARD_CONST +extern void cannot_change_mode_set_regs PARAMS ((HARD_REG_SET *, + enum machine_mode, + unsigned int)); +#endif +extern bool invalid_mode_change_p PARAMS ((unsigned int, + enum reg_class, + enum machine_mode)); extern int delete_null_pointer_checks PARAMS ((rtx)); @@ -2269,4 +2278,5 @@ extern void invert_br_probabilities PARAMS ((rtx)); extern bool expensive_function_p PARAMS ((int)); /* In tracer.c */ extern void tracer PARAMS ((void)); + #endif /* ! GCC_RTL_H */ diff --git a/gcc/simplify-rtx.c b/gcc/simplify-rtx.c index 52a92504a00..212d3b90236 100644 --- a/gcc/simplify-rtx.c +++ b/gcc/simplify-rtx.c @@ -2586,15 +2586,12 @@ simplify_subreg (outermode, op, innermode, byte) if (REG_P (op) && (! REG_FUNCTION_VALUE_P (op) || ! rtx_equal_function_value_matters) -#ifdef CLASS_CANNOT_CHANGE_MODE - && ! (CLASS_CANNOT_CHANGE_MODE_P (outermode, innermode) - && GET_MODE_CLASS (innermode) != MODE_COMPLEX_INT - && GET_MODE_CLASS (innermode) != MODE_COMPLEX_FLOAT - && (TEST_HARD_REG_BIT - (reg_class_contents[(int) CLASS_CANNOT_CHANGE_MODE], - REGNO (op)))) -#endif && REGNO (op) < FIRST_PSEUDO_REGISTER +#ifdef CANNOT_CHANGE_MODE_CLASS + && ! (REG_CANNOT_CHANGE_MODE_P (REGNO (op), outermode, innermode) + && GET_MODE_CLASS (innermode) != MODE_COMPLEX_INT + && GET_MODE_CLASS (innermode) != MODE_COMPLEX_FLOAT) +#endif && ((reload_completed && !frame_pointer_needed) || (REGNO (op) != FRAME_POINTER_REGNUM #if HARD_FRAME_POINTER_REGNUM != FRAME_POINTER_REGNUM