Commit da1f39e4 by Bob Wilson Committed by Bob Wilson

xtensa.c (smalloffset_mem_p): Use BASE_REG_P.

	* 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.

From-SVN: r121533
parent 2e6524ba
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> 2007-02-02 Steve Ellcey <sje@cup.hp.com>
* config/ia64/ia64.c (ia64_print_operand): Fix compare strings. * config/ia64/ia64.c (ia64_print_operand): Fix compare strings.
......
/* Prototypes of target machine for GNU compiler for Xtensa. /* 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. Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
This file is part of GCC. This file is part of GCC.
...@@ -52,6 +52,8 @@ extern char *xtensa_emit_branch (bool, bool, rtx *); ...@@ -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_bit_branch (bool, bool, rtx *);
extern char *xtensa_emit_movcc (bool, bool, bool, rtx *); extern char *xtensa_emit_movcc (bool, bool, bool, rtx *);
extern char *xtensa_emit_call (int, 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 #ifdef TREE_CODE
extern void init_cumulative_args (CUMULATIVE_ARGS *, int); extern void init_cumulative_args (CUMULATIVE_ARGS *, int);
...@@ -60,6 +62,7 @@ extern void xtensa_va_start (tree, rtx); ...@@ -60,6 +62,7 @@ extern void xtensa_va_start (tree, rtx);
extern void print_operand (FILE *, rtx, int); extern void print_operand (FILE *, rtx, int);
extern void print_operand_address (FILE *, rtx); 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 void xtensa_output_literal (FILE *, rtx, enum machine_mode, int);
extern rtx xtensa_return_addr (int, rtx); extern rtx xtensa_return_addr (int, rtx);
extern enum reg_class xtensa_preferred_reload_class (rtx, enum reg_class, int); extern enum reg_class xtensa_preferred_reload_class (rtx, enum reg_class, int);
......
/* Subroutines for insn-output.c for Tensilica's Xtensa architecture. /* 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. Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
This file is part of GCC. This file is part of GCC.
...@@ -397,7 +398,7 @@ smalloffset_mem_p (rtx op) ...@@ -397,7 +398,7 @@ smalloffset_mem_p (rtx op)
{ {
rtx addr = XEXP (op, 0); rtx addr = XEXP (op, 0);
if (GET_CODE (addr) == REG) if (GET_CODE (addr) == REG)
return REG_OK_FOR_BASE_P (addr); return BASE_REG_P (addr, 0);
if (GET_CODE (addr) == PLUS) if (GET_CODE (addr) == PLUS)
{ {
rtx offset = XEXP (addr, 0); rtx offset = XEXP (addr, 0);
...@@ -686,7 +687,8 @@ xtensa_expand_conditional_branch (rtx *operands, enum rtx_code test_code) ...@@ -686,7 +687,8 @@ xtensa_expand_conditional_branch (rtx *operands, enum rtx_code test_code)
case CMP_SF: case CMP_SF:
if (!TARGET_HARD_FLOAT) 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; invert = FALSE;
cmp = gen_float_relational (test_code, cmp0, cmp1); cmp = gen_float_relational (test_code, cmp0, cmp1);
break; break;
...@@ -1370,6 +1372,92 @@ xtensa_emit_call (int callop, rtx *operands) ...@@ -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'. */ /* Return the debugger register number to use for 'regno'. */
int int
...@@ -1820,6 +1908,29 @@ print_operand_address (FILE *file, rtx addr) ...@@ -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 void
xtensa_output_literal (FILE *file, rtx x, enum machine_mode mode, int labelno) xtensa_output_literal (FILE *file, rtx x, enum machine_mode mode, int labelno)
{ {
......
/* Definitions of Tensilica's Xtensa target machine for GNU compiler. /* 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. Contributed by Bob Wilson (bwilson@tensilica.com) at Tensilica.
This file is part of GCC. This file is part of GCC.
...@@ -825,39 +826,27 @@ typedef struct xtensa_args ...@@ -825,39 +826,27 @@ typedef struct xtensa_args
/* Addressing modes, and classification of registers for them. */ /* Addressing modes, and classification of registers for them. */
/* C expressions which are nonzero if register number NUM is suitable /* C expressions which are nonzero if register number NUM is suitable
for use as a base or index register in operand addresses. It may for use as a base or index register in operand addresses. */
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. */
#define REGNO_OK_FOR_INDEX_P(NUM) 0
#define REGNO_OK_FOR_BASE_P(NUM) \ #define REGNO_OK_FOR_BASE_P(NUM) \
(GP_REG_P (NUM) || GP_REG_P ((unsigned) reg_renumber[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 /* 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 valid for use as a base or index register. */
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. */
#ifdef REG_OK_STRICT #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 BASE_REG_P(X, STRICT) \
#define REG_OK_FOR_BASE_P(X) \ ((!(STRICT) && REGNO (X) >= FIRST_PSEUDO_REGISTER) \
REGNO_OK_FOR_BASE_P (REGNO (X)) || REGNO_OK_FOR_BASE_P (REGNO (X)))
#else /* !REG_OK_STRICT */
#define REG_OK_FOR_INDEX_P(X) 0 #define REG_OK_FOR_INDEX_P(X) 0
#define REG_OK_FOR_BASE_P(X) \ #define REG_OK_FOR_BASE_P(X) BASE_REG_P (X, REG_OK_STRICT_FLAG)
((REGNO (X) >= FIRST_PSEUDO_REGISTER) || (GP_REG_P (REGNO (X))))
#endif /* !REG_OK_STRICT */
/* Maximum number of registers that can appear in a valid memory address. */ /* Maximum number of registers that can appear in a valid memory address. */
#define MAX_REGS_PER_ADDRESS 1 #define MAX_REGS_PER_ADDRESS 1
...@@ -865,52 +854,8 @@ typedef struct xtensa_args ...@@ -865,52 +854,8 @@ typedef struct xtensa_args
/* Identify valid Xtensa addresses. */ /* Identify valid Xtensa addresses. */
#define GO_IF_LEGITIMATE_ADDRESS(MODE, ADDR, LABEL) \ #define GO_IF_LEGITIMATE_ADDRESS(MODE, ADDR, LABEL) \
do { \ do { \
rtx xinsn = (ADDR); \ if (xtensa_legitimate_address_p (MODE, ADDR, REG_OK_STRICT_FLAG)) \
\
/* 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)) \
goto LABEL; \ 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) } while (0)
/* A C expression that is 1 if the RTX X is a constant which is a /* A C expression that is 1 if the RTX X is a constant which is a
...@@ -934,36 +879,13 @@ typedef struct xtensa_args ...@@ -934,36 +879,13 @@ typedef struct xtensa_args
&& GET_CODE (X) != LABEL_REF \ && GET_CODE (X) != LABEL_REF \
&& GET_CODE (X) != CONST) && GET_CODE (X) != CONST)
/* Tell GCC how to use ADDMI to generate addresses. */
#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ #define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \
do { \ do { \
rtx xinsn = (X); \ rtx new_x = xtensa_legitimize_address (X, OLDX, MODE); \
if (GET_CODE (xinsn) == PLUS) \ if (new_x) \
{ \ { \
rtx plus0 = XEXP (xinsn, 0); \ X = new_x; \
rtx plus1 = XEXP (xinsn, 1); \ goto WIN; \
\
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; \
} \
} \ } \
} while (0) } while (0)
...@@ -1066,20 +988,7 @@ typedef struct xtensa_args ...@@ -1066,20 +988,7 @@ typedef struct xtensa_args
constants. Used for PIC-specific UNSPECs. */ constants. Used for PIC-specific UNSPECs. */
#define OUTPUT_ADDR_CONST_EXTRA(STREAM, X, FAIL) \ #define OUTPUT_ADDR_CONST_EXTRA(STREAM, X, FAIL) \
do { \ do { \
if (flag_pic && GET_CODE (X) == UNSPEC && XVECLEN ((X), 0) == 1) \ if (xtensa_output_addr_const_extra (STREAM, X) == FALSE) \
{ \
switch (XINT ((X), 1)) \
{ \
case UNSPEC_PLT: \
output_addr_const ((STREAM), XVECEXP ((X), 0, 0)); \
fputs ("@PLT", (STREAM)); \
break; \
default: \
goto FAIL; \
} \
break; \
} \
else \
goto FAIL; \ goto FAIL; \
} while (0) } while (0)
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment