Index: sparc-protos.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc-protos.h,v retrieving revision 1.35 diff -c -p -d -r1.35 sparc-protos.h *** sparc-protos.h 17 Jun 2003 01:00:44 -0000 1.35 --- sparc-protos.h 17 Jun 2003 05:53:13 -0000 *************** extern rtx gen_df_reg PARAMS ((rtx, int) *** 122,125 **** --- 122,132 ---- extern int sparc_extra_constraint_check PARAMS ((rtx, int, int)); #endif /* RTX_CODE */ + extern enum reg_class sparc_preferred_reload_class (rtx, enum reg_class); + extern enum reg_class sparc_secondary_reload_class(enum reg_class class, + enum machine_mode mode, + rtx, bool); + extern bool sparc_cannot_change_mode_class (enum machine_mode, + enum machine_mode, enum reg_class); + #endif /* __SPARC_PROTOS_H__ */ Index: sparc.c =================================================================== RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.c,v retrieving revision 1.247 diff -c -p -d -r1.247 sparc.c *** sparc.c 17 Jun 2003 00:39:20 -0000 1.247 --- sparc.c 17 Jun 2003 05:53:15 -0000 *************** sparc_init_modes () *** 3582,3599 **** /* Initialize the array used by REGNO_REG_CLASS. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { if (i < 16 && TARGET_V8PLUS) ! sparc_regno_reg_class[i] = I64_REGS; else if (i < 32 || i == FRAME_POINTER_REGNUM) ! sparc_regno_reg_class[i] = GENERAL_REGS; ! else if (i < 64) ! sparc_regno_reg_class[i] = FP_REGS; else if (i < 96) ! sparc_regno_reg_class[i] = EXTRA_FP_REGS; else if (i < 100) ! sparc_regno_reg_class[i] = FPCC_REGS; ! else ! sparc_regno_reg_class[i] = NO_REGS; } } --- 3582,3606 ---- /* Initialize the array used by REGNO_REG_CLASS. */ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) { + enum reg_class c = NO_REGS; + if (i < 16 && TARGET_V8PLUS) ! c = I64_REGS; else if (i < 32 || i == FRAME_POINTER_REGNUM) ! c = GENERAL_REGS; else if (i < 96) ! { ! if (i % 4 == 0) ! c = FP_Q_REGS; ! else if (i % 2 == 0) ! c = FP_D_REGS; ! else if (i < 64) ! c = FP_S_REGS; ! } else if (i < 100) ! c = FPCC_REGS; ! ! sparc_regno_reg_class[i] = c; } } *************** output_sibcall (insn, call_operand) *** 4299,4304 **** --- 4306,4398 ---- else fputs ("\t restore\n", asm_out_file); return ""; + } + + /* Given an rtx X being reloaded into a reg required to be + in class CLASS, return the class of reg to actually use. + In general this is just CLASS; but on some machines + in some cases it is preferable to use a more restrictive class. */ + /* - We can't load constants into FP registers. + - We can't load FP constants into integer registers when soft-float, + because there is no soft-float pattern with a r/F constraint. + - We can't load FP constants into integer registers for TFmode unless + it is 0.0L, because there is no movtf pattern with a r/F constraint. + - Try and reload integer constants (symbolic or otherwise) back into + registers directly, rather than having them dumped to memory. */ + + enum reg_class + sparc_preferred_reload_class (rtx x, enum reg_class class) + { + enum machine_mode mode = GET_MODE (x); + + if (!CONSTANT_P (x)) + return class; + + if (FP_REG_CLASS_P (class) + || class == GENERAL_OR_FP_REGS + || (GET_MODE_CLASS (mode) == MODE_FLOAT && ! TARGET_FPU) + || (mode == TFmode && ! fp_zero_operand (x, TFmode))) + return NO_REGS; + + if (!FP_REG_CLASS_P (class) && GET_MODE_CLASS (mode) == MODE_INT) + return GENERAL_REGS; + + return class; + } + + /* Return the register class of a scratch register needed to load IN into + a register of class CLASS in MODE. + + We need a temporary when loading/storing a HImode/QImode value + between memory and the FPU registers. This can happen when combine puts + a paradoxical subreg in a float/fix conversion insn. + + We need a temporary when loading/storing a DFmode value between + unaligned memory and the upper FPU registers. */ + + enum reg_class + sparc_secondary_reload_class(enum reg_class class, enum machine_mode mode, + rtx x, bool in_p ATTRIBUTE_UNUSED) + { + if (FP_REG_CLASS_P (class) + && (mode == HImode || mode == QImode) + && (GET_CODE (x) == MEM + || ((GET_CODE (x) == REG || GET_CODE (x) == SUBREG) + && true_regnum (x) == -1))) + return GENERAL_REGS; + + if (class == FP_D_REGS && mode == DFmode + && GET_CODE (x) == MEM && TARGET_ARCH32 + && ! mem_min_alignment (x, 8)) + return FP_S_REGS; + + if (((TARGET_CM_MEDANY && symbolic_operand (x, mode)) + || (TARGET_CM_EMBMEDANY && text_segment_operand (x, mode))) + && !flag_pic) + return GENERAL_REGS; + + return NO_REGS; + } + + bool + sparc_cannot_change_mode_class (enum machine_mode from, + enum machine_mode to, enum reg_class class) + { + unsigned int to_s = GET_MODE_SIZE (to); + unsigned int from_s = GET_MODE_SIZE (from); + + if (to_s <= from_s) + return false; + + switch (class) + { + case FP_D_REGS: + return to_s == 16; + case FP_S_REGS: + return to_s == 8; + default: + return false; + } } /* Functions for handling argument passing. Index: sparc.h =================================================================== RCS file: /cvs/gcc/gcc/gcc/config/sparc/sparc.h,v retrieving revision 1.229 diff -c -p -d -r1.229 sparc.h *** sparc.h 14 Jun 2003 21:47:45 -0000 1.229 --- sparc.h 17 Jun 2003 05:53:16 -0000 *************** extern int sparc_mode_class[]; *** 1230,1262 **** ??? Should %fcc[0123] be handled similarly? */ ! enum reg_class { NO_REGS, FPCC_REGS, I64_REGS, GENERAL_REGS, FP_REGS, ! EXTRA_FP_REGS, GENERAL_OR_FP_REGS, GENERAL_OR_EXTRA_FP_REGS, ! ALL_REGS, LIM_REG_CLASSES }; #define N_REG_CLASSES (int) LIM_REG_CLASSES /* Give names of register classes as strings for dump file. */ #define REG_CLASS_NAMES \ ! { "NO_REGS", "FPCC_REGS", "I64_REGS", "GENERAL_REGS", "FP_REGS", \ ! "EXTRA_FP_REGS", "GENERAL_OR_FP_REGS", "GENERAL_OR_EXTRA_FP_REGS", \ ! "ALL_REGS" } ! /* Define which registers fit in which classes. ! This is an initializer for a vector of HARD_REG_SET ! of length N_REG_CLASSES. */ #define REG_CLASS_CONTENTS \ ! {{0, 0, 0, 0}, /* NO_REGS */ \ ! {0, 0, 0, 0xf}, /* FPCC_REGS */ \ ! {0xffff, 0, 0, 0}, /* I64_REGS */ \ ! {-1, 0, 0, 0x20}, /* GENERAL_REGS */ \ ! {0, -1, 0, 0}, /* FP_REGS */ \ ! {0, -1, -1, 0}, /* EXTRA_FP_REGS */ \ ! {-1, -1, 0, 0x20}, /* GENERAL_OR_FP_REGS */ \ ! {-1, -1, -1, 0x20}, /* GENERAL_OR_EXTRA_FP_REGS */ \ ! {-1, -1, -1, 0x3f}} /* ALL_REGS */ /* The same information, inverted: Return the class number of the smallest class containing --- 1230,1261 ---- ??? Should %fcc[0123] be handled similarly? */ ! enum reg_class { NO_REGS, FPCC_REGS, I64_REGS, GENERAL_REGS, ! FP_Q_REGS, FP_D_REGS, FP_S_REGS, ! GENERAL_OR_FP_REGS, ALL_REGS, LIM_REG_CLASSES }; #define N_REG_CLASSES (int) LIM_REG_CLASSES /* Give names of register classes as strings for dump file. */ #define REG_CLASS_NAMES \ ! { "NO_REGS", "FPCC_REGS", "I64_REGS", "GENERAL_REGS", \ ! "FP_Q_REGS", "FP_D_REGS", "FP_S_REGS", \ ! "GENERAL_OR_FP_REGS", "ALL_REGS" } ! /* Define which registers fit in which classes. This is an initializer ! for a vector of HARD_REG_SET of length N_REG_CLASSES. */ #define REG_CLASS_CONTENTS \ ! {{0x00000000, 0x00000000, 0x00000000, 0x00}, /* NO_REGS */ \ ! {0x00000000, 0x00000000, 0x00000000, 0x0f}, /* FPCC_REGS */ \ ! {0x0000ffff, 0x00000000, 0x00000000, 0x00}, /* I64_REGS */ \ ! {0xffffffff, 0x00000000, 0x00000000, 0x20}, /* GENERAL_REGS */ \ ! {0x00000000, 0x11111111, 0x11111111, 0x00}, /* FP_Q_REGS */ \ ! {0x00000000, 0x55555555, 0x55555555, 0x00}, /* FP_D_REGS */ \ ! {0x00000000, 0xffffffff, 0x00000000, 0x00}, /* FP_S_REGS */ \ ! {0xffffffff, 0xffffffff, 0xffffffff, 0x20}, /* GENERAL_OR_FP_REGS */ \ ! {0xffffffff, 0xffffffff, 0xffffffff, 0x3f}} /* ALL_REGS */ /* The same information, inverted: Return the class number of the smallest class containing *************** extern char leaf_reg_remap[]; *** 1356,1384 **** #define INDEX_REG_CLASS GENERAL_REGS #define BASE_REG_CLASS GENERAL_REGS ! /* Local macro to handle the two v9 classes of FP regs. */ ! #define FP_REG_CLASS_P(CLASS) ((CLASS) == FP_REGS || (CLASS) == EXTRA_FP_REGS) /* Get reg_class from a letter such as appears in the machine description. - In the not-v9 case, coerce v9's 'e' class to 'f', so we can use 'e' in the - .md file for v8 and v9. 'd' and 'b' are used for single and double precision VIS operations, if TARGET_VIS. 'h' is used for V8+ 64 bit global and out registers. */ #define REG_CLASS_FROM_LETTER(C) \ ! (TARGET_V9 \ ! ? ((C) == 'f' ? FP_REGS \ ! : (C) == 'e' ? EXTRA_FP_REGS \ ! : (C) == 'c' ? FPCC_REGS \ ! : ((C) == 'd' && TARGET_VIS) ? FP_REGS\ ! : ((C) == 'b' && TARGET_VIS) ? EXTRA_FP_REGS\ ! : ((C) == 'h' && TARGET_V8PLUS) ? I64_REGS\ ! : NO_REGS) \ ! : ((C) == 'f' ? FP_REGS \ ! : (C) == 'e' ? FP_REGS \ ! : (C) == 'c' ? FPCC_REGS \ ! : NO_REGS)) /* The letters I, J, K, L and M in a register constraint string can be used to stand for particular ranges of immediate operands. --- 1355,1377 ---- #define INDEX_REG_CLASS GENERAL_REGS #define BASE_REG_CLASS GENERAL_REGS ! /* Local macro to handle the classes of FP regs. */ ! #define FP_REG_CLASS_P(CLASS) \ ! ((CLASS) >= FP_Q_REGS && (CLASS) <= FP_S_REGS) /* Get reg_class from a letter such as appears in the machine description. 'd' and 'b' are used for single and double precision VIS operations, if TARGET_VIS. 'h' is used for V8+ 64 bit global and out registers. */ #define REG_CLASS_FROM_LETTER(C) \ ! ((C) == 'f' ? FP_S_REGS \ ! : (C) == 'e' ? FP_D_REGS \ ! : (C) == 'c' ? FPCC_REGS \ ! : ((C) == 'd' && TARGET_VIS) ? FP_S_REGS \ ! : ((C) == 'b' && TARGET_VIS) ? FP_D_REGS \ ! : ((C) == 'h' && TARGET_V8PLUS) ? I64_REGS \ ! : NO_REGS) /* The letters I, J, K, L and M in a register constraint string can be used to stand for particular ranges of immediate operands. *************** extern char leaf_reg_remap[]; *** 1428,1508 **** : (C) == 'O' ? arith_double_4096_operand (VALUE, DImode) \ : 0) ! /* Given an rtx X being reloaded into a reg required to be ! in class CLASS, return the class of reg to actually use. ! In general this is just CLASS; but on some machines ! in some cases it is preferable to use a more restrictive class. */ ! /* - We can't load constants into FP registers. ! - We can't load FP constants into integer registers when soft-float, ! because there is no soft-float pattern with a r/F constraint. ! - We can't load FP constants into integer registers for TFmode unless ! it is 0.0L, because there is no movtf pattern with a r/F constraint. ! - Try and reload integer constants (symbolic or otherwise) back into ! registers directly, rather than having them dumped to memory. */ ! ! #define PREFERRED_RELOAD_CLASS(X,CLASS) \ ! (CONSTANT_P (X) \ ! ? ((FP_REG_CLASS_P (CLASS) \ ! || (CLASS) == GENERAL_OR_FP_REGS \ ! || (CLASS) == GENERAL_OR_EXTRA_FP_REGS \ ! || (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \ ! && ! TARGET_FPU) \ ! || (GET_MODE (X) == TFmode \ ! && ! fp_zero_operand (X, TFmode))) \ ! ? NO_REGS \ ! : (!FP_REG_CLASS_P (CLASS) \ ! && GET_MODE_CLASS (GET_MODE (X)) == MODE_INT) \ ! ? GENERAL_REGS \ ! : (CLASS)) \ ! : (CLASS)) ! ! /* Return the register class of a scratch register needed to load IN into ! a register of class CLASS in MODE. ! ! We need a temporary when loading/storing a HImode/QImode value ! between memory and the FPU registers. This can happen when combine puts ! a paradoxical subreg in a float/fix conversion insn. ! We need a temporary when loading/storing a DFmode value between ! unaligned memory and the upper FPU registers. */ ! #define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, IN) \ ! ((FP_REG_CLASS_P (CLASS) \ ! && ((MODE) == HImode || (MODE) == QImode) \ ! && (GET_CODE (IN) == MEM \ ! || ((GET_CODE (IN) == REG || GET_CODE (IN) == SUBREG) \ ! && true_regnum (IN) == -1))) \ ! ? GENERAL_REGS \ ! : ((CLASS) == EXTRA_FP_REGS && (MODE) == DFmode \ ! && GET_CODE (IN) == MEM && TARGET_ARCH32 \ ! && ! mem_min_alignment ((IN), 8)) \ ! ? FP_REGS \ ! : (((TARGET_CM_MEDANY \ ! && symbolic_operand ((IN), (MODE))) \ ! || (TARGET_CM_EMBMEDANY \ ! && text_segment_operand ((IN), (MODE)))) \ ! && !flag_pic) \ ! ? GENERAL_REGS \ ! : NO_REGS) ! #define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, IN) \ ! ((FP_REG_CLASS_P (CLASS) \ ! && ((MODE) == HImode || (MODE) == QImode) \ ! && (GET_CODE (IN) == MEM \ ! || ((GET_CODE (IN) == REG || GET_CODE (IN) == SUBREG) \ ! && true_regnum (IN) == -1))) \ ! ? GENERAL_REGS \ ! : ((CLASS) == EXTRA_FP_REGS && (MODE) == DFmode \ ! && GET_CODE (IN) == MEM && TARGET_ARCH32 \ ! && ! mem_min_alignment ((IN), 8)) \ ! ? FP_REGS \ ! : (((TARGET_CM_MEDANY \ ! && symbolic_operand ((IN), (MODE))) \ ! || (TARGET_CM_EMBMEDANY \ ! && text_segment_operand ((IN), (MODE)))) \ ! && !flag_pic) \ ! ? GENERAL_REGS \ ! : NO_REGS) /* On SPARC it is not possible to directly move data between GENERAL_REGS and FP_REGS. */ --- 1421,1437 ---- : (C) == 'O' ? arith_double_4096_operand (VALUE, DImode) \ : 0) ! #define PREFERRED_RELOAD_CLASS(X,CLASS) \ ! sparc_preferred_reload_class (X, CLASS) ! #define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, IN) \ ! sparc_secondary_reload_class(CLASS, MODE, IN, true) ! #define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS, MODE, IN) \ ! sparc_secondary_reload_class(CLASS, MODE, IN, false) ! #define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \ ! sparc_cannot_change_mode_class(FROM, TO, CLASS) /* On SPARC it is not possible to directly move data between GENERAL_REGS and FP_REGS. */