865 lines
28 KiB
C
865 lines
28 KiB
C
/* Definitions of target machine for GCC,
|
||
For Ubicom IP2022 Communications Controller
|
||
|
||
Copyright (C) 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
||
Contributed by Red Hat, Inc and Ubicom, Inc.
|
||
|
||
This file is part of GCC.
|
||
|
||
GCC is free software; you can redistribute it and/or modify
|
||
it under the terms of the GNU General Public License as published by
|
||
the Free Software Foundation; either version 2, or (at your option)
|
||
any later version.
|
||
|
||
GCC is distributed in the hope that it will be useful,
|
||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||
GNU General Public License for more details.
|
||
|
||
You should have received a copy of the GNU General Public License
|
||
along with GCC; see the file COPYING. If not, write to
|
||
the Free Software Foundation, 59 Temple Place - Suite 330,
|
||
Boston, MA 02111-1307, USA. */
|
||
|
||
|
||
#undef ASM_SPEC /* We have a GAS assembler. */
|
||
|
||
#define TARGET_CPU_CPP_BUILTINS() \
|
||
do \
|
||
{ \
|
||
builtin_define_std ("IP2K"); \
|
||
builtin_define ("_DOUBLE_IS_32BITS"); \
|
||
builtin_define ("_BUFSIZ=512"); \
|
||
builtin_define ("__FILENAME_MAX__=128"); \
|
||
} \
|
||
while (0)
|
||
|
||
/* This declaration should be present. */
|
||
extern int target_flags;
|
||
|
||
#define TARGET_SWITCHES {{"",0, NULL}}
|
||
|
||
#define TARGET_VERSION fprintf (stderr, " (ip2k, GNU assembler syntax)")
|
||
|
||
/* Caller-saves is not a win for the IP2K. Pretty much anywhere that
|
||
a register is permitted allows SP-relative addresses too.
|
||
|
||
This machine doesn't have PIC addressing modes, so disable that also. */
|
||
|
||
#define OVERRIDE_OPTIONS \
|
||
do { \
|
||
flag_caller_saves = 0; \
|
||
flag_pic = 0; \
|
||
} while (0)
|
||
|
||
/* Put each function in its own section so that PAGE-instruction
|
||
relaxation can do its best. */
|
||
#define OPTIMIZATION_OPTIONS(LEVEL, SIZEFLAG) \
|
||
do { \
|
||
if ((LEVEL) || (SIZEFLAG)) \
|
||
flag_function_sections = 1; \
|
||
} while (0)
|
||
|
||
#define BITS_BIG_ENDIAN 0
|
||
#define BYTES_BIG_ENDIAN 1
|
||
#define WORDS_BIG_ENDIAN 1
|
||
#define BITS_PER_WORD 8
|
||
#define UNITS_PER_WORD (BITS_PER_WORD / BITS_PER_UNIT)
|
||
|
||
/* Width in bits of a pointer.
|
||
See also the macro `Pmode' defined below. */
|
||
#define POINTER_SIZE 16
|
||
|
||
/* Maximum sized of reasonable data type DImode or Dfmode ... */
|
||
#define MAX_FIXED_MODE_SIZE 64
|
||
|
||
#define PARM_BOUNDARY 8
|
||
#define FUNCTION_BOUNDARY 16
|
||
#define EMPTY_FIELD_BOUNDARY 8
|
||
#define BIGGEST_ALIGNMENT 8
|
||
|
||
#define STRICT_ALIGNMENT 0
|
||
|
||
#define PCC_BITFIELD_TYPE_MATTERS 1
|
||
|
||
#undef INT_TYPE_SIZE
|
||
#define INT_TYPE_SIZE 16
|
||
|
||
#undef SHORT_TYPE_SIZE
|
||
#define SHORT_TYPE_SIZE 16
|
||
|
||
#undef LONG_TYPE_SIZE
|
||
#define LONG_TYPE_SIZE 32
|
||
|
||
#undef LONG_LONG_TYPE_SIZE
|
||
#define LONG_LONG_TYPE_SIZE 64
|
||
|
||
#undef CHAR_TYPE_SIZE
|
||
#define CHAR_TYPE_SIZE 8
|
||
|
||
#undef FLOAT_TYPE_SIZE
|
||
#define FLOAT_TYPE_SIZE 32
|
||
|
||
#undef DOUBLE_TYPE_SIZE
|
||
#define DOUBLE_TYPE_SIZE 32
|
||
|
||
#undef LONG_DOUBLE_TYPE_SIZE
|
||
#define LONG_DOUBLE_TYPE_SIZE 32
|
||
|
||
#define DEFAULT_SIGNED_CHAR 1
|
||
|
||
#define SIZE_TYPE "unsigned int"
|
||
|
||
#define PTRDIFF_TYPE "int"
|
||
|
||
#undef WCHAR_TYPE
|
||
#define WCHAR_TYPE "int"
|
||
#undef WCHAR_TYPE_SIZE
|
||
#define WCHAR_TYPE_SIZE 16
|
||
|
||
#define HARD_REG_SIZE (UNITS_PER_WORD)
|
||
/* Standard register usage.
|
||
|
||
for the IP2K, we are going to have a LOT of registers, but only some of them
|
||
are named. */
|
||
|
||
#define FIRST_PSEUDO_REGISTER (0x104) /* Skip over physical regs, VFP, AP. */
|
||
|
||
#define REG_IP 0x4
|
||
#define REG_IPH REG_IP
|
||
#define REG_IPL 0x5
|
||
|
||
#define REG_SP 0x6
|
||
#define REG_SPH REG_SP
|
||
#define REG_SPL 0x7
|
||
|
||
#define REG_PCH 0x8
|
||
#define REG_PCL 0x9
|
||
|
||
#define REG_W 0xa
|
||
#define REG_STATUS 0xb
|
||
|
||
#define REG_DP 0xc
|
||
#define REG_DPH REG_DP
|
||
#define REG_DPL 0xd
|
||
|
||
#define REG_MULH 0xf
|
||
|
||
#define REG_CALLH 0x7e /* Call-stack readout. */
|
||
#define REG_CALLL 0x7f
|
||
|
||
|
||
#define REG_RESULT 0x80 /* Result register (upto 8 bytes). */
|
||
#define REG_FP 0xfd /* 2 bytes for FRAME chain */
|
||
|
||
#define REG_ZERO 0xff /* Initialized to zero by runtime. */
|
||
|
||
#define REG_VFP 0x100 /* Virtual frame pointer. */
|
||
#define REG_AP 0x102 /* Virtual arg pointer. */
|
||
|
||
/* Status register bits. */
|
||
#define Z_FLAG 0x2
|
||
#define DC_FLAG 0x1
|
||
#define C_FLAG 0x0
|
||
|
||
#define FIXED_REGISTERS {\
|
||
1,1,1,1,0,0,1,1,1,1,1,1,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/* r0.. r31*/\
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/* r32.. r63*/\
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/* r64.. r95*/\
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/* r96..r127*/\
|
||
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,/*r128..r159*/\
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/*r160..r191*/\
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/*r192..r223*/\
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/*r224..r255*/\
|
||
1,1,1,1}
|
||
|
||
#define CALL_USED_REGISTERS { \
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/* r0.. r31*/\
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/* r32.. r63*/\
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/* r64.. r95*/\
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/* r96..r127*/\
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/*r128..r159*/\
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/*r160..r191*/\
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/*r192..r223*/\
|
||
1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,/*r224..r255*/\
|
||
1,1,1,1}
|
||
|
||
#define NON_SAVING_SETJMP 0
|
||
|
||
#define REG_ALLOC_ORDER { \
|
||
0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f, \
|
||
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97, \
|
||
0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f, \
|
||
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
|
||
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7, \
|
||
0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf, \
|
||
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7, \
|
||
0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf, \
|
||
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7, \
|
||
0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf, \
|
||
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7, \
|
||
0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf, \
|
||
0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7, \
|
||
0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef, \
|
||
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7, \
|
||
0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff, \
|
||
0x00,0x01,0x02,0x03,0x0c,0x0d,0x06,0x07, \
|
||
0x08,0x09,0x0a,0x0b,0x04,0x05,0x0e,0x0f, \
|
||
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, \
|
||
0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f, \
|
||
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27, \
|
||
0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f, \
|
||
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, \
|
||
0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f, \
|
||
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47, \
|
||
0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f, \
|
||
0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57, \
|
||
0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f, \
|
||
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67, \
|
||
0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f, \
|
||
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77, \
|
||
0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f, \
|
||
0x100,0x101,0x102,0x103}
|
||
|
||
|
||
#define ORDER_REGS_FOR_LOCAL_ALLOC ip2k_init_local_alloc (reg_alloc_order)
|
||
|
||
/* Are we allowed to rename registers? For some reason, regrename was
|
||
changing DP to IP (when it appeared in addresses like (plus:HI
|
||
(reg: DP) (const_int 37)) - and that's bad because IP doesn't
|
||
permit offsets! */
|
||
|
||
#define HARD_REGNO_RENAME_OK(REG, NREG) \
|
||
(((REG) == REG_DPH) ? 0 \
|
||
: ((REG) == REG_IPH) ? ((NREG) == REG_DPH) \
|
||
: (((NREG) == REG_IPL) || ((NREG) == REG_DPL)) ? 0 : 1)
|
||
|
||
#define HARD_REGNO_NREGS(REGNO, MODE) \
|
||
((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
|
||
|
||
#define HARD_REGNO_MODE_OK(REGNO, MODE) 1
|
||
|
||
#define MODES_TIEABLE_P(MODE1, MODE2) \
|
||
(((MODE1) == QImode && (MODE2) == HImode) \
|
||
|| ((MODE2) == QImode && (MODE1) == HImode))
|
||
/* We originally had this as follows - this isn't a win on the IP2k
|
||
though as registers just get in our way!
|
||
|
||
#define MODES_TIEABLE_P(MODE1, MODE2) \
|
||
(((MODE1) > HImode && (MODE2) == HImode)
|
||
|| ((MODE1) == HImode && (MODE2) > HImode)) */
|
||
|
||
enum reg_class {
|
||
NO_REGS,
|
||
DPH_REGS,
|
||
DPL_REGS,
|
||
DP_REGS,
|
||
SP_REGS,
|
||
IPH_REGS,
|
||
IPL_REGS,
|
||
IP_REGS,
|
||
DP_SP_REGS,
|
||
PTR_REGS,
|
||
NONPTR_REGS,
|
||
NONSP_REGS,
|
||
GENERAL_REGS,
|
||
ALL_REGS = GENERAL_REGS,
|
||
LIM_REG_CLASSES
|
||
};
|
||
|
||
#define N_REG_CLASSES (int)LIM_REG_CLASSES
|
||
|
||
#define REG_CLASS_NAMES { \
|
||
"NO_REGS", \
|
||
"DPH_REGS", \
|
||
"DPL_REGS", \
|
||
"DP_REGS", \
|
||
"SP_REGS", \
|
||
"IPH_REGS", \
|
||
"IPL_REGS", \
|
||
"IP_REGS", \
|
||
"DP_SP_REGS", \
|
||
"PTR_REGS", \
|
||
"NONPTR_REGS", \
|
||
"NONSP_REGS", \
|
||
"GENERAL_REGS" \
|
||
}
|
||
|
||
|
||
#define REG_CLASS_CONTENTS { \
|
||
{0x00000000, 0, 0, 0, 0, 0, 0, 0, 0}, /* NO_REGS */ \
|
||
{0x00001000, 0, 0, 0, 0, 0, 0, 0, 0}, /* DPH_REGS */ \
|
||
{0x00002000, 0, 0, 0, 0, 0, 0, 0, 0}, /* DPL_REGS */ \
|
||
{0x00003000, 0, 0, 0, 0, 0, 0, 0, 0}, /* DP_REGS */ \
|
||
{0x000000c0, 0, 0, 0, 0, 0, 0, 0, 0}, /* SP_REGS */ \
|
||
{0x00000010, 0, 0, 0, 0, 0, 0, 0, 0}, /* IPH_REGS */ \
|
||
{0x00000020, 0, 0, 0, 0, 0, 0, 0, 0}, /* IPL_REGS */ \
|
||
{0x00000030, 0, 0, 0, 0, 0, 0, 0, 0}, /* IP_REGS */ \
|
||
{0x000030c0, 0, 0, 0, 0, 0, 0, 0, 0}, /* DP_SP_REGS */ \
|
||
{0x000030f0, 0, 0, 0, 0, 0, 0, 0, 0}, /* PTR_REGS */ \
|
||
{0xffffcf0f,-1,-1,-1,-1,-1,-1,-1, 0}, /* NONPTR_REGS */ \
|
||
{0xffffff3f,-1,-1,-1,-1,-1,-1,-1, 0}, /* NONSP_REGS */ \
|
||
{0xffffffff,-1,-1,-1,-1,-1,-1,-1,15} /* GENERAL_REGS */ \
|
||
}
|
||
|
||
#define REGNO_REG_CLASS(R) \
|
||
( (R) == REG_IPH ? IPH_REGS \
|
||
: (R) == REG_IPL ? IPL_REGS \
|
||
: (R) == REG_DPH ? DPH_REGS \
|
||
: (R) == REG_DPL ? DPL_REGS \
|
||
: (R) == REG_SPH ? SP_REGS \
|
||
: (R) == REG_SPL ? SP_REGS \
|
||
: NONPTR_REGS)
|
||
|
||
#define MODE_BASE_REG_CLASS(MODE) ((MODE) == QImode ? PTR_REGS : DP_SP_REGS)
|
||
|
||
#define BASE_REG_CLASS PTR_REGS
|
||
|
||
#define INDEX_REG_CLASS NO_REGS
|
||
|
||
#define REG_CLASS_FROM_LETTER(C) \
|
||
( (C) == 'j' ? IPH_REGS \
|
||
: (C) == 'k' ? IPL_REGS \
|
||
: (C) == 'f' ? IP_REGS \
|
||
: (C) == 'y' ? DPH_REGS \
|
||
: (C) == 'z' ? DPL_REGS \
|
||
: (C) == 'b' ? DP_REGS \
|
||
: (C) == 'u' ? NONSP_REGS \
|
||
: (C) == 'q' ? SP_REGS \
|
||
: (C) == 'c' ? DP_SP_REGS \
|
||
: (C) == 'a' ? PTR_REGS \
|
||
: (C) == 'd' ? NONPTR_REGS \
|
||
: NO_REGS)
|
||
|
||
#define REGNO_OK_FOR_BASE_P(R) \
|
||
((R) == REG_DP || (R) == REG_IP || (R) == REG_SP)
|
||
|
||
#define REGNO_MODE_OK_FOR_BASE_P(R,M) \
|
||
((R) == REG_DP || (R) == REG_SP \
|
||
|| ((R) == REG_IP && GET_MODE_SIZE (M) <= 1))
|
||
|
||
#define REGNO_OK_FOR_INDEX_P(NUM) 0
|
||
|
||
#define PREFERRED_RELOAD_CLASS(X, CLASS) (CLASS)
|
||
|
||
#define SMALL_REGISTER_CLASSES 1
|
||
|
||
#define CLASS_LIKELY_SPILLED_P(CLASS) class_likely_spilled_p(CLASS)
|
||
|
||
#define CLASS_MAX_NREGS(CLASS, MODE) GET_MODE_SIZE (MODE)
|
||
|
||
#define CONST_OK_FOR_LETTER_P(VALUE, C) \
|
||
((C) == 'I' ? (VALUE) >= -255 && (VALUE) <= -1 : \
|
||
(C) == 'J' ? (VALUE) >= 0 && (VALUE) <= 7 : \
|
||
(C) == 'K' ? (VALUE) >= 0 && (VALUE) <= 127 : \
|
||
(C) == 'L' ? (VALUE) > 0 && (VALUE) < 128: \
|
||
(C) == 'M' ? (VALUE) == -1: \
|
||
(C) == 'N' ? (VALUE) == 1: \
|
||
(C) == 'O' ? (VALUE) == 0: \
|
||
(C) == 'P' ? (VALUE) >= 0 && (VALUE) <= 255: \
|
||
0)
|
||
|
||
#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C) 0
|
||
|
||
#define EXTRA_CONSTRAINT(X, C) ip2k_extra_constraint (X, C)
|
||
|
||
/* This is an undocumented variable which describes
|
||
how GCC will pop a data. */
|
||
#define STACK_POP_CODE PRE_INC
|
||
|
||
#define STACK_PUSH_CODE POST_DEC
|
||
|
||
#define STACK_CHECK_BUILTIN 1
|
||
/* Prologue code will do stack checking as necessary. */
|
||
|
||
#define STARTING_FRAME_OFFSET (0)
|
||
|
||
#define FRAME_GROWS_DOWNWARD 1
|
||
#define STACK_GROWS_DOWNWARD 1
|
||
|
||
/* On IP2K arg pointer is virtual and resolves to either SP or FP
|
||
after we've resolved what registers are saved (fp chain, return
|
||
pc, etc. */
|
||
|
||
#define FIRST_PARM_OFFSET(FUNDECL) 0
|
||
|
||
#define STACK_POINTER_OFFSET 1
|
||
/* IP2K stack is post-decremented, so 0(sp) is address of open space
|
||
and 1(sp) is offset to the location avobe the forst location at which
|
||
outgoing arguments are placed. */
|
||
|
||
#define STACK_BOUNDARY 8
|
||
|
||
#define STACK_POINTER_REGNUM REG_SP
|
||
|
||
#define FRAME_POINTER_REGNUM REG_VFP
|
||
#define HARD_FRAME_POINTER_REGNUM REG_FP
|
||
|
||
#define ARG_POINTER_REGNUM REG_AP
|
||
|
||
/* We don't really want to support nested functions. But we'll crash
|
||
in various testsuite tests if we don't at least define the register
|
||
to contain the static chain. The return value register is about as
|
||
bad a place as any for this. */
|
||
|
||
#define STATIC_CHAIN_REGNUM REG_RESULT
|
||
|
||
#define FRAME_POINTER_REQUIRED (!flag_omit_frame_pointer)
|
||
|
||
#define ELIMINABLE_REGS { \
|
||
{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
|
||
{ARG_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
|
||
{FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
|
||
{FRAME_POINTER_REGNUM, HARD_FRAME_POINTER_REGNUM}, \
|
||
{HARD_FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
|
||
}
|
||
|
||
#define CAN_ELIMINATE(FROM, TO) \
|
||
((FROM) == HARD_FRAME_POINTER_REGNUM \
|
||
? (flag_omit_frame_pointer && !frame_pointer_needed) : 1)
|
||
/* Don't eliminate FP unless we EXPLICITLY_ASKED */
|
||
|
||
#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
|
||
((OFFSET) = ip2k_init_elim_offset ((FROM), (TO)))
|
||
|
||
#define RETURN_ADDR_RTX(COUNT, X) \
|
||
(((COUNT) == 0) ? gen_rtx_REG (HImode, REG_CALLH) : NULL_RTX)
|
||
|
||
#define PUSH_ROUNDING(NPUSHED) (NPUSHED)
|
||
|
||
#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) \
|
||
ip2k_return_pops_args ((FUNDECL), (FUNTYPE), (SIZE))
|
||
|
||
#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) 0
|
||
|
||
#define CUMULATIVE_ARGS int
|
||
|
||
#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
|
||
((CUM) = 0)
|
||
|
||
#define FUNCTION_ARG_ADVANCE(CUM, MODE, TYPE, NAMED)
|
||
|
||
/* All arguments are passed on stack - do nothing here. */
|
||
|
||
#define FUNCTION_ARG_REGNO_P(R) 0
|
||
|
||
#define FUNCTION_VALUE(VALTYPE, FUNC) \
|
||
((TYPE_MODE (VALTYPE) == QImode) \
|
||
? gen_rtx_REG (TYPE_MODE (VALTYPE), REG_RESULT + 1) \
|
||
: gen_rtx_REG (TYPE_MODE (VALTYPE), REG_RESULT))
|
||
|
||
/* Because functions returning 'char' actually widen to 'int', we have to
|
||
use $81 as the return location if we think we only have a 'char'. */
|
||
|
||
#define LIBCALL_VALUE(MODE) gen_rtx_REG ((MODE), REG_RESULT)
|
||
|
||
#define FUNCTION_VALUE_REGNO_P(N) ((N) == REG_RESULT)
|
||
|
||
/* Indicate that large structures are passed by reference. */
|
||
#define FUNCTION_ARG_PASS_BY_REFERENCE(CUM,MODE,TYPE,NAMED) 0
|
||
|
||
#define DEFAULT_PCC_STRUCT_RETURN 0
|
||
|
||
#define EPILOGUE_USES(REGNO) 0
|
||
|
||
|
||
/* Hmmm. We don't actually like constants as addresses - they always need
|
||
to be loaded to a register, except for function calls which take an
|
||
address by immediate value. But changing this to zero had negative
|
||
effects, causing the compiler to get very confused.... */
|
||
|
||
#define CONSTANT_ADDRESS_P(X) CONSTANT_P (X)
|
||
|
||
#define MAX_REGS_PER_ADDRESS 1
|
||
|
||
#ifdef REG_OK_STRICT
|
||
# define GO_IF_LEGITIMATE_ADDRESS(MODE, OPERAND, ADDR) \
|
||
{ \
|
||
if (legitimate_address_p ((MODE), (OPERAND), 1)) \
|
||
goto ADDR; \
|
||
}
|
||
#else
|
||
# define GO_IF_LEGITIMATE_ADDRESS(MODE, OPERAND, ADDR) \
|
||
{ \
|
||
if (legitimate_address_p ((MODE), (OPERAND), 0)) \
|
||
goto ADDR; \
|
||
}
|
||
#endif
|
||
|
||
#define REG_OK_FOR_BASE_STRICT_P(X) REGNO_OK_FOR_BASE_P (REGNO (X))
|
||
|
||
#define REG_OK_FOR_BASE_NOSTRICT_P(X) \
|
||
(REGNO (X) >= FIRST_PSEUDO_REGISTER \
|
||
|| (REGNO (X) == REG_FP) \
|
||
|| (REGNO (X) == REG_VFP) \
|
||
|| (REGNO (X) == REG_AP) \
|
||
|| REG_OK_FOR_BASE_STRICT_P(X))
|
||
|
||
#ifdef REG_OK_STRICT
|
||
# define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_STRICT_P (X)
|
||
#else
|
||
# define REG_OK_FOR_BASE_P(X) REG_OK_FOR_BASE_NOSTRICT_P (X)
|
||
#endif
|
||
|
||
#define REG_OK_FOR_INDEX_P(X) 0
|
||
|
||
#define LEGITIMIZE_ADDRESS(X,OLDX,MODE,WIN) \
|
||
do { rtx orig_x = (X); \
|
||
(X) = legitimize_address ((X), (OLDX), (MODE), 0); \
|
||
if ((X) != orig_x && memory_address_p ((MODE), (X))) \
|
||
goto WIN; \
|
||
} while (0)
|
||
|
||
/* Is X a legitimate register to reload, or is it a pseudo stack-temp
|
||
that is problematic for push_reload() ? */
|
||
|
||
#define LRA_REG(X) \
|
||
(! (reg_equiv_memory_loc[REGNO (X)] \
|
||
&& (reg_equiv_address[REGNO (X)] \
|
||
|| num_not_at_initial_offset)))
|
||
|
||
/* Given a register X that failed the LRA_REG test, replace X
|
||
by its memory equivalent, find the reloads needed for THAT memory
|
||
location and substitute that back for the higher-level reload
|
||
that we're conducting... */
|
||
|
||
/* WARNING: we reference 'ind_levels' and 'insn' which are local variables
|
||
in find_reloads_address (), where the LEGITIMIZE_RELOAD_ADDRESS macro
|
||
expands. */
|
||
|
||
#define FRA_REG(X,MODE,OPNUM,TYPE) \
|
||
do { \
|
||
rtx tem = make_memloc ((X), REGNO (X)); \
|
||
\
|
||
if (! strict_memory_address_p (GET_MODE (tem), XEXP (tem, 0))) \
|
||
{ \
|
||
/* Note that we're doing address in address - cf. ADDR_TYPE */ \
|
||
find_reloads_address (GET_MODE (tem), &tem, XEXP (tem, 0), \
|
||
&XEXP (tem, 0), (OPNUM), \
|
||
ADDR_TYPE (TYPE), ind_levels, insn); \
|
||
} \
|
||
(X) = tem; \
|
||
} while (0)
|
||
|
||
|
||
/* For the IP2K, we want to be clever about picking IP vs DP for a
|
||
base pointer since IP only directly supports a zero displacement.
|
||
(Note that we have modified all the HI patterns to correctly handle
|
||
IP references by manipulating iph:ipl as we fetch the pieces). */
|
||
#define LEGITIMIZE_RELOAD_ADDRESS(X,MODE,OPNUM,TYPE,IND,WIN) \
|
||
{ \
|
||
if (GET_CODE (X) == PLUS \
|
||
&& REG_P (XEXP (X, 0)) \
|
||
&& GET_CODE (XEXP (X, 1)) == CONST_INT) \
|
||
{ \
|
||
int disp = INTVAL (XEXP (X, 1)); \
|
||
int fit = (disp >= 0 && disp <= (127 - 2 * GET_MODE_SIZE (MODE))); \
|
||
rtx reg = XEXP (X, 0); \
|
||
if (!fit) \
|
||
{ \
|
||
push_reload ((X), NULL_RTX, &(X), \
|
||
NULL, MODE_BASE_REG_CLASS (MODE), GET_MODE (X), \
|
||
VOIDmode, 0, 0, OPNUM, TYPE); \
|
||
goto WIN; \
|
||
} \
|
||
if (reg_equiv_memory_loc[REGNO (reg)] \
|
||
&& (reg_equiv_address[REGNO (reg)] || num_not_at_initial_offset)) \
|
||
{ \
|
||
rtx mem = make_memloc (reg, REGNO (reg)); \
|
||
if (! strict_memory_address_p (GET_MODE (mem), XEXP (mem, 0))) \
|
||
{ \
|
||
/* Note that we're doing address in address - cf. ADDR_TYPE */\
|
||
find_reloads_address (GET_MODE (mem), &mem, XEXP (mem, 0), \
|
||
&XEXP (mem, 0), (OPNUM), \
|
||
ADDR_TYPE (TYPE), (IND), insn); \
|
||
} \
|
||
push_reload (mem, NULL, &XEXP (X, 0), NULL, \
|
||
GENERAL_REGS, Pmode, VOIDmode, 0, 0, \
|
||
OPNUM, TYPE); \
|
||
push_reload (X, NULL, &X, NULL, \
|
||
MODE_BASE_REG_CLASS (MODE), GET_MODE (X), VOIDmode, \
|
||
0, 0, OPNUM, TYPE); \
|
||
goto WIN; \
|
||
} \
|
||
} \
|
||
}
|
||
|
||
#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \
|
||
do { \
|
||
if (ip2k_mode_dependent_address (ADDR)) goto LABEL; \
|
||
} while (0)
|
||
|
||
#define LEGITIMATE_CONSTANT_P(X) 1
|
||
|
||
#define REGISTER_MOVE_COST(MODE, CLASS1, CLASS2) 7
|
||
|
||
#define MEMORY_MOVE_COST(MODE,CLASS,IN) 6
|
||
|
||
#define SLOW_BYTE_ACCESS 0
|
||
|
||
#define NO_FUNCTION_CSE
|
||
#define NO_RECURSIVE_FUNCTION_CSE
|
||
|
||
#define TEXT_SECTION_ASM_OP ".text"
|
||
#define DATA_SECTION_ASM_OP ".data"
|
||
|
||
#define JUMP_TABLES_IN_TEXT_SECTION 1
|
||
|
||
#define ASM_COMMENT_START " ; "
|
||
|
||
#define ASM_APP_ON "/* #APP */\n"
|
||
|
||
#define ASM_APP_OFF "/* #NOAPP */\n"
|
||
|
||
#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \
|
||
fprintf ((STREAM), ".double %.20e\n", (VALUE))
|
||
#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \
|
||
asm_output_float ((STREAM), (VALUE))
|
||
|
||
#define ASM_OUTPUT_INT(FILE, VALUE) \
|
||
( fprintf ((FILE), "\t.long "), \
|
||
output_addr_const ((FILE), (VALUE)), \
|
||
fputs ("\n", (FILE)))
|
||
|
||
#define ASM_OUTPUT_SHORT(FILE,VALUE) \
|
||
asm_output_short ((FILE), (VALUE))
|
||
#define ASM_OUTPUT_CHAR(FILE,VALUE) \
|
||
asm_output_char ((FILE), (VALUE))
|
||
|
||
#define ASM_OUTPUT_BYTE(FILE,VALUE) \
|
||
asm_output_byte ((FILE), (VALUE))
|
||
|
||
#define IS_ASM_LOGICAL_LINE_SEPARATOR(C) \
|
||
((C) == '\n' || ((C) == '$'))
|
||
|
||
#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \
|
||
do { \
|
||
fputs ("\t.comm ", (STREAM)); \
|
||
assemble_name ((STREAM), (NAME)); \
|
||
fprintf ((STREAM), ",%d\n", (int)(SIZE)); \
|
||
} while (0)
|
||
|
||
#define ASM_OUTPUT_LOCAL(STREAM, NAME, SIZE, ROUNDED) \
|
||
do { \
|
||
fputs ("\t.lcomm ", (STREAM)); \
|
||
assemble_name ((STREAM), (NAME)); \
|
||
fprintf ((STREAM), ",%d\n", (int)(SIZE)); \
|
||
} while (0)
|
||
|
||
#undef WEAK_ASM_OP
|
||
#define WEAK_ASM_OP ".weak"
|
||
|
||
#undef ASM_DECLARE_FUNCTION_SIZE
|
||
#define ASM_DECLARE_FUNCTION_SIZE(FILE, FNAME, DECL) \
|
||
do { \
|
||
if (!flag_inhibit_size_directive) \
|
||
ASM_OUTPUT_MEASURED_SIZE (FILE, FNAME); \
|
||
} while (0)
|
||
|
||
#define ESCAPES \
|
||
"\1\1\1\1\1\1\1\1btn\1fr\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
|
||
\0\0\"\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\
|
||
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\\\0\0\0\
|
||
\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\1\
|
||
\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
|
||
\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
|
||
\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\
|
||
\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1\1"
|
||
/* A table of bytes codes used by the ASM_OUTPUT_ASCII and
|
||
ASM_OUTPUT_LIMITED_STRING macros. Each byte in the table
|
||
corresponds to a particular byte value [0..255]. For any
|
||
given byte value, if the value in the corresponding table
|
||
position is zero, the given character can be output directly.
|
||
If the table value is 1, the byte must be output as a \ooo
|
||
octal escape. If the tables value is anything else, then the
|
||
byte value should be output as a \ followed by the value
|
||
in the table. Note that we can use standard UN*X escape
|
||
sequences for many control characters, but we don't use
|
||
\a to represent BEL because some svr4 assemblers (e.g. on
|
||
the i386) don't know about that. Also, we don't use \v
|
||
since some versions of gas, such as 2.2 did not accept it. */
|
||
|
||
/* Globalizing directive for a label. */
|
||
#define GLOBAL_ASM_OP ".global\t"
|
||
|
||
#define REGISTER_NAMES { \
|
||
"$00","$01","$02","$03","iph","ipl","sph","spl", \
|
||
"pch","pcl","wreg","status","dph","dpl","$0e","mulh", \
|
||
"$10","$11","$12","$13","$14","$15","$16","$17", \
|
||
"$18","$19","$1a","$1b","$1c","$1d","$1e","$1f", \
|
||
"$20","$21","$22","$23","$24","$25","$26","$27", \
|
||
"$28","$29","$2a","$2b","$2c","$2d","$2e","$2f", \
|
||
"$30","$31","$32","$33","$34","$35","$36","$37", \
|
||
"$38","$39","$3a","$3b","$3c","$3d","$3e","$3f", \
|
||
"$40","$41","$42","$43","$44","$45","$46","$47", \
|
||
"$48","$49","$4a","$4b","$4c","$4d","$4e","$4f", \
|
||
"$50","$51","$52","$53","$54","$55","$56","$57", \
|
||
"$58","$59","$5a","$5b","$5c","$5d","$5e","$5f", \
|
||
"$60","$61","$62","$63","$64","$65","$66","$67", \
|
||
"$68","$69","$6a","$6b","$6c","$6d","$6e","$6f", \
|
||
"$70","$71","$72","$73","$74","$75","$76","$77", \
|
||
"$78","$79","$7a","$7b","$7c","$7d","callh","calll", \
|
||
"$80","$81","$82","$83","$84","$85","$86","$87", \
|
||
"$88","$89","$8a","$8b","$8c","$8d","$8e","$8f", \
|
||
"$90","$91","$92","$93","$94","$95","$96","$97", \
|
||
"$98","$99","$9a","$9b","$9c","$9d","$9e","$9f", \
|
||
"$a0","$a1","$a2","$a3","$a4","$a5","$a6","$a7", \
|
||
"$a8","$a9","$aa","$ab","$ac","$ad","$ae","$af", \
|
||
"$b0","$b1","$b2","$b3","$b4","$b5","$b6","$b7", \
|
||
"$b8","$b9","$ba","$bb","$bc","$bd","$be","$bf", \
|
||
"$c0","$c1","$c2","$c3","$c4","$c5","$c6","$c7", \
|
||
"$c8","$c9","$ca","$cb","$cc","$cd","$ce","$cf", \
|
||
"$d0","$d1","$d2","$d3","$d4","$d5","$d6","$d7", \
|
||
"$d8","$d9","$da","$db","$dc","$dd","$de","$df", \
|
||
"$e0","$e1","$e2","$e3","$e4","$e5","$e6","$e7", \
|
||
"$e8","$e9","$ea","$eb","$ec","$ed","$ee","$ef", \
|
||
"$f0","$f1","$f2","$f3","$f4","$f5","$f6","$f7", \
|
||
"$f8","$f9","$fa","$fb","$fc","$fd","$fe","$ff", \
|
||
"vfph","vfpl","vaph","vapl"}
|
||
|
||
#define PRINT_OPERAND(STREAM, X, CODE) \
|
||
print_operand ((STREAM), (X), (CODE))
|
||
|
||
#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \
|
||
((CODE) == '<' || (CODE) == '>')
|
||
|
||
#define PRINT_OPERAND_ADDRESS(STREAM, X) print_operand_address(STREAM, X)
|
||
|
||
/* Since register names don't have a prefix, we must preface all
|
||
user identifiers with the '_' to prevent confusion. */
|
||
|
||
#undef USER_LABEL_PREFIX
|
||
#define USER_LABEL_PREFIX "_"
|
||
#define LOCAL_LABEL_PREFIX ".L"
|
||
|
||
#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL) \
|
||
asm_fprintf ((STREAM), "\tpage\t%L%d\n\tjmp\t%L%d\n", (VALUE), (VALUE))
|
||
|
||
/* elfos.h presumes that we will want switch/case dispatch tables aligned.
|
||
This is not so for the ip2k. */
|
||
#undef ASM_OUTPUT_CASE_LABEL
|
||
|
||
#undef ASM_OUTPUT_ADDR_VEC_ELT
|
||
#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \
|
||
asm_fprintf ((STREAM), "\tpage\t%L%d\n\tjmp\t%L%d\n", (VALUE), (VALUE))
|
||
|
||
#define ASM_OUTPUT_ALIGN(STREAM, POWER) \
|
||
fprintf ((STREAM), "\t.align %d\n", (POWER))
|
||
|
||
/* Since instructions are 16 bit word addresses, we should lie and claim that
|
||
the dispatch vectors are in QImode. Otherwise the offset into the jump
|
||
table will be scaled by the MODE_SIZE. */
|
||
|
||
#define CASE_VECTOR_MODE QImode
|
||
|
||
#undef WORD_REGISTER_OPERATIONS
|
||
|
||
#define MOVE_MAX 1
|
||
|
||
#define MOVE_RATIO 3
|
||
/* MOVE_RATIO is the number of move instructions that is better than a
|
||
block move. Make this small on the IP2k, since the code size grows very
|
||
large with each move. */
|
||
|
||
#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
|
||
|
||
#define Pmode HImode
|
||
|
||
#define FUNCTION_MODE HImode
|
||
|
||
#define DOLLARS_IN_IDENTIFIERS 0
|
||
|
||
extern int ip2k_reorg_in_progress;
|
||
/* Flag if we're in the middle of IP2k-specific reorganization. */
|
||
|
||
extern int ip2k_reorg_completed;
|
||
/* Flag if we've completed our IP2k-specific reorganization. If we have
|
||
then we allow quite a few more tricks than before. */
|
||
|
||
extern int ip2k_reorg_split_dimode;
|
||
extern int ip2k_reorg_split_simode;
|
||
extern int ip2k_reorg_split_qimode;
|
||
extern int ip2k_reorg_split_himode;
|
||
/* Flags for various split operations that we run in sequence. */
|
||
|
||
extern int ip2k_reorg_merge_qimode;
|
||
/* Flag to indicate that it's safe to merge QImode operands. */
|
||
|
||
#define TRAMPOLINE_TEMPLATE(FILE) abort ()
|
||
|
||
#define TRAMPOLINE_SIZE 4
|
||
|
||
#define INITIALIZE_TRAMPOLINE(TRAMP, FNADDR, CXT) \
|
||
{ \
|
||
emit_move_insn (gen_rtx_MEM (HImode, plus_constant ((TRAMP), 2)), \
|
||
CXT); \
|
||
emit_move_insn (gen_rtx_MEM (HImode, plus_constant ((TRAMP), 6)), \
|
||
FNADDR); \
|
||
}
|
||
/* Store in cc_status the expressions
|
||
that the condition codes will describe
|
||
after execution of an instruction whose pattern is EXP.
|
||
Do not alter them if the instruction would not alter the cc's. */
|
||
|
||
#define NOTICE_UPDATE_CC(EXP, INSN) (void)(0)
|
||
|
||
/* Output assembler code to FILE to increment profiler label # LABELNO
|
||
for profiling a function entry. */
|
||
|
||
#define FUNCTION_PROFILER(FILE, LABELNO) \
|
||
fprintf ((FILE), "/* profiler %d */", (LABELNO))
|
||
|
||
#define TARGET_MEM_FUNCTIONS
|
||
|
||
#undef ENDFILE_SPEC
|
||
#undef LINK_SPEC
|
||
#undef STARTFILE_SPEC
|
||
|
||
#if defined(__STDC__) || defined(ALMOST_STDC)
|
||
#define AS2(a,b,c) #a "\t" #b "," #c
|
||
#define AS1(a,b) #a "\t" #b
|
||
#else
|
||
#define AS1(a,b) "a b"
|
||
#define AS2(a,b,c) "a b,c"
|
||
#endif
|
||
#define OUT_AS1(a,b) output_asm_insn (AS1 (a,b), operands)
|
||
#define OUT_AS2(a,b,c) output_asm_insn (AS2 (a,b,c), operands)
|
||
#define CR_TAB "\n\t"
|
||
|
||
#define PREDICATE_CODES \
|
||
{"ip2k_ip_operand", {MEM}}, \
|
||
{"ip2k_short_operand", {MEM}}, \
|
||
{"ip2k_gen_operand", {MEM, REG, SUBREG}}, \
|
||
{"ip2k_nonptr_operand", {REG, SUBREG}}, \
|
||
{"ip2k_ptr_operand", {REG, SUBREG}}, \
|
||
{"ip2k_split_dest_operand", {REG, SUBREG, MEM}}, \
|
||
{"ip2k_sp_operand", {REG}}, \
|
||
{"ip2k_nonsp_reg_operand", {REG, SUBREG}}, \
|
||
{"ip2k_symbol_ref_operand", {SYMBOL_REF}}, \
|
||
{"ip2k_binary_operator", {PLUS, MINUS, MULT, DIV, \
|
||
UDIV, MOD, UMOD, AND, IOR, \
|
||
XOR, COMPARE, ASHIFT, \
|
||
ASHIFTRT, LSHIFTRT}}, \
|
||
{"ip2k_unary_operator", {NEG, NOT, SIGN_EXTEND, \
|
||
ZERO_EXTEND}}, \
|
||
{"ip2k_unsigned_comparison_operator", {LTU, GTU, NE, \
|
||
EQ, LEU, GEU}},\
|
||
{"ip2k_signed_comparison_operator", {LT, GT, LE, GE}},
|
||
|
||
#define DWARF2_DEBUGGING_INFO 1
|
||
|
||
#define DWARF2_ASM_LINE_DEBUG_INFO 1
|
||
|
||
#define DBX_REGISTER_NUMBER(REGNO) (REGNO)
|
||
|
||
/* Miscellaneous macros to describe machine specifics. */
|
||
|
||
#define IS_PSEUDO_P(R) (REGNO (R) >= FIRST_PSEUDO_REGISTER)
|
||
|
||
/* Default calculations would cause DWARF address sizes to be 2 bytes,
|
||
but the Harvard architecture of the IP2k and the word-addressed 64k
|
||
of instruction memory causes us to want a 32-bit "address" field. */
|
||
#undef DWARF2_ADDR_SIZE
|
||
#define DWARF2_ADDR_SIZE 4
|
||
|