{ "subtarget_link_emul_suffix", SUBTARGET_LINK_EMUL_SUFFIX }, \
{ "subtarget_link_spec", SUBTARGET_LINK_SPEC }, \
{ "subtarget_asm_endian_spec", SUBTARGET_ASM_ENDIAN_SPEC }, \
+ { "subtarget_asm_relax_spec", SUBTARGET_ASM_RELAX_SPEC }, \
+ { "subtarget_asm_isa_spec", SUBTARGET_ASM_ISA_SPEC }, \
SUBTARGET_EXTRA_SPECS
-#define ASM_SPEC "%(subtarget_asm_endian_spec) %{mrelax:-relax}"
+#if TARGET_CPU_DEFAULT & HARD_SH4_BIT
+#define SUBTARGET_ASM_RELAX_SPEC "%{!m[1235]*:-isa=sh4}"
+#else
+#define SUBTARGET_ASM_RELAX_SPEC "%{m4*:-isa=sh4}"
+#endif
+
+#define SH_ASM_SPEC \
+ "%(subtarget_asm_endian_spec) %{mrelax:-relax %(subtarget_asm_relax_spec)}\
+%(subtarget_asm_isa_spec)"
+
+#define ASM_SPEC SH_ASM_SPEC
#ifndef SUBTARGET_ASM_ENDIAN_SPEC
#if TARGET_ENDIAN_DEFAULT == LITTLE_ENDIAN_BIT
#endif
#endif
+#define SUBTARGET_ASM_ISA_SPEC ""
+
#define LINK_EMUL_PREFIX "sh%{ml:l}"
#if TARGET_CPU_DEFAULT & SH5_BIT
targetm.asm_out.unaligned_op.di = NULL; \
} \
if (TARGET_FMOVD) \
- reg_class_from_letter['e'] = NO_REGS; \
+ reg_class_from_letter['e' - 'a'] = NO_REGS; \
\
for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++) \
if (! VALID_REGISTER_P (regno)) \
flag_schedule_insns = 0; \
} \
\
+ if (align_loops == 0) \
+ align_loops = 1 << (TARGET_SH5 ? 3 : 2); \
+ if (align_jumps == 0) \
+ align_jumps = 1 << CACHE_LOG; \
+ else if (align_jumps < (TARGET_SHMEDIA ? 4 : 2)) \
+ align_jumps = TARGET_SHMEDIA ? 4 : 2; \
+ \
/* Allocation boundary (in *bytes*) for the code of a function. \
SH1: 32 bit alignment is faster, because instructions are always \
fetched as a pair from a longword boundary. \
if (align_functions == 0) \
align_functions \
= TARGET_SMALLCODE ? FUNCTION_BOUNDARY/8 : (1 << CACHE_LOG); \
+ /* The linker relaxation code breaks when a function contains \
+ alignments that are larger than that at the start of a \
+ compilation unit. */ \
+ if (TARGET_RELAX) \
+ { \
+ int min_align \
+ = align_loops > align_jumps ? align_loops : align_jumps; \
+ \
+ /* Also take possible .long constants / mova tables int account. */\
+ if (min_align < 4) \
+ min_align = 4; \
+ if (align_functions < min_align) \
+ align_functions = min_align; \
+ } \
} while (0)
\f
/* Target machine storage layout. */
#define HARD_REGNO_NREGS(REGNO, MODE) \
(XD_REGISTER_P (REGNO) \
- ? (GET_MODE_SIZE (MODE) / (2 * UNITS_PER_WORD)) \
+ ? ((GET_MODE_SIZE (MODE) + (2*UNITS_PER_WORD - 1)) / (2*UNITS_PER_WORD)) \
: (TARGET_SHMEDIA && FP_REGISTER_P (REGNO)) \
? ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD/2 - 1) / (UNITS_PER_WORD/2)) \
- : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) \
+ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
/* Value is 1 if hard register REGNO can hold a value of machine-mode MODE.
We can allow any mode in any general register. The special registers
? R0_REGS \
: (CLASS == FPUL_REGS \
&& ((GET_CODE (X) == REG \
- && (REGNO (X) == MACL_REG || REGNO (X) == MACH_REG \
- || REGNO (X) == T_REG)))) \
+ && (REGNO (X) == MACL_REG || REGNO (X) == MACH_REG \
+ || REGNO (X) == T_REG)) \
+ || GET_CODE (X) == PLUS)) \
? GENERAL_REGS \
: CLASS == FPUL_REGS && immediate_operand ((X), (MODE)) \
? (GET_CODE (X) == CONST_INT && CONST_OK_FOR_I (INTVAL (X)) \
/* Return the maximum number of consecutive registers
needed to represent mode MODE in a register of class CLASS.
- On SH this is the size of MODE in words. */
+ If TARGET_SHMEDIA, we need two FP registers per word.
+ Otherwise we will need at most one register per word. */
#define CLASS_MAX_NREGS(CLASS, MODE) \
- ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+ (TARGET_SHMEDIA \
+ && TEST_HARD_REG_BIT (reg_class_contents[CLASS], FIRST_FP_REG) \
+ ? (GET_MODE_SIZE (MODE) + UNITS_PER_WORD/2 - 1) / (UNITS_PER_WORD/2) \
+ : (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. */
/* ??? We need to renumber the internal numbers for the frnn registers
when in little endian in order to allow mode size changes. */
-#define CANNOT_CHANGE_MODE_CLASS(FROM, TO) \
- sh_cannot_change_mode_class (FROM, TO)
+#define CANNOT_CHANGE_MODE_CLASS(FROM, TO, CLASS) \
+ sh_cannot_change_mode_class (FROM, TO, CLASS)
\f
/* Stack layout; function entry, exit and calling. */
#define Pmode (TARGET_SHMEDIA64 ? DImode : SImode)
#define FUNCTION_MODE Pmode
-/* The relative costs of various types of constants. */
-
-#define CONST_COSTS(RTX, CODE, OUTER_CODE) \
- case CONST_INT: \
- if (TARGET_SHMEDIA) \
- { \
- if (INTVAL (RTX) == 0) \
- return 0; \
- if ((OUTER_CODE) == AND && and_operand ((RTX), DImode)) \
- return 0; \
- if (((OUTER_CODE) == IOR || (OUTER_CODE) == XOR \
- || (OUTER_CODE) == PLUS) \
- && CONST_OK_FOR_P (INTVAL (RTX))) \
- return 0; \
- if (CONST_OK_FOR_J (INTVAL (RTX))) \
- return COSTS_N_INSNS ((OUTER_CODE) != SET); \
- else if (CONST_OK_FOR_J (INTVAL (RTX) >> 16)) \
- return COSTS_N_INSNS (2); \
- else if (CONST_OK_FOR_J ((INTVAL (RTX) >> 16) >> 16)) \
- return COSTS_N_INSNS (3); \
- else \
- return COSTS_N_INSNS (4); \
- } \
- if (CONST_OK_FOR_I (INTVAL (RTX))) \
- return 0; \
- else if (((OUTER_CODE) == AND || (OUTER_CODE) == IOR || (OUTER_CODE) == XOR) \
- && CONST_OK_FOR_L (INTVAL (RTX))) \
- return 1; \
- else \
- return 8; \
- case CONST: \
- case LABEL_REF: \
- case SYMBOL_REF: \
- if (TARGET_SHMEDIA64) \
- return COSTS_N_INSNS (4); \
- if (TARGET_SHMEDIA32) \
- return COSTS_N_INSNS (2); \
- return 5; \
- case CONST_DOUBLE: \
- if (TARGET_SHMEDIA) \
- return COSTS_N_INSNS (4); \
- else \
- return 10;
-
-#define RTX_COSTS(X, CODE, OUTER_CODE) \
- case PLUS: \
- return COSTS_N_INSNS (addsubcosts (X)); \
- case AND: \
- return COSTS_N_INSNS (andcosts (X)); \
- case MULT: \
- return COSTS_N_INSNS (multcosts (X)); \
- case ASHIFT: \
- case ASHIFTRT: \
- case LSHIFTRT: \
- return COSTS_N_INSNS (shiftcosts (X)); \
- case DIV: \
- case UDIV: \
- case MOD: \
- case UMOD: \
- return COSTS_N_INSNS (20); \
- case FLOAT: \
- case FIX: \
- return 100;
-
/* The multiply insn on the SH1 and the divide insns on the SH1 and SH2
are actually function calls with some special constraints on arguments
and register usage.
((GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == LABEL_REF) \
&& nonpic_symbol_mentioned_p (X))
\f
-/* Compute the cost of an address. For the SH, all valid addresses are
- the same cost. Use a slightly higher cost for reg + reg addressing,
- since it increases pressure on r0. */
+/* TLS. */
+
+/* The prefix used to mark SYMBOL_REFs that refer to TLS symbols. */
+#define SH_TLS_ENCODING "@"
-#define ADDRESS_COST(X) (GET_CODE (X) == PLUS && ! CONSTANT_P (XEXP (X, 1)) \
- && ! TARGET_SHMEDIA \
- ? 1 : 0)
+/* Return true if SYM_NAME starts with SH_TLS_ENCODING. */
+#define TLS_SYMNAME_P(SYM_NAME) \
+ ((SYM_NAME)[0] == SH_TLS_ENCODING[0])
+/* Skip an optional SH_TLS_ENCODING in the beginning of SYM_NAME. */
+#define STRIP_TLS_ENCODING(VAR, SYM_NAME) \
+ (VAR) = (SYM_NAME) + (TLS_SYMNAME_P (SYM_NAME) \
+ ? strlen (SH_TLS_ENCODING) + 1 : 0)
+\f
/* Compute extra cost of moving data between one register class
and another. */
const char * lname; \
\
STRIP_DATALABEL_ENCODING (lname, (NAME)); \
+ STRIP_TLS_ENCODING (lname, lname); \
if (lname[0] == '*') \
fputs (lname + 1, (FILE)); \
else \
output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \
fputs ("@GOTPLT", (STREAM)); \
break; \
+ case UNSPEC_DTPOFF: \
+ output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \
+ fputs ("@DTPOFF", (STREAM)); \
+ break; \
+ case UNSPEC_GOTTPOFF: \
+ output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \
+ fputs ("@GOTTPOFF", (STREAM)); \
+ break; \
+ case UNSPEC_TPOFF: \
+ output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \
+ fputs ("@TPOFF", (STREAM)); \
+ break; \
case UNSPEC_CALLER: \
{ \
char name[32]; \