--- gcc/config/arm/arm.h 2018/04/24 18:16:11 1.1.1.2 +++ gcc/config/arm/arm.h 2018/04/24 18:30:05 1.1.1.4 @@ -1,7 +1,7 @@ /* Definitions of target machine for GNU compiler, for Acorn RISC Machine. - Copyright (C) 1991, 1993 Free Software Foundation, Inc. + Copyright (C) 1991, 1993, 1994, 1995 Free Software Foundation, Inc. Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) - and Martin Simmons (@harleqn.co.uk). + and Martin Simmons (@harleqn.co.uk). More major hacks by Richard Earnshaw (rwe11@cl.cam.ac.uk) This file is part of GNU CC. @@ -18,17 +18,15 @@ GNU General Public License for more deta You should have received a copy of the GNU General Public License along with GNU CC; see the file COPYING. If not, write to -the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */ +the Free Software Foundation, 59 Temple Place - Suite 330, +Boston, MA 02111-1307, USA. */ /* Sometimes the directive `riscos' is checked. This does not imply that this tm file can be used unchanged to build a GCC for RISC OS. (Since in fact, it can't.) */ -extern void output_prologue (); -extern void output_epilogue (); -extern char *arm_output_asm_insn (); -extern char *arm_output_llc (); -extern char *arithmetic_instr (); +extern void output_func_prologue (); +extern void output_func_epilogue (); extern char *output_add_immediate (); extern char *output_call (); extern char *output_call_mem (); @@ -40,14 +38,9 @@ extern char *output_mov_long_double_arm_ extern char *output_mov_long_double_arm_from_arm (); extern char *output_mov_immediate (); extern char *output_multi_immediate (); -extern char *output_shifted_move (); -extern char *output_shift_compare (); -extern char *output_arithmetic_with_immediate_multiply (); -extern char *output_arithmetic_with_shift (); extern char *output_return_instruction (); extern char *output_load_symbol (); extern char *fp_immediate_constant (); -extern char *shift_instr (); extern struct rtx_def *gen_compare_reg (); extern struct rtx_def *arm_gen_store_multiple (); extern struct rtx_def *arm_gen_load_multiple (); @@ -94,26 +87,41 @@ extern int target_flags; of condition flags when returning from a branch & link (ie. a function) */ #define TARGET_6 (target_flags & 8) -/* ARM_EXTRA_TARGET_SWITCHES is used in riscix.h to define some options which - are passed to the preprocessor and the assembler post-processor. They - aren't needed in the main pass of the compiler, but if we don't define - them in target switches cc1 complains about them. For the sake of - argument lets allocate bit 31 of target flags for such options. */ +/* Leave some bits for new processor variants */ -#ifndef ARM_EXTRA_TARGET_SWITCHES -#define ARM_EXTRA_TARGET_SWITCHES +/* Nonzero if shorts must be loaded byte at a time. This is not necessary + for the arm processor chip, but it is needed for some MMU chips. */ +#define TARGET_SHORT_BY_BYTES (target_flags & 0x200) + +/* Nonzero if GCC should use a floating point library. + GCC will assume the fp regs don't exist and will not emit any fp insns. + Note that this is different than fp emulation which still uses fp regs + and insns - the kernel catches the trap and performs the operation. */ +#define TARGET_SOFT_FLOAT (target_flags & 0x400) +#define TARGET_HARD_FLOAT (! TARGET_SOFT_FLOAT) + +/* SUBTARGET_SWITCHES is used to add flags on a per-config basis. + Bit 31 is reserved. See riscix.h. */ +#ifndef SUBTARGET_SWITCHES +#define SUBTARGET_SWITCHES #endif -#define TARGET_SWITCHES \ -{ \ - {"apcs", 1}, \ - {"poke-function-name", 2}, \ - {"fpe", 4}, \ - {"6", 8}, \ - {"2", -8}, \ - {"3", -8}, \ - ARM_EXTRA_TARGET_SWITCHES \ - {"", TARGET_DEFAULT } \ +#define TARGET_SWITCHES \ +{ \ + {"apcs", 1}, \ + {"poke-function-name", 2}, \ + {"fpe", 4}, \ + {"6", 8}, \ + {"2", -8}, \ + {"3", -8}, \ + {"short-load-bytes", (0x200)}, \ + {"no-short-load-bytes", -(0x200)}, \ + {"short-load-words", -(0x200)}, \ + {"no-short-load-words", (0x200)}, \ + {"soft-float", (0x400)}, \ + {"hard-float", -(0x400)}, \ + SUBTARGET_SWITCHES \ + {"", TARGET_DEFAULT } \ } /* Which processor we are running on. Currently this is only used to @@ -134,7 +142,21 @@ enum processor_type extern enum processor_type arm_cpu; +/* What sort of floating point unit do we have? Hardware or software. */ +enum floating_point_type +{ + FP_HARD, + FP_SOFT +}; + +/* Recast the floating point class to be the floating point attribute. */ +#define arm_fpu_attr ((enum attr_fpu) arm_fpu) + +extern enum floating_point_type arm_fpu; + +#ifndef TARGET_DEFAULT #define TARGET_DEFAULT 0 +#endif #define TARGET_MEM_FUNCTIONS 1 @@ -144,9 +166,6 @@ extern enum processor_type arm_cpu; - if floating point is done by emulation, forget about instruction scheduling. Note that this only saves compilation time; it doesn't matter for the final code. */ -#ifndef TARGET_WHEN_DEBUGGING -#define TARGET_WHEN_DEBUGGING 1 -#endif #define OVERRIDE_OPTIONS \ { \ @@ -158,19 +177,6 @@ extern enum processor_type arm_cpu; flag_schedule_insns = flag_schedule_insns_after_reload = 0; \ arm_cpu = TARGET_6 ? PROCESSOR_ARM6: PROCESSOR_ARM2; \ } - -/* Omitting the frame pointer is a very good idea on the ARM, especially if - not TARGET_APCS, in which case all that pushing on function entry isn't - mandatory anymore. Unfortunately this is not permitted since we mustn't - change the flags when -g is enabled and without a frame pointer debugging - using dbx is impossible. - Forcing loads to be explicit allows cse to work better */ - -#define OPTIMIZATION_OPTIONS(OPTIMIZE) \ -{ \ - if (OPTIMIZE) \ - flag_force_mem = 1; \ -} /* Target machine storage Layout. */ @@ -184,12 +190,14 @@ extern enum processor_type arm_cpu; /* It is far faster to zero extend chars than to sign extend them */ #define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \ - if (GET_MODE_CLASS (MODE) == MODE_INT \ - && GET_MODE_SIZE (MODE) < 4) \ - { \ - if (MODE == QImode) \ - UNSIGNEDP = 1; \ - (MODE) = SImode; \ + if (GET_MODE_CLASS (MODE) == MODE_INT \ + && GET_MODE_SIZE (MODE) < 4) \ + { \ + if (MODE == QImode) \ + UNSIGNEDP = 1; \ + else if (MODE == HImode) \ + UNSIGNEDP = TARGET_SHORT_BY_BYTES != 0; \ + (MODE) = SImode; \ } /* Define for XFmode extended real floating point support. @@ -218,7 +226,10 @@ extern enum processor_type arm_cpu; in instructions that operate on numbered bit-fields. */ #define BITS_BIG_ENDIAN 0 -/* Define this if most significant byte of a word is the lowest numbered. */ +/* Define this if most significant byte of a word is the lowest numbered. + Most ARM processors are run in little endian mode, so that is the default. + If you want to have it run-time selectable, change the definition in a + cover file to be TARGET_BIG_ENDIAN. */ #define BYTES_BIG_ENDIAN 0 /* Define this if most significant word of a multiword number is the lowest @@ -357,9 +368,15 @@ extern enum processor_type arm_cpu; XXX It is a hack, I know. XXX Is this still needed? */ #define CONDITIONAL_REGISTER_USAGE \ -{ \ - if (obey_regdecls) \ - fixed_regs[0] = 1; \ +{ \ + if (obey_regdecls) \ + fixed_regs[0] = 1; \ + if (TARGET_SOFT_FLOAT) \ + { \ + int regno; \ + for (regno = 16; regno < 24; ++regno) \ + fixed_regs[regno] = call_used_regs[regno] = 1; \ + } \ } /* Return number of consecutive hard regs needed starting at reg REGNO @@ -388,8 +405,7 @@ extern enum processor_type arm_cpu; If HARD_REGNO_MODE_OK could produce different values for MODE1 and MODE2, for any hard reg, then this must be 0 for correct output. */ #define MODES_TIEABLE_P(MODE1, MODE2) \ - (((MODE1) == SFmode || (MODE1) == DFmode) \ - == ((MODE2) == SFmode || (MODE2) == DFmode)) + (GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2)) /* Specify the registers used for certain standard purposes. The values of these macros are register numbers. */ @@ -415,7 +431,8 @@ extern enum processor_type arm_cpu; If we have to have a frame pointer we might as well make use of it. APCS says that the frame pointer does not need to be pushed in leaf functions. */ -#define FRAME_POINTER_REQUIRED (TARGET_APCS && !leaf_function_p ()) +#define FRAME_POINTER_REQUIRED \ + (current_function_has_nonlocal_label || (TARGET_APCS && !leaf_function_p ())) /* Base register for access to arguments of the function. */ #define ARG_POINTER_REGNUM 26 @@ -507,13 +524,17 @@ enum reg_class Return 1 if VALUE is in the range specified by C. I: immediate arithmetic operand (i.e. 8 bits shifted as required). J: valid indexing constants. - K: as I but also (not (value)) ok. - L: as I but also (neg (value)) ok.*/ -#define CONST_OK_FOR_LETTER_P(VALUE, C) \ - ((C) == 'I' ? const_ok_for_arm (VALUE) : \ - (C) == 'J' ? ((VALUE) < 4096 && (VALUE) > -4096) : \ - (C) == 'K' ? (const_ok_for_arm (VALUE) || const_ok_for_arm (~(VALUE))) : \ - (C) == 'L' ? (const_ok_for_arm (VALUE) || const_ok_for_arm (-(VALUE))) : 0) + K: ~value ok in rhs argument of data operand. + L: -value ok in rhs argument of data operand. + M: 0..32, or a power of 2 (for shifts, or mult done by shift). */ +#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + ((C) == 'I' ? const_ok_for_arm (VALUE) : \ + (C) == 'J' ? ((VALUE) < 4096 && (VALUE) > -4096) : \ + (C) == 'K' ? (const_ok_for_arm (~(VALUE))) : \ + (C) == 'L' ? (const_ok_for_arm (-(VALUE))) : \ + (C) == 'M' ? (((VALUE >= 0 && VALUE <= 32)) \ + || (((VALUE) & ((VALUE) - 1)) == 0)) \ + : 0) /* For the ARM, `Q' means that this is a memory operand that is just an offset from a register. @@ -523,7 +544,10 @@ enum reg_class #define EXTRA_CONSTRAINT(OP, C) \ ((C) == 'Q' ? GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == REG \ - : (C) == 'S' ? CONSTANT_ADDRESS_P (OP) : 0) + : (C) == 'R' ? (GET_CODE (OP) == MEM \ + && GET_CODE (XEXP (OP, 0)) == SYMBOL_REF \ + && CONSTANT_POOL_ADDRESS_P (XEXP (OP, 0))) \ + : (C) == 'S' ? (optimize > 0 && CONSTANT_ADDRESS_P (OP)) : 0) /* Constant letter 'G' for the FPU immediate constants. 'H' means the same constant negated. */ @@ -542,9 +566,15 @@ enum reg_class NO_REGS is returned. */ #define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,X) \ (((MODE) == DFmode && (CLASS) == GENERAL_REGS \ - && true_regnum (X) == -1) ? GENERAL_REGS \ + && true_regnum (X) == -1 && TARGET_HARD_FLOAT) \ + ? GENERAL_REGS \ : ((MODE) == HImode && true_regnum (X) == -1) ? GENERAL_REGS : NO_REGS) +/* If we need to load shorts byte-at-a-time, then we need a scratch. */ +#define SECONDARY_INPUT_RELOAD_CLASS(CLASS,MODE,X) \ + (((MODE) == HImode && TARGET_SHORT_BY_BYTES && true_regnum (X) == -1) \ + ? GENERAL_REGS : NO_REGS) + /* Return the maximum number of consecutive registers needed to represent mode MODE in a register of class CLASS. ARM regs are UNITS_PER_WORD bits while FPU regs can hold any FP mode */ @@ -585,34 +615,35 @@ enum reg_class /* Value is the number of byte of arguments automatically popped when returning from a subroutine call. + FUNDECL is the declaration node of the function (as a tree), FUNTYPE is the data type of the function (as a tree), or for a library call it is an identifier node for the subroutine name. SIZE is the number of bytes of arguments passed on the stack. On the ARM, the caller does not pop any of its arguments that were passed on the stack. */ -#define RETURN_POPS_ARGS(FUNTYPE, SIZE) 0 +#define RETURN_POPS_ARGS(FUNDECL,FUNTYPE,SIZE) 0 /* Define how to find the value returned by a function. VALTYPE is the data type of the value (as a tree). If the precise function being called is known, FUNC is its FUNCTION_DECL; otherwise, FUNC is 0. */ #define FUNCTION_VALUE(VALTYPE, FUNC) \ - (GET_MODE_CLASS (TYPE_MODE (VALTYPE)) == MODE_FLOAT \ - ? gen_rtx (REG, TYPE_MODE (VALTYPE), 16) \ + (GET_MODE_CLASS (TYPE_MODE (VALTYPE)) == MODE_FLOAT && TARGET_HARD_FLOAT \ + ? gen_rtx (REG, TYPE_MODE (VALTYPE), 16) \ : gen_rtx (REG, TYPE_MODE (VALTYPE), 0)) /* Define how to find the value returned by a library function assuming the value has mode MODE. */ #define LIBCALL_VALUE(MODE) \ - (GET_MODE_CLASS (MODE) == MODE_FLOAT \ - ? gen_rtx (REG, MODE, 16) \ + (GET_MODE_CLASS (MODE) == MODE_FLOAT && TARGET_HARD_FLOAT \ + ? gen_rtx (REG, MODE, 16) \ : gen_rtx (REG, MODE, 0)) /* 1 if N is a possible register number for a function value. On the ARM, only r0 and f0 can return results. */ #define FUNCTION_VALUE_REGNO_P(REGNO) \ - ((REGNO) == 0 || (REGNO) == 16) + ((REGNO) == 0 || ((REGNO) == 16) && TARGET_HARD_FLOAT) /* Define where to put the arguments to a function. Value is zero to push the argument on the stack, @@ -696,18 +727,17 @@ enum reg_class /* Generate assembly output for the start of a function. */ #define FUNCTION_PROLOGUE(STREAM, SIZE) \ - output_prologue ((STREAM), (SIZE)) + output_func_prologue ((STREAM), (SIZE)) /* Call the function profiler with a given profile label. The Acorn compiler puts this BEFORE the prolog but gcc pust it afterwards. The ``mov ip,lr'' seems like a good idea to stick with cc convention. ``prof'' doesn't seem to mind about this! */ -#define FUNCTION_PROFILER(STREAM,LABELNO) \ -{ \ - fprintf(STREAM, "\tmov\tip, lr\n"); \ - fprintf(STREAM, "\tbl\tmcount\n"); \ - fprintf(STREAM, "\t.word\tLP%d\n", (LABELNO)); \ - arm_increase_location (12); \ +#define FUNCTION_PROFILER(STREAM,LABELNO) \ +{ \ + fprintf(STREAM, "\tmov\t%sip, %slr\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf(STREAM, "\tbl\tmcount\n"); \ + fprintf(STREAM, "\t.word\tLP%d\n", (LABELNO)); \ } /* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, @@ -721,7 +751,7 @@ enum reg_class /* Generate the assembly code for function exit. */ #define FUNCTION_EPILOGUE(STREAM, SIZE) \ - output_epilogue ((STREAM), (SIZE)) + output_func_epilogue ((STREAM), (SIZE)) /* Determine if the epilogue should be output as RTL. You should override this if you define FUNCTION_EXTRA_EPILOGUE. */ @@ -750,7 +780,7 @@ enum reg_class Frame pointer elimination is automatically handled. All eliminations are permissible. Note that ARG_POINTER_REGNUM and - HARD_FRAME_POINTER_REGNUM are infact the same thing. If we need a frame + HARD_FRAME_POINTER_REGNUM are in fact the same thing. If we need a frame pointer, we must eliminate FRAME_POINTER_REGNUM into HARD_FRAME_POINTER_REGNUM and not into STACK_POINTER_REGNUM. */ #define CAN_ELIMINATE(FROM, TO) \ @@ -760,6 +790,7 @@ enum reg_class its replacement, at the start of a routine. */ #define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \ { \ + int volatile_func = arm_volatile_func (); \ if ((FROM) == ARG_POINTER_REGNUM && (TO) == HARD_FRAME_POINTER_REGNUM)\ (OFFSET) = 0; \ else if ((FROM) == FRAME_POINTER_REGNUM && (TO) == STACK_POINTER_REGNUM)\ @@ -768,48 +799,30 @@ enum reg_class { \ int regno; \ int offset = 12; \ + int saved_hard_reg = 0; \ \ - for (regno = 4; regno <= 10; regno++) \ - if (regs_ever_live[regno]) \ - offset += 4; \ - for (regno = 20; regno <=23; regno++) \ - if (regs_ever_live[regno]) \ - offset += 12; \ + if (! volatile_func) \ + { \ + for (regno = 0; regno <= 10; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + saved_hard_reg = 1, offset += 4; \ + for (regno = 16; regno <=23; regno++) \ + if (regs_ever_live[regno] && ! call_used_regs[regno]) \ + offset += 12; \ + } \ if ((FROM) == FRAME_POINTER_REGNUM) \ (OFFSET) = -offset; \ else \ { \ - if (! regs_ever_live[HARD_FRAME_POINTER_REGNUM]) \ + if (! frame_pointer_needed) \ offset -= 16; \ - if (regs_ever_live[14]) \ + if (! volatile_func && (regs_ever_live[14] || saved_hard_reg)) \ offset += 4; \ (OFFSET) = (get_frame_size () + 3 & ~3) + offset; \ } \ } \ } -#if 0 -/* Store in the variable DEPTH the initial difference between the frame - pointer reg contents and the stack pointer reg contents, as of the start of - the function body. This depends on the layout of the fixed parts of the - stack frame and on how registers are saved. */ -#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) \ -{ \ - int regno; \ - int offset = 12; \ - \ - for (regno = 0; regno < FRAME_POINTER_REGNUM; regno++) \ - if (regs_ever_live[regno]) \ - offset += 4; \ - for (regno = 20; regno < 24; regno++) \ - if (regs_ever_live[regno]) \ - offset += 12; \ - (DEPTH) = offset + (get_frame_size () + 3 & ~3); \ -} - -#define INITIAL_FRAME_POINTER_OFFSET(DEPTH) \ - (DEPTH) = (get_frame_size () + 3) & ~3; -#endif /* Output assembler code for a block containing the constant parts of a trampoline, leaving space for the variable parts. @@ -819,12 +832,14 @@ enum reg_class ldr pc, [pc] .word static chain value .word function's address */ -#define TRAMPOLINE_TEMPLATE(FILE) \ -{ \ - fprintf ((FILE), "\tldr\tr8, [pc, #0]\n"); \ - fprintf ((FILE), "\tldr\tpc, [pc, #0]\n"); \ - fprintf ((FILE), "\t.word\t0\n"); \ - fprintf ((FILE), "\t.word\t0\n"); \ +#define TRAMPOLINE_TEMPLATE(FILE) \ +{ \ + fprintf ((FILE), "\tldr\t%sr8, [%spc, #0]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\tldr\t%spc, [%spc, #0]\n", \ + REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.word\t0\n"); \ } /* Length in units of the trampoline for entering a nested function. */ @@ -844,17 +859,6 @@ enum reg_class (FNADDR)); \ } -/* Call the function profiler with a given profile label. The Acorn compiler - puts this BEFORE the prolog but gcc pust it afterwards. The ``mov ip,lr'' - seems like a good idea to stick with cc convention. ``prof'' doesn't seem - to mind about this! */ -#define FUNCTION_PROFILER(STREAM,LABELNO) \ -{ \ - fprintf(STREAM, "\tmov\tip, lr\n"); \ - fprintf(STREAM, "\tbl\tmcount\n"); \ - fprintf(STREAM, "\t.word\tLP%d\n", (LABELNO)); \ - arm_increase_location (12); \ -} /* Addressing modes, and classification of registers for them. */ @@ -896,9 +900,10 @@ enum reg_class || GET_CODE(X) == CONST ) #endif -#define CONSTANT_ADDRESS_P(X) \ - (GET_CODE (X) == SYMBOL_REF \ - && (CONSTANT_POOL_ADDRESS_P (X) || SYMBOL_REF_FLAG (X))) +#define CONSTANT_ADDRESS_P(X) \ + (GET_CODE (X) == SYMBOL_REF \ + && (CONSTANT_POOL_ADDRESS_P (X) \ + || (optimize > 0 && SYMBOL_REF_FLAG (X)))) /* Nonzero if the constant value X is a legitimate general operand. It is given that X satisfies CONSTANT_P or is a CONST_DOUBLE. @@ -915,11 +920,13 @@ enum reg_class /* Symbols in the text segment can be accessed without indirecting via the constant pool; it may take an extra binary operation, but this is still - faster than indirecting via memory. */ + faster than indirecting via memory. Don't do this when not optimizing, + since we won't be calculating al of the offsets necessary to do this + simplification. */ #define ENCODE_SECTION_INFO(decl) \ { \ - if (TREE_CONSTANT (decl) \ + if (optimize > 0 && TREE_CONSTANT (decl) \ && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST)) \ { \ rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd' \ @@ -985,8 +992,8 @@ enum reg_class #define GO_IF_LEGITIMATE_INDEX(MODE, BASE_REGNO, INDEX, LABEL) \ do \ { \ - int range; \ - int code = GET_CODE (INDEX); \ + HOST_WIDE_INT range; \ + enum rtx_code code = GET_CODE (INDEX); \ \ if (GET_MODE_CLASS (MODE) == MODE_FLOAT) \ { \ @@ -1011,7 +1018,7 @@ do \ goto LABEL; \ } \ if (GET_MODE_SIZE (MODE) <= 4 \ - && (code == LSHIFTRT || code == ASHIFTRT || code == LSHIFT \ + && (code == LSHIFTRT || code == ASHIFTRT \ || code == ASHIFT || code == ROTATERT)) \ { \ rtx op = XEXP (INDEX, 1); \ @@ -1087,48 +1094,66 @@ do \ On the ARM, try to convert [REG, #BIGCONST] into ADD BASE, REG, #UPPERCONST and [BASE, #VALIDCONST], where VALIDCONST == 0 in case of TImode. */ -#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ -{ \ - if (GET_CODE (X) == PLUS) \ - { \ - rtx xop0 = XEXP (X, 0); \ - rtx xop1 = XEXP (X, 1); \ - \ - if (BASE_REGISTER_RTX_P (xop0) && GET_CODE (xop1) == CONST_INT) \ - { \ - int n = INTVAL (xop1); \ - int low_n = ((MODE) == TImode ? 0 \ - : n >= 0 ? (n & 0xFFF) : -((-n) & 0xFFF)); \ - rtx base_reg = gen_reg_rtx (SImode); \ - rtx val = force_operand (gen_rtx (PLUS, SImode, xop0, \ - gen_rtx (CONST_INT, \ - VOIDmode, n - low_n)), \ - 0); \ - emit_move_insn (base_reg, val); \ - (X) = (low_n == 0 ? base_reg \ - : gen_rtx (PLUS, SImode, base_reg, \ - gen_rtx (CONST_INT, VOIDmode, low_n))); \ - } \ - else if (BASE_REGISTER_RTX_P (xop1) && GET_CODE (xop0) == CONST_INT) \ - { \ - int n = INTVAL (xop0); \ - int low_n = ((MODE) == TImode ? 0 \ - : n >= 0 ? (n & 0xFFF) : -((-n) & 0xFFF)); \ - rtx base_reg = gen_reg_rtx (SImode); \ - rtx val = force_operand (gen_rtx (PLUS, SImode, xop1, \ - gen_rtx (CONST_INT, \ - VOIDmode, n - low_n)), \ - 0); \ - emit_move_insn (base_reg, val); \ - (X) = (low_n == 0 ? base_reg \ - : gen_rtx (PLUS, SImode, base_reg, \ - gen_rtx (CONST_INT, VOIDmode, low_n))); \ - } \ - } \ - if (memory_address_p (MODE, X)) \ - goto win; \ +#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN) \ +{ \ + if (GET_CODE (X) == PLUS) \ + { \ + rtx xop0 = XEXP (X, 0); \ + rtx xop1 = XEXP (X, 1); \ + \ + if (CONSTANT_P (xop0) && ! LEGITIMATE_CONSTANT_P (xop0)) \ + xop0 = force_reg (SImode, xop0); \ + if (CONSTANT_P (xop1) && ! LEGITIMATE_CONSTANT_P (xop1)) \ + xop1 = force_reg (SImode, xop1); \ + if (BASE_REGISTER_RTX_P (xop0) && GET_CODE (xop1) == CONST_INT) \ + { \ + HOST_WIDE_INT n, low_n; \ + rtx base_reg, val; \ + n = INTVAL (xop1); \ + \ + if (MODE == DImode) \ + { \ + low_n = n & 0x0f; \ + n &= ~0x0f; \ + if (low_n > 4) \ + { \ + n += 16; \ + low_n -= 16; \ + } \ + } \ + else \ + { \ + low_n = ((MODE) == TImode ? 0 \ + : n >= 0 ? (n & 0xfff) : -((-n) & 0xfff)); \ + n -= low_n; \ + } \ + base_reg = gen_reg_rtx (SImode); \ + val = force_operand (gen_rtx (PLUS, SImode, xop0, \ + GEN_INT (n)), NULL_RTX); \ + emit_move_insn (base_reg, val); \ + (X) = (low_n == 0 ? base_reg \ + : gen_rtx (PLUS, SImode, base_reg, GEN_INT (low_n))); \ + } \ + else if (xop0 != XEXP (X, 0) || xop1 != XEXP (x, 1)) \ + (X) = gen_rtx (PLUS, SImode, xop0, xop1); \ + } \ + else if (GET_CODE (X) == MINUS) \ + { \ + rtx xop0 = XEXP (X, 0); \ + rtx xop1 = XEXP (X, 1); \ + \ + if (CONSTANT_P (xop0)) \ + xop0 = force_reg (SImode, xop0); \ + if (CONSTANT_P (xop1) && ! LEGITIMATE_CONSTANT_P (xop1)) \ + xop1 = force_reg (SImode, xop1); \ + if (xop0 != XEXP (X, 0) || xop1 != XEXP (X, 1)) \ + (X) = gen_rtx (MINUS, SImode, xop0, xop1); \ + } \ + if (memory_address_p (MODE, X)) \ + goto WIN; \ } + /* Go to LABEL if ADDR (a legitimate address expression) has an effect that depends on the machine mode it is used for. */ #define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR,LABEL) \ @@ -1156,7 +1181,7 @@ do \ /* signed 'char' is most compatible, but RISC OS wants it unsigned. unsigned is probably best, but may break some code. */ #ifndef DEFAULT_SIGNED_CHAR -#define DEFAULT_SIGNED_CHAR 1 +#define DEFAULT_SIGNED_CHAR 0 #endif /* Don't cse the address of the function being compiled. */ @@ -1174,8 +1199,9 @@ do \ will either zero-extend or sign-extend. The value of this macro should be the code that says which one of the two operations is implicitly done, NIL if none. */ -#define LOAD_EXTEND_OP(MODE) \ - ((MODE) == QImode ? ZERO_EXTEND : NIL) +#define LOAD_EXTEND_OP(MODE) \ + ((MODE) == QImode ? ZERO_EXTEND \ + : ((BYTES_BIG_ENDIAN && (MODE) == HImode) ? SIGN_EXTEND : NIL)) /* Define this if zero-extension is slow (more than one real instruction). On the ARM, it is more than one instruction only if not fetching from @@ -1241,94 +1267,38 @@ do \ return -1; \ return(7); +#define ARM_FRAME_RTX(X) \ + ((X) == frame_pointer_rtx || (X) == stack_pointer_rtx \ + || (X) == arg_pointer_rtx) + #define RTX_COSTS(X,CODE,OUTER_CODE) \ - case MEM: \ - { \ - int num_words = (GET_MODE_SIZE (GET_MODE (X)) > UNITS_PER_WORD) ? 2 : 1;\ - return (COSTS_N_INSNS (10*num_words)); \ - } \ - case MULT: \ - if (GET_CODE (XEXP (X, 1)) == CONST_INT \ - && exact_log2 (INTVAL (XEXP (X, 1))) >= 0) \ - return rtx_cost (XEXP (X, 0), GET_CODE (X))+1; \ - return COSTS_N_INSNS (9); \ - case LSHIFT: \ - case ASHIFT: \ - case LSHIFTRT: \ - case ASHIFTRT: \ - if (GET_CODE (XEXP (X, 1)) == CONST_INT) \ - return rtx_cost (XEXP (X, 0), GET_CODE (X))+1; \ - break; \ - case MINUS: \ - { \ - enum rtx_code code = GET_CODE (XEXP (X, 1)); \ - if (code == MULT) \ - { \ - if (GET_CODE (XEXP (XEXP (X, 1), 1)) == CONST_INT \ - && exact_log2 (INTVAL (XEXP (XEXP (X, 0), 1))) >= 0) \ - return COSTS_N_INSNS (1); \ - break; \ - } \ - else if (code == ASHIFT || code == LSHIFT || code == ASHIFTRT \ - || code == LSHIFTRT) \ - return COSTS_N_INSNS (1); \ - } /* fall through */ \ - case PLUS: \ - case IOR: \ - case XOR: \ - case AND: \ - { \ - enum rtx_code code = GET_CODE (XEXP (X, 0)); \ - if (code == MULT) \ - { \ - if (GET_CODE (XEXP (XEXP (X, 0), 1)) == CONST_INT \ - && exact_log2 (INTVAL (XEXP (XEXP (X, 0), 1))) >= 0) \ - return COSTS_N_INSNS (1); \ - if (GET_CODE (X) == PLUS) \ - return COSTS_N_INSNS (12); \ - break; \ - } \ - else if (code == ASHIFT || code == LSHIFT || code == ASHIFTRT \ - || code == LSHIFTRT) \ - return COSTS_N_INSNS (1); \ - break; \ - } \ - case NOT: \ - return rtx_cost (XEXP (X, 0), GET_CODE (XEXP (X, 0))); \ - case IF_THEN_ELSE: \ - { \ - if (GET_CODE (XEXP(X,1)) == PC || GET_CODE (XEXP(X,2)) == PC) \ - return COSTS_N_INSNS (4); \ - return COSTS_N_INSNS (1); \ - } \ - case SIGN_EXTEND: \ - return COSTS_N_INSNS (2); \ - case ZERO_EXTEND: \ - if (GET_MODE (XEXP (X, 0)) == QImode) \ - { \ - if (GET_CODE (XEXP (X, 0)) == MEM) \ - return COSTS_N_INSNS (10); \ - return COSTS_N_INSNS (1); \ - } \ - break; \ - case COMPARE: \ - if (GET_CODE (XEXP (X, 1)) == REG) \ - return 4; \ - case SMIN: \ - case SMAX: \ - case UMIN: \ - case UMAX: \ - return COSTS_N_INSNS (3); \ - case ABS: \ - if (GET_MODE (X) == SImode) \ - return COSTS_N_INSNS (2); \ - return COSTS_N_INSNS (1); + default: \ + return arm_rtx_costs (X, CODE, OUTER_CODE); /* Moves to and from memory are quite expensive */ #define MEMORY_MOVE_COST(MODE) 10 -/* All address computations that can be done are free */ -#define ADDRESS_COST(x) 2 +/* All address computations that can be done are free, but rtx cost returns + the same for practically all of them. So we weight the different types + of address here in the order (most pref first): + PRE/POST_INC/DEC, SHIFT or NON-INT sum, INT sum, REG, MEM or LABEL. */ +#define ADDRESS_COST(X) \ + (10 - ((GET_CODE (X) == MEM || GET_CODE (X) == LABEL_REF \ + || GET_CODE (X) == SYMBOL_REF) \ + ? 0 \ + : ((GET_CODE (X) == PRE_INC || GET_CODE (X) == PRE_DEC \ + || GET_CODE (X) == POST_INC || GET_CODE (X) == POST_DEC) \ + ? 10 \ + : (((GET_CODE (X) == PLUS || GET_CODE (X) == MINUS) \ + ? 6 + (GET_CODE (XEXP (X, 1)) == CONST_INT ? 2 \ + : ((GET_RTX_CLASS (GET_CODE (XEXP (X, 0))) == '2' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 0))) == 'c' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 1))) == '2' \ + || GET_RTX_CLASS (GET_CODE (XEXP (X, 1))) == 'c') \ + ? 1 : 0)) \ + : 4))))) + + /* Try to generate sequences that don't involve branches, we can then use conditional instructions */ @@ -1337,9 +1307,9 @@ do \ /* Condition code information. */ /* Given a comparison code (EQ, NE, etc.) and the first operand of a COMPARE, return the mode to be used for the comparison. - CCFPEmode should be used with floating inequalites, + CCFPEmode should be used with floating inequalities, CCFPmode should be used with floating equalities. - CC_NOOVmode should be used with SImode integer equalites + CC_NOOVmode should be used with SImode integer equalities. CCmode should be used otherwise. */ #define EXTRA_CC_MODES CC_NOOVmode, CCFPmode, CCFPEmode @@ -1355,12 +1325,14 @@ do \ || GET_CODE (X) == AND || GET_CODE (X) == IOR \ || GET_CODE (X) == XOR || GET_CODE (X) == MULT \ || GET_CODE (X) == NOT || GET_CODE (X) == NEG \ - || GET_CODE (X) == LSHIFT || GET_CODE (X) == LSHIFTRT \ + || GET_CODE (X) == LSHIFTRT \ || GET_CODE (X) == ASHIFT || GET_CODE (X) == ASHIFTRT \ || GET_CODE (X) == ROTATERT || GET_CODE (X) == ZERO_EXTRACT) \ ? CC_NOOVmode \ : GET_MODE (X) == QImode ? CC_NOOVmode : CCmode)) +#define REVERSIBLE_CC_MODE(MODE) ((MODE) != CCFPEmode) + #define STORE_FLAG_VALUE 1 /* Define the information needed to generate branch insns. This is @@ -1380,15 +1352,19 @@ extern int arm_compare_fp; {"arm_not_operand", {SUBREG, REG, CONST_INT}}, \ {"shiftable_operator", {PLUS, MINUS, AND, IOR, XOR}}, \ {"minmax_operator", {SMIN, SMAX, UMIN, UMAX}}, \ - {"shift_operator", {ASHIFT, LSHIFT, ASHIFTRT, LSHIFTRT, MULT}}, \ + {"shift_operator", {ASHIFT, ASHIFTRT, LSHIFTRT, ROTATERT, MULT}}, \ {"di_operand", {SUBREG, REG, CONST_INT, CONST_DOUBLE, MEM}}, \ + {"soft_df_operand", {SUBREG, REG, CONST_DOUBLE, MEM}}, \ {"load_multiple_operation", {PARALLEL}}, \ {"store_multiple_operation", {PARALLEL}}, \ {"equality_operator", {EQ, NE}}, \ {"arm_rhsm_operand", {SUBREG, REG, CONST_INT, MEM}}, \ {"const_shift_operand", {CONST_INT}}, \ {"index_operand", {SUBREG, REG, CONST_INT}}, \ - {"cc_register", {REG}}, + {"reg_or_int_operand", {SUBREG, REG, CONST_INT}}, \ + {"multi_register_push", {PARALLEL}}, \ + {"cc_register", {REG}}, \ + {"reversible_cc_register", {REG}}, /* Assembler output control */ @@ -1398,18 +1374,18 @@ extern int arm_compare_fp; #endif /* The text to go at the start of the assembler file */ -#define ASM_FILE_START(STREAM) \ -{ \ - extern char *version_string; \ - \ - fprintf (STREAM,"@ Generated by gcc %s for ARM/%s\n", version_string, \ - ARM_OS_NAME); \ - fprintf (STREAM,"rfp\t.req\tr9\n"); \ - fprintf (STREAM,"fp\t.req\tr11\n"); \ - fprintf (STREAM,"ip\t.req\tr12\n"); \ - fprintf (STREAM,"sp\t.req\tr13\n"); \ - fprintf (STREAM,"lr\t.req\tr14\n"); \ - fprintf (STREAM,"pc\t.req\tr15\n"); \ +#define ASM_FILE_START(STREAM) \ +{ \ + extern char *version_string; \ + fprintf (STREAM,"%s Generated by gcc %s for ARM/%s\n", \ + ASM_COMMENT_START, version_string, ARM_OS_NAME); \ + fprintf (STREAM,"%srfp\t.req\t%sr9\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf (STREAM,"%ssl\t.req\t%sr10\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf (STREAM,"%sfp\t.req\t%sr11\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf (STREAM,"%sip\t.req\t%sr12\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf (STREAM,"%ssp\t.req\t%sr13\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf (STREAM,"%slr\t.req\t%sr14\n", REGISTER_PREFIX, REGISTER_PREFIX); \ + fprintf (STREAM,"%spc\t.req\t%sr15\n", REGISTER_PREFIX, REGISTER_PREFIX); \ } #define ASM_APP_ON "" @@ -1419,17 +1395,45 @@ extern int arm_compare_fp; #define TEXT_SECTION_ASM_OP ".text" #define DATA_SECTION_ASM_OP ".data" -/* The assembler's names for the registers. RFP need not always be used as - the Real framepointer; it can also be used as a normal general register. - Note that the name `fp' is horribly misleading since `fp' is in fact only - the argument-and-return-context pointer. */ +#define REGISTER_PREFIX "" +#define USER_LABEL_PREFIX "_" +#define LOCAL_LABEL_PREFIX "" + +/* The assembler's names for the registers. */ +#ifndef REGISTER_NAMES #define REGISTER_NAMES \ { \ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \ - "r8","rfp", "sl", "fp", "ip", "sp", "lr", "pc", \ + "r8", "r9", "sl", "fp", "ip", "sp", "lr", "pc", \ "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", \ "cc", "sfp", "afp" \ } +#endif + +#ifndef ADDITIONAL_REGISTER_NAMES +#define ADDITIONAL_REGISTER_NAMES \ +{ \ + {"a1", 0}, \ + {"a2", 1}, \ + {"a3", 2}, \ + {"a4", 3}, \ + {"v1", 4}, \ + {"v2", 5}, \ + {"v3", 6}, \ + {"v4", 7}, \ + {"v5", 8}, \ + {"v6", 9}, \ + {"rfp", 9}, /* Gcc used to call it this */ \ + {"sb", 9}, \ + {"v7", 10}, \ + {"r10", 10}, \ + {"r11", 11}, /* fp */ \ + {"r12", 12}, /* ip */ \ + {"r13", 13}, /* sp */ \ + {"r14", 14}, /* lr */ \ + {"r15", 15} /* pc */ \ +} +#endif /* Arm Assembler barfs on dollars */ #define DOLLARS_IN_IDENTIFIERS 0 @@ -1444,7 +1448,9 @@ extern int arm_compare_fp; #define DBX_DEBUGGING_INFO 1 /* Acorn dbx moans about continuation chars, so don't use any. */ +#ifndef DBX_CONTIN_LENGTH #define DBX_CONTIN_LENGTH 0 +#endif /* Output a source filename for the debugger. RISCiX dbx insists that the ``desc'' field is set to compiler version number >= 315 (sic). */ @@ -1472,7 +1478,7 @@ do { \ /* Output a reference to a label. */ #define ASM_OUTPUT_LABELREF(STREAM,NAME) \ - fprintf (STREAM, "_%s", NAME) + fprintf (STREAM, "%s%s", USER_LABEL_PREFIX, NAME) /* Make an internal label into a string. */ #define ASM_GENERATE_INTERNAL_LABEL(STRING, PREFIX, NUM) \ @@ -1507,13 +1513,13 @@ do { \ sprintf ((OUTVAR), "%s.%d", (NAME), (NUMBER))) /* Output a push or a pop instruction (only used when profiling). */ -#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ - (arm_increase_location (4) \ - , fprintf(STREAM,"\tstmfd\tsp!,{%s}\n", reg_names[REGNO])) - -#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ - (arm_increase_location (4) \ - , fprintf(STREAM,"\tldmfd\tsp!,{%s}\n", reg_names[REGNO])) +#define ASM_OUTPUT_REG_PUSH(STREAM,REGNO) \ + fprintf(STREAM,"\tstmfd\t%ssp!,{%s%s}\n", \ + REGISTER_PREFIX, REGISTER_PREFIX, reg_names[REGNO]) + +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ + fprintf(STREAM,"\tldmfd\t%ssp!,{%s%s}\n", \ + REGISTER_PREFIX, REGISTER_PREFIX, reg_names[REGNO]) /* Output a relative address. Not needed since jump tables are absolute but we must define it anyway. */ @@ -1522,8 +1528,7 @@ do { \ /* Output an element of a dispatch table. */ #define ASM_OUTPUT_ADDR_VEC_ELT(STREAM,VALUE) \ - (arm_increase_location (4) \ - , fprintf (STREAM, "\t.word\tL%d\n", VALUE)) + fprintf (STREAM, "\t.word\tL%d\n", VALUE) /* Output various types of constants. For real numbers we output hex, with a comment containing the "human" value, this allows us to pass NaN's which @@ -1537,11 +1542,11 @@ do { char dstr[30]; \ REAL_VALUE_TO_TARGET_LONG_DOUBLE (VALUE, l); \ REAL_VALUE_TO_DECIMAL (VALUE, "%.20g", dstr); \ if (sizeof (int) == sizeof (long)) \ - fprintf (STREAM, "\t.long 0x%x,0x%x,0x%x\t@ long double %s\n", \ - l[2], l[1], l[0], dstr); \ + fprintf (STREAM, "\t.long 0x%x,0x%x,0x%x\t%s long double %s\n", \ + l[2], l[1], l[0], ASM_COMMENT_START, dstr); \ else \ - fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t@ long double %s\n",\ - l[0], l[1], l[2], dstr); \ + fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%s long double %s\n",\ + l[0], l[1], l[2], ASM_COMMENT_START, dstr); \ } while (0) @@ -1552,11 +1557,11 @@ do { char dstr[30]; \ REAL_VALUE_TO_TARGET_DOUBLE (VALUE, l); \ REAL_VALUE_TO_DECIMAL (VALUE, "%.14g", dstr); \ if (sizeof (int) == sizeof (long)) \ - fprintf (STREAM, "\t.long 0x%x, 0x%x\t@ double %s\n", l[0], l[1],\ - dstr); \ + fprintf (STREAM, "\t.long 0x%x, 0x%x\t%s double %s\n", l[0], \ + l[1], ASM_COMMENT_START, dstr); \ else \ - fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t@ double %s\n", l[0], \ - l[1], dstr); \ + fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%s double %s\n", l[0], \ + l[1], ASM_COMMENT_START, dstr); \ } while (0) #define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ @@ -1566,9 +1571,11 @@ do { char dstr[30]; \ REAL_VALUE_TO_TARGET_SINGLE (VALUE, l); \ REAL_VALUE_TO_DECIMAL (VALUE, "%.7g", dstr); \ if (sizeof (int) == sizeof (long)) \ - fprintf (STREAM, "\t.word 0x%x\t@ float %s\n", l, dstr); \ + fprintf (STREAM, "\t.word 0x%x\t%s float %s\n", l, \ + ASM_COMMENT_START, dstr); \ else \ - fprintf (STREAM, "\t.word 0x%lx\t@ float %s\n", l, dstr); \ + fprintf (STREAM, "\t.word 0x%lx\t%s float %s\n", l, \ + ASM_COMMENT_START, dstr); \ } while (0); #define ASM_OUTPUT_INT(STREAM, EXP) \ @@ -1619,23 +1626,16 @@ do { char dstr[30]; \ } while (0) /* Output a common block */ -#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ - (fprintf (STREAM, "\t.comm\t"), \ - assemble_name ((STREAM), (NAME)), \ - fprintf(STREAM, ", %d\t@%d\n", ROUNDED, SIZE)) +#define ASM_OUTPUT_COMMON(STREAM, NAME, SIZE, ROUNDED) \ + (fprintf (STREAM, "\t.comm\t"), \ + assemble_name ((STREAM), (NAME)), \ + fprintf(STREAM, ", %d\t%s %d\n", ROUNDED, ASM_COMMENT_START, SIZE)) /* Output a local common block. /bin/as can't do this, so hack a `.space' into the bss segment. Note that this is *bad* practice. */ #define ASM_OUTPUT_LOCAL(STREAM,NAME,SIZE,ROUNDED) \ output_lcomm_directive (STREAM, NAME, SIZE, ROUNDED) -/* Output a source filename for the debugger. RISCiX dbx insists that the - ``desc'' field is set to compiler version number >= 315 (sic). */ -#if 0 -#define ASM_OUTPUT_SOURCE_FILENAME(STREAM,NAME) \ - fprintf (STREAM, "\t.stabs\t\"%s\", %d, 0, 315, Ltext\n", (NAME), N_SOL) -#endif - /* Output a source line for the debugger. */ /* #define ASM_OUTPUT_SOURCE_LINE(STREAM,LINE) */ @@ -1656,86 +1656,29 @@ do { char dstr[30]; \ #define TARGET_FF 014 #define TARGET_CR 015 -/* FINAL_PRESCAN_INSN is used to take a look at the insns, in order to delete - small-distance conditional branches and have ASM_OUTPUT_OPCODE make the - instructions conditional. Suffixes like s (affect flags) and b (bytewise - load/store) need to stay suffixes, so the possible condition code comes - before these suffixes. %d or %D may appear in the opcode if - it can take a condition; a null rtx will cause no condition to be added, - this is what we expect to happen if arm_ccfsm_state is non-zero. */ -#define ASM_OUTPUT_OPCODE(STREAM, PTR) \ - { \ - extern int arm_ccfsm_state, arm_current_cc; \ - extern char *arm_condition_codes[]; \ - int i; \ - \ - fflush (STREAM); /* XXX for debugging only. */ \ - if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4) \ - { \ - for (i = 0; *(PTR) != ' ' && *(PTR) != '\t' && *(PTR) != '%' && i < 3;\ - i++, (PTR)++) \ - putc (*(PTR), STREAM); \ - fprintf (STREAM, "%s", arm_condition_codes[arm_current_cc]); \ - for (; *(PTR) != ' ' && *(PTR) != '\t' && *(PTR) != '%'; (PTR)++) \ - putc (*(PTR), STREAM); \ - } \ - } - /* Only perform branch elimination (by making instructions conditional) if we're optimising. Otherwise it's of no use anyway. */ #define FINAL_PRESCAN_INSN(INSN, OPVEC, NOPERANDS) \ if (optimize) \ final_prescan_insn (INSN, OPVEC, NOPERANDS) -/* Output an operand of an instruction. If X is a REG and CODE is `M', output - a ldm/stm style multi-reg. */ +#ifndef ASM_COMMENT_START +#define ASM_COMMENT_START "@" +#endif + +#define PRINT_OPERAND_PUNCT_VALID_P(CODE) \ + ((CODE) == '?' || (CODE) == '|' || (CODE) == '@') +/* Output an operand of an instruction. */ #define PRINT_OPERAND(STREAM, X, CODE) \ -{ \ - if ((CODE) == 'd') \ - { \ - if (X) \ - fputs (arm_condition_codes[get_arm_condition_code (X)], \ - (STREAM)); \ - } \ - else if ((CODE) == 'D') \ - { \ - if (X) \ - fputs (arm_condition_codes[get_arm_condition_code (X) ^ 1], \ - (STREAM)); \ - } \ - else if ((CODE) == 'R') \ - fputs (reg_names[REGNO (X) + 1], (STREAM)); \ - else if (GET_CODE (X) == REG) \ - { \ - if ((CODE) != 'M') \ - fputs (reg_names[REGNO (X)], (STREAM)); \ - else \ - fprintf ((STREAM), "{%s-%s}", \ - reg_names[REGNO (X)], \ - reg_names[REGNO (X) - 1 \ - + ((GET_MODE_SIZE (GET_MODE (X)) \ - + GET_MODE_SIZE (SImode) - 1) \ - / GET_MODE_SIZE (SImode))]); \ - } \ - else if (GET_CODE (X) == MEM) \ - { \ - extern int output_memory_reference_mode; \ - output_memory_reference_mode = GET_MODE (X); \ - output_address (XEXP (X, 0)); \ - } \ - else if (GET_CODE(X) == CONST_DOUBLE) \ - fprintf(STREAM,"#%s", fp_immediate_constant(X)); \ - else if (GET_CODE (X) == NEG) \ - { \ - fputc ('-', (STREAM)); \ - output_operand ((X), 0); \ - } \ - else \ - { \ - fputc('#', STREAM); \ - output_addr_const(STREAM, X); \ - } \ -} + arm_print_operand (STREAM, X, CODE) + +#define ARM_SIGN_EXTEND(x) ((HOST_WIDE_INT) \ + (HOST_BITS_PER_WIDE_INT <= 32 ? (x) \ + : (((x) & (unsigned HOST_WIDE_INT) 0xffffffff) | \ + (((x) & (unsigned HOST_WIDE_INT) 0x80000000) \ + ? ((~ (HOST_WIDE_INT) 0) \ + & ~ (unsigned HOST_WIDE_INT) 0xffffffff) \ + : 0)))) /* Output the address of an operand. */ #define PRINT_OPERAND_ADDRESS(STREAM,X) \ @@ -1743,14 +1686,14 @@ do { char dstr[30]; \ int is_minus = GET_CODE (X) == MINUS; \ \ if (GET_CODE (X) == REG) \ - fprintf (STREAM, "[%s, #0]", reg_names[REGNO (X)]); \ + fprintf (STREAM, "[%s%s, #0]", REGISTER_PREFIX, \ + reg_names[REGNO (X)]); \ else if (GET_CODE (X) == PLUS || is_minus) \ { \ rtx base = XEXP (X, 0); \ rtx index = XEXP (X, 1); \ char *base_reg_name; \ - int offset = 0; \ - int shift; \ + HOST_WIDE_INT offset = 0; \ if (GET_CODE (base) != REG) \ { \ /* Ensure that BASE is a register (one of them must be). */ \ @@ -1765,44 +1708,27 @@ do { char dstr[30]; \ offset = INTVAL (index); \ if (is_minus) \ offset = -offset; \ - fprintf (STREAM, "[%s, #%d]", base_reg_name, offset); \ + fprintf (STREAM, "[%s%s, #%d]", REGISTER_PREFIX, \ + base_reg_name, offset); \ break; \ \ case REG: \ - fprintf (STREAM, "[%s, %s%s]", base_reg_name, \ - is_minus ? "-" : "", reg_names[REGNO (index)] ); \ + fprintf (STREAM, "[%s%s, %s%s%s]", REGISTER_PREFIX, \ + base_reg_name, is_minus ? "-" : "", \ + REGISTER_PREFIX, reg_names[REGNO (index)] ); \ break; \ \ case MULT: \ - if (GET_CODE (XEXP (index,0)) == CONST_INT) \ - { \ - shift = int_log2 (INTVAL (XEXP (index, 0))); \ - index = XEXP (index, 1); \ - } \ - else if (GET_CODE(XEXP(index,1)) == CONST_INT) \ - { \ - shift = int_log2 (INTVAL (XEXP (index, 1))); \ - index = XEXP (index, 0); \ - } \ - else \ - abort(); \ - fprintf (STREAM, "[%s, %s%s, asl #%d]", base_reg_name, \ - is_minus ? "-" : "", reg_names[REGNO (index)], \ - shift); \ - break; \ case ASHIFTRT: \ case LSHIFTRT: \ case ASHIFT: \ - case LSHIFT: \ case ROTATERT: \ { \ - char *shift_type = shift_instr (GET_CODE (index), \ - &XEXP (index, 1)); \ - shift = INTVAL (XEXP (index, 1)); \ - index = XEXP (index, 0); \ - fprintf (STREAM, "[%s, %s%s, %s #%d]", base_reg_name, \ - is_minus ? "-" : "", reg_names[REGNO (index)], \ - shift_type, shift); \ + fprintf (STREAM, "[%s%s, %s%s%s", REGISTER_PREFIX, \ + base_reg_name, is_minus ? "-" : "", REGISTER_PREFIX,\ + reg_names[REGNO (XEXP (index, 0))]); \ + arm_print_operand (STREAM, index, 'S'); \ + fputs ("]", STREAM); \ break; \ } \ \ @@ -1819,15 +1745,15 @@ do { char dstr[30]; \ abort (); \ \ if (GET_CODE (X) == PRE_DEC || GET_CODE (X) == PRE_INC) \ - fprintf (STREAM, "[%s, #%s%d]!", reg_names[REGNO (XEXP (X, 0))],\ + fprintf (STREAM, "[%s%s, #%s%d]!", REGISTER_PREFIX, \ + reg_names[REGNO (XEXP (X, 0))], \ GET_CODE (X) == PRE_DEC ? "-" : "", \ GET_MODE_SIZE (output_memory_reference_mode)); \ else \ - fprintf (STREAM, "[%s], #%s%d", reg_names[REGNO (XEXP (X, 0))], \ + fprintf (STREAM, "[%s%s], #%s%d", REGISTER_PREFIX, \ + reg_names[REGNO (XEXP (X, 0))], \ GET_CODE (X) == POST_DEC ? "-" : "", \ GET_MODE_SIZE (output_memory_reference_mode)); \ } \ else output_addr_const(STREAM, X); \ } - -/* EOF arm.h */