aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog16
-rw-r--r--gcc/config/xtensa/xtensa-protos.h5
-rw-r--r--gcc/config/xtensa/xtensa.c117
-rw-r--r--gcc/config/xtensa/xtensa.h131
4 files changed, 154 insertions, 115 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index dc35247..73626e6 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,19 @@
+2007-02-02 Bob Wilson <bob.wilson@acm.org>
+
+ * config/xtensa/xtensa.c (smalloffset_mem_p): Use BASE_REG_P.
+ (xtensa_legitimate_address_p): New.
+ (xtensa_legitimize_address): New.
+ (xtensa_output_addr_const_extra): New.
+ * config/xtensa/xtensa.h (REG_OK_STRICT_FLAG): Define.
+ (BASE_REG_P): New.
+ (REG_OK_FOR_BASE_P): Use BASE_REG_P.
+ (GO_IF_LEGITIMATE_ADDRESS): Move code to xtensa_legitimate_address_p.
+ (LEGITIMIZE_ADDRESS): Move code to xtensa_legitimize_address.
+ (OUTPUT_ADDR_CONST_EXTRA): Move code to xtensa_output_addr_const_extra.
+ * config/xtensa/xtensa-protos.h (xtensa_legitimate_address_p): New.
+ (xtensa_legitimize_address): New.
+ (xtensa_output_addr_const_extra): New.
+
2007-02-02 Steve Ellcey <sje@cup.hp.com>
* config/ia64/ia64.c (ia64_print_operand): Fix compare strings.
diff --git a/gcc/config/xtensa/xtensa-protos.h b/gcc/config/xtensa/xtensa-protos.h
index 762aa0a..f6cca7a 100644
--- a/gcc/config/xtensa/xtensa-protos.h
+++ b/gcc/config/xtensa/xtensa-protos.h
@@ -1,5 +1,5 @@
/* Prototypes of target machine for GNU compiler for Xtensa.
- Copyright 2001, 2002, 2003, 2004, 2005 Free Software Foundation, Inc.
+ Copyright 2001, 2002, 2003, 2004, 2005, 2007 Free Software Foundation, Inc.
Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
This file is part of GCC.
@@ -52,6 +52,8 @@ extern char *xtensa_emit_branch (bool, bool, rtx *);
extern char *xtensa_emit_bit_branch (bool, bool, rtx *);
extern char *xtensa_emit_movcc (bool, bool, bool, rtx *);
extern char *xtensa_emit_call (int, rtx *);
+extern bool xtensa_legitimate_address_p (enum machine_mode, rtx, bool);
+extern rtx xtensa_legitimize_address (rtx, rtx, enum machine_mode);
#ifdef TREE_CODE
extern void init_cumulative_args (CUMULATIVE_ARGS *, int);
@@ -60,6 +62,7 @@ extern void xtensa_va_start (tree, rtx);
extern void print_operand (FILE *, rtx, int);
extern void print_operand_address (FILE *, rtx);
+extern bool xtensa_output_addr_const_extra (FILE *, rtx);
extern void xtensa_output_literal (FILE *, rtx, enum machine_mode, int);
extern rtx xtensa_return_addr (int, rtx);
extern enum reg_class xtensa_preferred_reload_class (rtx, enum reg_class, int);
diff --git a/gcc/config/xtensa/xtensa.c b/gcc/config/xtensa/xtensa.c
index 49a8992..6269f1f 100644
--- a/gcc/config/xtensa/xtensa.c
+++ b/gcc/config/xtensa/xtensa.c
@@ -1,5 +1,6 @@
/* Subroutines for insn-output.c for Tensilica's Xtensa architecture.
- Copyright 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
This file is part of GCC.
@@ -397,7 +398,7 @@ smalloffset_mem_p (rtx op)
{
rtx addr = XEXP (op, 0);
if (GET_CODE (addr) == REG)
- return REG_OK_FOR_BASE_P (addr);
+ return BASE_REG_P (addr, 0);
if (GET_CODE (addr) == PLUS)
{
rtx offset = XEXP (addr, 0);
@@ -686,7 +687,8 @@ xtensa_expand_conditional_branch (rtx *operands, enum rtx_code test_code)
case CMP_SF:
if (!TARGET_HARD_FLOAT)
- fatal_insn ("bad test", gen_rtx_fmt_ee (test_code, VOIDmode, cmp0, cmp1));
+ fatal_insn ("bad test", gen_rtx_fmt_ee (test_code, VOIDmode,
+ cmp0, cmp1));
invert = FALSE;
cmp = gen_float_relational (test_code, cmp0, cmp1);
break;
@@ -1370,6 +1372,92 @@ xtensa_emit_call (int callop, rtx *operands)
}
+bool
+xtensa_legitimate_address_p (enum machine_mode mode, rtx addr, bool strict)
+{
+ /* Allow constant pool addresses. */
+ if (mode != BLKmode && GET_MODE_SIZE (mode) >= UNITS_PER_WORD
+ && ! TARGET_CONST16 && constantpool_address_p (addr))
+ return true;
+
+ while (GET_CODE (addr) == SUBREG)
+ addr = SUBREG_REG (addr);
+
+ /* Allow base registers. */
+ if (GET_CODE (addr) == REG && BASE_REG_P (addr, strict))
+ return true;
+
+ /* Check for "register + offset" addressing. */
+ if (GET_CODE (addr) == PLUS)
+ {
+ rtx xplus0 = XEXP (addr, 0);
+ rtx xplus1 = XEXP (addr, 1);
+ enum rtx_code code0;
+ enum rtx_code code1;
+
+ while (GET_CODE (xplus0) == SUBREG)
+ xplus0 = SUBREG_REG (xplus0);
+ code0 = GET_CODE (xplus0);
+
+ while (GET_CODE (xplus1) == SUBREG)
+ xplus1 = SUBREG_REG (xplus1);
+ code1 = GET_CODE (xplus1);
+
+ /* Swap operands if necessary so the register is first. */
+ if (code0 != REG && code1 == REG)
+ {
+ xplus0 = XEXP (addr, 1);
+ xplus1 = XEXP (addr, 0);
+ code0 = GET_CODE (xplus0);
+ code1 = GET_CODE (xplus1);
+ }
+
+ if (code0 == REG && BASE_REG_P (xplus0, strict)
+ && code1 == CONST_INT
+ && xtensa_mem_offset (INTVAL (xplus1), mode))
+ return true;
+ }
+
+ return false;
+}
+
+
+rtx
+xtensa_legitimize_address (rtx x,
+ rtx oldx ATTRIBUTE_UNUSED,
+ enum machine_mode mode)
+{
+ if (GET_CODE (x) == PLUS)
+ {
+ rtx plus0 = XEXP (x, 0);
+ rtx plus1 = XEXP (x, 1);
+
+ if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG)
+ {
+ plus0 = XEXP (x, 1);
+ plus1 = XEXP (x, 0);
+ }
+
+ /* Try to split up the offset to use an ADDMI instruction. */
+ if (GET_CODE (plus0) == REG
+ && GET_CODE (plus1) == CONST_INT
+ && !xtensa_mem_offset (INTVAL (plus1), mode)
+ && !xtensa_simm8 (INTVAL (plus1))
+ && xtensa_mem_offset (INTVAL (plus1) & 0xff, mode)
+ && xtensa_simm8x256 (INTVAL (plus1) & ~0xff))
+ {
+ rtx temp = gen_reg_rtx (Pmode);
+ rtx addmi_offset = GEN_INT (INTVAL (plus1) & ~0xff);
+ emit_insn (gen_rtx_SET (Pmode, temp,
+ gen_rtx_PLUS (Pmode, plus0, addmi_offset)));
+ return gen_rtx_PLUS (Pmode, temp, GEN_INT (INTVAL (plus1) & 0xff));
+ }
+ }
+
+ return NULL_RTX;
+}
+
+
/* Return the debugger register number to use for 'regno'. */
int
@@ -1820,6 +1908,29 @@ print_operand_address (FILE *file, rtx addr)
}
+bool
+xtensa_output_addr_const_extra (FILE *fp, rtx x)
+{
+ if (GET_CODE (x) == UNSPEC && XVECLEN (x, 0) == 1)
+ {
+ switch (XINT (x, 1))
+ {
+ case UNSPEC_PLT:
+ if (flag_pic)
+ {
+ output_addr_const (fp, XVECEXP (x, 0, 0));
+ fputs ("@PLT", fp);
+ return true;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+
void
xtensa_output_literal (FILE *file, rtx x, enum machine_mode mode, int labelno)
{
diff --git a/gcc/config/xtensa/xtensa.h b/gcc/config/xtensa/xtensa.h
index d1fe022..11c4184 100644
--- a/gcc/config/xtensa/xtensa.h
+++ b/gcc/config/xtensa/xtensa.h
@@ -1,5 +1,6 @@
/* Definitions of Tensilica's Xtensa target machine for GNU compiler.
- Copyright 2001, 2002, 2003, 2004, 2005, 2006 Free Software Foundation, Inc.
+ Copyright 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
This file is part of GCC.
@@ -825,39 +826,27 @@ typedef struct xtensa_args
/* Addressing modes, and classification of registers for them. */
/* C expressions which are nonzero if register number NUM is suitable
- for use as a base or index register in operand addresses. It may
- be either a suitable hard register or a pseudo register that has
- been allocated such a hard register. The difference between an
- index register and a base register is that the index register may
- be scaled. */
+ for use as a base or index register in operand addresses. */
+#define REGNO_OK_FOR_INDEX_P(NUM) 0
#define REGNO_OK_FOR_BASE_P(NUM) \
(GP_REG_P (NUM) || GP_REG_P ((unsigned) reg_renumber[NUM]))
-#define REGNO_OK_FOR_INDEX_P(NUM) 0
-
/* C expressions that are nonzero if X (assumed to be a `reg' RTX) is
- valid for use as a base or index register. For hard registers, it
- should always accept those which the hardware permits and reject
- the others. Whether the macro accepts or rejects pseudo registers
- must be controlled by `REG_OK_STRICT'. This usually requires two
- variant definitions, of which `REG_OK_STRICT' controls the one
- actually used. The difference between an index register and a base
- register is that the index register may be scaled. */
+ valid for use as a base or index register. */
#ifdef REG_OK_STRICT
+#define REG_OK_STRICT_FLAG 1
+#else
+#define REG_OK_STRICT_FLAG 0
+#endif
-#define REG_OK_FOR_INDEX_P(X) 0
-#define REG_OK_FOR_BASE_P(X) \
- REGNO_OK_FOR_BASE_P (REGNO (X))
-
-#else /* !REG_OK_STRICT */
+#define BASE_REG_P(X, STRICT) \
+ ((!(STRICT) && REGNO (X) >= FIRST_PSEUDO_REGISTER) \
+ || REGNO_OK_FOR_BASE_P (REGNO (X)))
#define REG_OK_FOR_INDEX_P(X) 0
-#define REG_OK_FOR_BASE_P(X) \
- ((REGNO (X) >= FIRST_PSEUDO_REGISTER) || (GP_REG_P (REGNO (X))))
-
-#endif /* !REG_OK_STRICT */
+#define REG_OK_FOR_BASE_P(X) BASE_REG_P (X, REG_OK_STRICT_FLAG)
/* Maximum number of registers that can appear in a valid memory address. */
#define MAX_REGS_PER_ADDRESS 1
@@ -865,52 +854,8 @@ typedef struct xtensa_args
/* Identify valid Xtensa addresses. */
#define GO_IF_LEGITIMATE_ADDRESS(MODE, ADDR, LABEL) \
do { \
- rtx xinsn = (ADDR); \
- \
- /* allow constant pool addresses */ \
- if ((MODE) != BLKmode && GET_MODE_SIZE (MODE) >= UNITS_PER_WORD \
- && !TARGET_CONST16 && constantpool_address_p (xinsn)) \
- goto LABEL; \
- \
- while (GET_CODE (xinsn) == SUBREG) \
- xinsn = SUBREG_REG (xinsn); \
- \
- /* allow base registers */ \
- if (GET_CODE (xinsn) == REG && REG_OK_FOR_BASE_P (xinsn)) \
+ if (xtensa_legitimate_address_p (MODE, ADDR, REG_OK_STRICT_FLAG)) \
goto LABEL; \
- \
- /* check for "register + offset" addressing */ \
- if (GET_CODE (xinsn) == PLUS) \
- { \
- rtx xplus0 = XEXP (xinsn, 0); \
- rtx xplus1 = XEXP (xinsn, 1); \
- enum rtx_code code0; \
- enum rtx_code code1; \
- \
- while (GET_CODE (xplus0) == SUBREG) \
- xplus0 = SUBREG_REG (xplus0); \
- code0 = GET_CODE (xplus0); \
- \
- while (GET_CODE (xplus1) == SUBREG) \
- xplus1 = SUBREG_REG (xplus1); \
- code1 = GET_CODE (xplus1); \
- \
- /* swap operands if necessary so the register is first */ \
- if (code0 != REG && code1 == REG) \
- { \
- xplus0 = XEXP (xinsn, 1); \
- xplus1 = XEXP (xinsn, 0); \
- code0 = GET_CODE (xplus0); \
- code1 = GET_CODE (xplus1); \
- } \
- \
- if (code0 == REG && REG_OK_FOR_BASE_P (xplus0) \
- && code1 == CONST_INT \
- && xtensa_mem_offset (INTVAL (xplus1), (MODE))) \
- { \
- goto LABEL; \
- } \
- } \
} while (0)
/* A C expression that is 1 if the RTX X is a constant which is a
@@ -934,36 +879,13 @@ typedef struct xtensa_args
&& GET_CODE (X) != LABEL_REF \
&& GET_CODE (X) != CONST)
-/* Tell GCC how to use ADDMI to generate addresses. */
#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
do { \
- rtx xinsn = (X); \
- if (GET_CODE (xinsn) == PLUS) \
- { \
- rtx plus0 = XEXP (xinsn, 0); \
- rtx plus1 = XEXP (xinsn, 1); \
- \
- if (GET_CODE (plus0) != REG && GET_CODE (plus1) == REG) \
- { \
- plus0 = XEXP (xinsn, 1); \
- plus1 = XEXP (xinsn, 0); \
- } \
- \
- if (GET_CODE (plus0) == REG \
- && GET_CODE (plus1) == CONST_INT \
- && !xtensa_mem_offset (INTVAL (plus1), MODE) \
- && !xtensa_simm8 (INTVAL (plus1)) \
- && xtensa_mem_offset (INTVAL (plus1) & 0xff, MODE) \
- && xtensa_simm8x256 (INTVAL (plus1) & ~0xff)) \
- { \
- rtx temp = gen_reg_rtx (Pmode); \
- emit_insn (gen_rtx_SET (Pmode, temp, \
- gen_rtx_PLUS (Pmode, plus0, \
- GEN_INT (INTVAL (plus1) & ~0xff)))); \
- (X) = gen_rtx_PLUS (Pmode, temp, \
- GEN_INT (INTVAL (plus1) & 0xff)); \
- goto WIN; \
- } \
+ rtx new_x = xtensa_legitimize_address (X, OLDX, MODE); \
+ if (new_x) \
+ { \
+ X = new_x; \
+ goto WIN; \
} \
} while (0)
@@ -1066,20 +988,7 @@ typedef struct xtensa_args
constants. Used for PIC-specific UNSPECs. */
#define OUTPUT_ADDR_CONST_EXTRA(STREAM, X, FAIL) \
do { \
- if (flag_pic && GET_CODE (X) == UNSPEC && XVECLEN ((X), 0) == 1) \
- { \
- switch (XINT ((X), 1)) \
- { \
- case UNSPEC_PLT: \
- output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \
- fputs ("@PLT", (STREAM)); \
- break; \
- default: \
- goto FAIL; \
- } \
- break; \
- } \
- else \
+ if (xtensa_output_addr_const_extra (STREAM, X) == FALSE) \
goto FAIL; \
} while (0)