--- gcc/config/arm/arm.h 2018/04/24 18:10:25 1.1.1.1 +++ gcc/config/arm/arm.h 2018/04/24 18:22:23 1.1.1.3 @@ -1,8 +1,9 @@ /* Definitions of target machine for GNU compiler, for Acorn RISC Machine. - Copyright (C) 1991 Free Software Foundation, Inc. + Copyright (C) 1991, 1993, 1994 Free Software Foundation, Inc. Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) and Martin Simmons (@harleqn.co.uk). - + More major hacks by Richard Earnshaw (rwe11@cl.cam.ac.uk) + This file is part of GNU CC. GNU CC is free software; you can redistribute it and/or modify @@ -23,34 +24,45 @@ the Free Software Foundation, 675 Mass A 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 void output_func_prologue (); +extern void output_func_epilogue (); extern char *output_add_immediate (); extern char *output_call (); +extern char *output_call_mem (); extern char *output_move_double (); extern char *output_mov_double_fpu_from_arm (); extern char *output_mov_double_arm_from_fpu (); +extern char *output_mov_long_double_fpu_from_arm (); +extern char *output_mov_long_double_arm_from_fpu (); +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_arithmetic_with_immediate_multiply (); +extern char *output_return_instruction (); +extern char *output_load_symbol (); +extern char *fp_immediate_constant (); +extern struct rtx_def *gen_compare_reg (); +extern struct rtx_def *arm_gen_store_multiple (); +extern struct rtx_def *arm_gen_load_multiple (); + +extern char *arm_condition_codes[]; + +/* This is needed by the tail-calling peepholes */ +extern int frame_pointer_needed; + -/* Translation to find startup files. On RISCiX boxes, gcrt0.o is in - /usr/lib. */ -#define STARTFILE_SPEC \ - "%{pg:/usr/lib/gcrt0.o%s}%{!pg:%{p:mcrt0.o%s}%{!p:crt0.o%s}}" +#ifndef CPP_PREDEFINES +#define CPP_PREDEFINES "-Darm -Acpu(arm) -Amachine(arm)" +#endif -#ifdef riscos -#define CPP_PREDEFINES "-Darm -Driscos" -#else -#define CPP_PREDEFINES "-Darm -Driscix -Dunix" +#ifndef CPP_SPEC +#define CPP_SPEC "%{m6:-D__arm6__}" #endif /* Run-time Target Specification. */ +#ifndef TARGET_VERSION #define TARGET_VERSION \ - fputs (" (ARM/RISCiX)", stderr); + fputs (" (ARM/generic)", stderr); +#endif /* Run-time compilation parameters selecting different hardware subsets. On the ARM, misuse it in a different way. */ @@ -70,15 +82,75 @@ extern int target_flags; case instruction scheduling becomes very uninteresting. */ #define TARGET_FPE (target_flags & 4) -#define TARGET_SWITCHES \ -{ \ - {"apcs", 1}, \ - {"poke-function-name", 2}, \ - {"fpe", 4}, \ - {"", TARGET_DEFAULT } \ -} +/* Nonzero if destined for an ARM6xx. Takes out bits that assume restoration + of condition flags when returning from a branch & link (ie. a function) */ +#define TARGET_6 (target_flags & 8) + +/* Leave some bits for new processor variants */ + +/* 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) + +/* 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. */ + +#ifndef ARM_EXTRA_TARGET_SWITCHES +#define ARM_EXTRA_TARGET_SWITCHES +#endif + +#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)}, \ + ARM_EXTRA_TARGET_SWITCHES \ + {"", TARGET_DEFAULT } \ +} + +/* Which processor we are running on. Currently this is only used to + get the condition code clobbering attribute right when we are running on + an arm 6 */ + +enum processor_type +{ + PROCESSOR_ARM2, + PROCESSOR_ARM3, + PROCESSOR_ARM6 +}; + +/* Recast the cpu class to be the cpu attribute. */ + +/* Recast the cpu class to be the cpu attribute. */ +#define arm_cpu_attr ((enum attr_cpu)arm_cpu) +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 @@ -88,44 +160,81 @@ extern int target_flags; - 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. */ -#ifdef riscos -#define TARGET_WHEN_DEBUGGING 3 -#else -#define TARGET_WHEN_DEBUGGING 1 -#endif #define OVERRIDE_OPTIONS \ { \ - if (write_symbols != NO_DEBUG) \ - target_flags |= TARGET_WHEN_DEBUGGING; \ - else if (TARGET_POKE_FUNCTION_NAME) \ + if (write_symbols != NO_DEBUG && flag_omit_frame_pointer) \ + warning ("-g without a frame pointer may not give sensible debugging");\ + if (TARGET_POKE_FUNCTION_NAME) \ target_flags |= 1; \ if (TARGET_FPE) \ flag_schedule_insns = flag_schedule_insns_after_reload = 0; \ -} - -/* 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. */ -#define OPTIMIZATION_OPTIONS(OPTIMIZE) \ -{ \ - if (OPTIMIZE) \ - flag_omit_frame_pointer = 1; \ + arm_cpu = TARGET_6 ? PROCESSOR_ARM6: PROCESSOR_ARM2; \ } /* Target machine storage Layout. */ + +/* Define this macro if it is advisable to hold scalars in registers + in a wider mode than that declared by the program. In such cases, + the value is constrained to be within the bounds of the declared + type, but kept valid in the wider mode. The signedness of the + extension may differ from that of the type. */ + +/* 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; \ + else if (MODE == HImode) \ + UNSIGNEDP = TARGET_SHORT_BY_BYTES != 0; \ + (MODE) = SImode; \ + } + +/* Define for XFmode extended real floating point support. + This will automatically cause REAL_ARITHMETIC to be defined. */ +/* For the ARM: + I think I have added all the code to make this work. Unfortunately, + early releases of the floating point emulation code on RISCiX used a + different format for extended precision numbers. On my RISCiX box there + is a bug somewhere which causes the machine to lock up when running enquire + with long doubles. There is the additional aspect that Norcroft C + treats long doubles as doubles and we ought to remain compatible. + Perhaps someone with an FPA coprocessor and not running RISCiX would like + to try this someday. */ +/* #define LONG_DOUBLE_TYPE_SIZE 96 */ + +/* Disable XFmode patterns in md file */ +#define ENABLE_XF_PATTERNS 0 + +/* Define if you don't want extended real, but do want to use the + software floating point emulator for REAL_ARITHMETIC and + decimal <-> binary conversion. */ +/* See comment above */ +#define REAL_ARITHMETIC + /* Define this if most significant bit is lowest numbered 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, but it should now be + possible to build the compiler to support big endian code. (Note: This + is currently a compiler-build-time option, not a run-time one. */ +#ifndef BYTES_BIG_ENDIAN #define BYTES_BIG_ENDIAN 0 +#endif /* Define this if most significant word of a multiword number is the lowest numbered. */ #define WORDS_BIG_ENDIAN 0 +/* Define this if most significant word of doubles is the lowest numbered */ +#define FLOAT_WORDS_BIG_ENDIAN 1 + /* Number of bits in an addressable storage unit */ #define BITS_PER_UNIT 8 @@ -145,11 +254,20 @@ extern int target_flags; #define BIGGEST_ALIGNMENT 32 +/* Make strings word-aligned so strcpy from constants will be faster. */ +#define CONSTANT_ALIGNMENT(EXP, ALIGN) \ + (TREE_CODE (EXP) == STRING_CST \ + && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + /* Every structures size must be a multiple of 32 bits. */ #define STRUCTURE_SIZE_BOUNDARY 32 +/* Non-zero if move instructions will actually fail to work + when given unaligned data. */ #define STRICT_ALIGNMENT 1 +#define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT + /* Define number of bits in most basic integer type. (If undefined, default is BITS_PER_WORD). */ /* #define INT_TYPE_SIZE */ @@ -177,10 +295,43 @@ extern int target_flags; f4-f7 S floating point variable + cc This is NOT a real register, but is used internally + to represent things that use or set the condition + codes. + sfp This isn't either. It is used during rtl generation + since the offset between the frame pointer and the + auto's isn't known until after register allocation. + afp Nor this, we only need this because of non-local + goto. Without it fp appears to be used and the + elimination code won't get rid of sfp. It tracks + fp exactly at all times. + *: See CONDITIONAL_REGISTER_USAGE */ -/* The number of hard registers is 16 ARM + 8 FPU. */ -#define FIRST_PSEUDO_REGISTER 24 +/* The stack backtrace structure is as follows: + fp points to here: | save code pointer | [fp] + | return link value | [fp, #-4] + | return sp value | [fp, #-8] + | return fp value | [fp, #-12] + [| saved r10 value |] + [| saved r9 value |] + [| saved r8 value |] + [| saved r7 value |] + [| saved r6 value |] + [| saved r5 value |] + [| saved r4 value |] + [| saved r3 value |] + [| saved r2 value |] + [| saved r1 value |] + [| saved r0 value |] + [| saved f7 value |] three words + [| saved f6 value |] three words + [| saved f5 value |] three words + [| saved f4 value |] three words + r0-r3 are not normally saved in a C function. */ + +/* The number of hard registers is 16 ARM + 8 FPU + 1 CC + 1 SFP. */ +#define FIRST_PSEUDO_REGISTER 27 /* 1 for registers that have pervasive standard uses and are not available for the register allocator. */ @@ -188,7 +339,8 @@ extern int target_flags; { \ 0,0,0,0,0,0,0,0, \ 0,0,1,1,0,1,0,1, \ - 0,0,0,0,0,0,0,0 \ + 0,0,0,0,0,0,0,0, \ + 1,1,1 \ } /* 1 for registers not available across function calls. @@ -196,12 +348,15 @@ extern int target_flags; registers that can be used without being saved. The latter must include the registers where values are returned and the register where structure-value addresses are passed. - Aside from that, you can include as many other registers as you like. */ + Aside from that, you can include as many other registers as you like. + The CC is not preserved over function calls on the ARM 6, so it is + easier to assume this for all. SFP is preserved, since FP is. */ #define CALL_USED_REGISTERS \ { \ 1,1,1,1,0,0,0,0, \ 0,0,1,1,1,1,1,1, \ - 1,1,1,1,0,0,0,0 \ + 1,1,1,1,0,0,0,0, \ + 1,1,1 \ } /* If doing stupid life analysis, avoid a bug causing a return value r0 to be @@ -221,23 +376,26 @@ extern int target_flags; On the ARM regs are UNITS_PER_WORD bits wide; FPU regs can hold any FP mode. */ -#define HARD_REGNO_NREGS(REGNO, MODE) \ - ((REGNO) >= 16 ? 1 \ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + (((REGNO) >= 16 && REGNO != FRAME_POINTER_REGNUM \ + && (REGNO) != ARG_POINTER_REGNUM) ? 1 \ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) /* Value is 1 if hard register REGNO can hold a value of machine-mode MODE. This is TRUE for ARM regs since they can hold anything, and TRUE for FPU regs holding FP. */ -#define HARD_REGNO_MODE_OK(REGNO, MODE) \ - ((REGNO) < 16 || GET_MODE_CLASS (MODE) == MODE_FLOAT) +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((GET_MODE_CLASS (MODE) == MODE_CC) ? (REGNO == CC_REGNUM) : \ + ((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ + || REGNO == ARG_POINTER_REGNUM \ + || GET_MODE_CLASS (MODE) == MODE_FLOAT)) /* Value is 1 if it is a good idea to tie two pseudo registers when one has mode MODE1 and one has mode MODE2. 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. */ @@ -249,15 +407,25 @@ extern int target_flags; #define STACK_POINTER_REGNUM 13 /* Base register for access to local variables of the function. */ -#define FRAME_POINTER_REGNUM 9 +#define FRAME_POINTER_REGNUM 25 + +/* Define this to be where the real frame pointer is if it is not possible to + work out the offset between the frame pointer and the automatic variables + until after register allocation has taken place. FRAME_POINTER_REGNUM + should point to a special register that we will make sure is eliminated. */ +#define HARD_FRAME_POINTER_REGNUM 11 /* Value should be nonzero if functions must have frame pointers. Zero means the frame pointer need not be set up (and parms may be accessed - via the stack pointer) in functions that seem suitable. */ -#define FRAME_POINTER_REQUIRED 0 + via the stack pointer) in functions that seem suitable. + 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 \ + (current_function_has_nonlocal_label || (TARGET_APCS && !leaf_function_p ())) /* Base register for access to arguments of the function. */ -#define ARG_POINTER_REGNUM 11 +#define ARG_POINTER_REGNUM 26 /* The native (Norcroft) Pascal compiler for the ARM passes the static chain as an invisible last argument (possible since varargs don't exist in @@ -268,14 +436,22 @@ extern int target_flags; is passed to a function. */ #define STRUCT_VALUE_REGNUM 0 +/* Internal, so that we don't need to refer to a raw number */ +#define CC_REGNUM 24 + /* The order in which register should be allocated. It is good to use ip - since no saving is required (though calls clobber it). It is quite good to - use lr since other calls may clobber it anyway. */ + since no saving is required (though calls clobber it) and it never contains + function parameters. It is quite good to use lr since other calls may + clobber it anyway. Allocate r0 through r3 in reverse order since r3 is + least likely to contain a function parameter; in addition results are + returned in r0. + */ #define REG_ALLOC_ORDER \ { \ - 0, 1, 2, 3, 12, 14, 4, 5, \ + 3, 2, 1, 0, 12, 14, 4, 5, \ 6, 7, 8, 10, 9, 11, 13, 15, \ - 16, 17, 18, 19, 20, 21, 22, 23 \ + 16, 17, 18, 19, 20, 21, 22, 23, \ + 24, 25 \ } /* Register and constant classes. */ @@ -306,18 +482,21 @@ enum reg_class of length N_REG_CLASSES. */ #define REG_CLASS_CONTENTS \ { \ - 0x000000, /* NO_REGS */ \ - 0xFF0000, /* FPU_REGS */ \ - 0x00FFFF, /* GENERAL_REGS */ \ - 0xFFFFFF /* ALL_REGS */ \ + 0x0000000, /* NO_REGS */ \ + 0x0FF0000, /* FPU_REGS */ \ + 0x200FFFF, /* GENERAL_REGS */ \ + 0x2FFFFFF /* ALL_REGS */ \ } /* The same information, inverted: Return the class number of the smallest class containing reg number REGNO. This could be a conditional expression or could index an array. */ -#define REGNO_REG_CLASS(REGNO) \ - ((REGNO) < 16 ? GENERAL_REGS : FPU_REGS) +#define REGNO_REG_CLASS(REGNO) \ + (((REGNO) < 16 || REGNO == FRAME_POINTER_REGNUM \ + || REGNO == ARG_POINTER_REGNUM) \ + ? GENERAL_REGS : (REGNO) == CC_REGNUM \ + ? NO_REGS : FPU_REGS) /* The class value for index registers, and the one for base regs. */ #define INDEX_REG_CLASS GENERAL_REGS @@ -334,14 +513,37 @@ enum reg_class C is the letter, and VALUE is a constant value. 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. */ -#define CONST_OK_FOR_LETTER_P(VALUE, C) \ + J: valid indexing constants. + 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' ? (abs (VALUE) < 4096) : 0) + (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) -/* Constant letter 'G' for the FPU immediate constants. */ -#define CONST_DOUBLE_OK_FOR_LETTER_P(X,C) \ - ((C) == 'G' ? const_double_rtx_ok_for_fpu (X) : 0) +/* For the ARM, `Q' means that this is a memory operand that is just + an offset from a register. + `S' means any symbol that has the SYMBOL_REF_FLAG set or a CONSTANT_POOL + address. This means that the symbol is in the text segment and can be + accessed without using a load. */ + +#define EXTRA_CONSTRAINT(OP, C) \ + ((C) == 'Q' ? GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == REG \ + : (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. */ +#define CONST_DOUBLE_OK_FOR_LETTER_P(X,C) \ + ((C) == 'G' ? const_double_rtx_ok_for_fpu (X) \ + : (C) == 'H' ? neg_const_double_rtx_ok_for_fpu (X) : 0) /* Given an rtx X being reloaded into a reg required to be in class CLASS, return the class of reg to actually use. @@ -349,6 +551,19 @@ enum reg_class in some cases it is preferable to use a more restrictive class. */ #define PREFERRED_RELOAD_CLASS(X, CLASS) (CLASS) +/* Return the register class of a scratch register needed to copy IN into + or out of a register in CLASS in MODE. If it can be done directly, + NO_REGS is returned. */ +#define SECONDARY_OUTPUT_RELOAD_CLASS(CLASS,MODE,X) \ + (((MODE) == DFmode && (CLASS) == GENERAL_REGS \ + && true_regnum (X) == -1) ? 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 */ @@ -356,11 +571,11 @@ enum reg_class ((CLASS) == FPU_REGS ? 1 \ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)) -/* Moves between FPU_REGS and GENERAL_REGS are two insns. */ +/* Moves between FPU_REGS and GENERAL_REGS are two memory insns. */ #define REGISTER_MOVE_COST(CLASS1, CLASS2) \ ((((CLASS1) == FPU_REGS && (CLASS2) != FPU_REGS) \ || ((CLASS2) == FPU_REGS && (CLASS1) != FPU_REGS)) \ - ? 4 : 2) + ? 20 : 2) /* Stack layout; function entry, exit and calling. */ @@ -462,7 +677,7 @@ enum reg_class For a library call, FNTYPE is 0. On the ARM, the offset starts at 0. */ #define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME) \ - ((CUM) = (((FNTYPE) && aggregate_value_p (FNTYPE)) ? 4 : 0)) + ((CUM) = (((FNTYPE) && aggregate_value_p (TREE_TYPE ((FNTYPE)))) ? 4 : 0)) /* Update the data in CUM to advance over an argument of mode MODE and data type TYPE. @@ -500,18 +715,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", ARM_REG_PREFIX, ARM_REG_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, @@ -525,18 +739,77 @@ 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. */ -/* #define USE_RETURN_INSN use_return_insn () */ +#define USE_RETURN_INSN use_return_insn () -/* 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) \ - (DEPTH) = (get_frame_size () + 3) & ~3; +/* Definitions for register eliminations. + + This is an array of structures. Each structure initializes one pair + of eliminable registers. The "from" register number is given first, + followed by "to". Eliminations of the same "from" register are listed + in order of preference. + + We have two registers that can be eliminated on the ARM. First, the + arg pointer register can often be eliminated in favor of the stack + pointer register. Secondly, the pseudo frame pointer register can always + be eliminated; it is replaced with either the stack or the real 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}} + +/* Given FROM and TO register numbers, say whether this elimination is allowed. + 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 + pointer, we must eliminate FRAME_POINTER_REGNUM into + HARD_FRAME_POINTER_REGNUM and not into STACK_POINTER_REGNUM. */ +#define CAN_ELIMINATE(FROM, TO) \ + (((TO) == STACK_POINTER_REGNUM && frame_pointer_needed) ? 0 : 1) + +/* Define the offset between two registers, one to be eliminated, and the other + 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)\ + (OFFSET) = (get_frame_size () + 3 & ~3); \ + else \ + { \ + int regno; \ + int offset = 12; \ + int saved_hard_reg = 0; \ + \ + 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 (! frame_pointer_needed) \ + offset -= 16; \ + if (! volatile_func && (regs_ever_live[14] || saved_hard_reg)) \ + offset += 4; \ + (OFFSET) = (get_frame_size () + 3 & ~3) + offset; \ + } \ + } \ +} /* Output assembler code for a block containing the constant parts of a trampoline, leaving space for the variable parts. @@ -547,12 +820,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", ARM_REG_PREFIX, \ + ARM_REG_PREFIX); \ + fprintf ((FILE), "\tldr\t%spc, [%spc, #0]\n", ARM_REG_PREFIX, \ + ARM_REG_PREFIX); \ + fprintf ((FILE), "\t.word\t0\n"); \ + fprintf ((FILE), "\t.word\t0\n"); \ } /* Length in units of the trampoline for entering a nested function. */ @@ -572,17 +847,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. */ @@ -600,15 +864,19 @@ enum reg_class has been allocated, which happens in local-alloc.c. On the ARM, don't allow the pc to be used. */ -#define REGNO_OK_FOR_BASE_P(REGNO) \ - ((REGNO) < 15 || (unsigned) reg_renumber[(REGNO)] < 15) -#define REGNO_OK_FOR_INDEX_P(REGNO) \ +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < 15 || (REGNO) == FRAME_POINTER_REGNUM \ + || (REGNO) == ARG_POINTER_REGNUM \ + || (unsigned) reg_renumber[(REGNO)] < 15 \ + || (unsigned) reg_renumber[(REGNO)] == FRAME_POINTER_REGNUM \ + || (unsigned) reg_renumber[(REGNO)] == ARG_POINTER_REGNUM) +#define REGNO_OK_FOR_INDEX_P(REGNO) \ REGNO_OK_FOR_BASE_P(REGNO) /* Maximum number of registers that can appear in a valid memory address. - The addressing mode [ra,rb, rc] uses the greatest number of - registers. */ -#define MAX_REGS_PER_ADDRESS 3 + Shifts in addresses can't be by a register. */ + +#define MAX_REGS_PER_ADDRESS 2 /* Recognize any constant value that is a valid address. */ /* XXX We can address any constant, eventually... */ @@ -620,8 +888,10 @@ enum reg_class || GET_CODE(X) == CONST ) #endif -#define CONSTANT_ADDRESS_P(X) \ - (GET_CODE (X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (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. @@ -632,10 +902,26 @@ enum reg_class #define LEGITIMATE_CONSTANT_P(X) \ (GET_CODE (X) == CONST_INT \ || (GET_CODE (X) == CONST_DOUBLE \ - && const_double_rtx_ok_for_fpu (X))) -#if 0 - || GET_CODE(X) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P(X)) -#endif + && (const_double_rtx_ok_for_fpu (X) \ + || neg_const_double_rtx_ok_for_fpu (X))) \ + || CONSTANT_ADDRESS_P (X)) + +/* 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. 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 (optimize > 0 && TREE_CONSTANT (decl) \ + && (!flag_writable_strings || TREE_CODE (decl) != STRING_CST)) \ + { \ + rtx rtl = (TREE_CODE_CLASS (TREE_CODE (decl)) != 'd' \ + ? TREE_CST_RTL (decl) : DECL_RTL (decl)); \ + SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1; \ + } \ +} /* The macros REG_OK_FOR..._P assume that the arg is a REG rtx and check its validity for a certain class. @@ -644,23 +930,36 @@ enum reg_class them unless they have been allocated suitable hard regs. The symbol REG_OK_STRICT causes the latter definition to be used. */ #ifndef REG_OK_STRICT + /* Nonzero if X is a hard reg that can be used as a base reg or if it is a pseudo reg. */ -#define REG_OK_FOR_BASE_P(X) \ - (REGNO (X) < 16 || REGNO (X) >= 24) +#define REG_OK_FOR_BASE_P(X) \ + (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + /* Nonzero if X is a hard reg that can be used as an index or if it is a pseudo reg. */ #define REG_OK_FOR_INDEX_P(X) \ REG_OK_FOR_BASE_P(X) -#define REG_OK_FOR_PRE_POST_P(X) \ - (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER) + +#define REG_OK_FOR_PRE_POST_P(X) \ + (REGNO (X) < 16 || REGNO (X) >= FIRST_PSEUDO_REGISTER \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM) + #else + /* Nonzero if X is a hard reg that can be used as a base reg. */ #define REG_OK_FOR_BASE_P(X) REGNO_OK_FOR_BASE_P (REGNO (X)) + /* Nonzero if X is a hard reg that can be used as an index. */ #define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X)) -#define REG_OK_FOR_PRE_POST_P(X) \ - (REGNO (X) < 16 || (unsigned) reg_renumber[REGNO (X)] < 16) + +#define REG_OK_FOR_PRE_POST_P(X) \ + (REGNO (X) < 16 || (unsigned) reg_renumber[REGNO (X)] < 16 \ + || REGNO (X) == FRAME_POINTER_REGNUM || REGNO (X) == ARG_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO (X)] == FRAME_POINTER_REGNUM \ + || (unsigned) reg_renumber[REGNO (X)] == ARG_POINTER_REGNUM) + #endif /* GO_IF_LEGITIMATE_ADDRESS recognizes an RTL expression @@ -678,18 +977,24 @@ enum reg_class /* A C statement (sans semicolon) to jump to LABEL for legitimate index RTXs used by the macro GO_IF_LEGITIMATE_ADDRESS. Floating point indices can only be small constants. */ -#define GO_IF_LEGITIMATE_INDEX(MODE, BASE_REGNO, INDEX, LABEL) \ +#define GO_IF_LEGITIMATE_INDEX(MODE, BASE_REGNO, INDEX, LABEL) \ do \ { \ - int range; \ + HOST_WIDE_INT range; \ + enum rtx_code code = GET_CODE (INDEX); \ \ if (GET_MODE_CLASS (MODE) == MODE_FLOAT) \ - range = 1024; \ + { \ + if (code == CONST_INT && INTVAL (INDEX) < 1024 \ + && INTVAL (INDEX) > -1024 \ + && (INTVAL (INDEX) & 3) == 0) \ + goto LABEL; \ + } \ else \ { \ - if (INDEX_REGISTER_RTX_P (INDEX)) \ + if (INDEX_REGISTER_RTX_P (INDEX) && GET_MODE_SIZE (MODE) <= 4) \ goto LABEL; \ - if (GET_MODE_SIZE (MODE) <= 4 && GET_CODE (INDEX) == MULT) \ + if (GET_MODE_SIZE (MODE) <= 4 && code == MULT) \ { \ rtx xiop0 = XEXP (INDEX, 0); \ rtx xiop1 = XEXP (INDEX, 1); \ @@ -700,20 +1005,29 @@ do \ && power_of_two_operand (xiop0, SImode)) \ goto LABEL; \ } \ - range = 4096; \ + if (GET_MODE_SIZE (MODE) <= 4 \ + && (code == LSHIFTRT || code == ASHIFTRT \ + || code == ASHIFT || code == ROTATERT)) \ + { \ + rtx op = XEXP (INDEX, 1); \ + if (INDEX_REGISTER_RTX_P (XEXP (INDEX, 0)) \ + && GET_CODE (op) == CONST_INT && INTVAL (op) > 0 \ + && INTVAL (op) <= 31) \ + goto LABEL; \ + } \ + range = (MODE) == HImode ? 4095 : 4096; \ + if (code == CONST_INT && INTVAL (INDEX) < range \ + && INTVAL (INDEX) > -range) \ + goto LABEL; \ } \ - \ - if (GET_CODE (INDEX) == CONST_INT && INTVAL (INDEX) < range \ - && INTVAL (INDEX) > -range) \ - goto LABEL; \ } while (0) /* Jump to LABEL if X is a valid address RTX. This must also take REG_OK_STRICT into account when deciding about valid registers, but it uses the above macros so we are in luck. Allow REG, REG+REG, REG+INDEX, INDEX+REG, REG-INDEX, and non floating SYMBOL_REF to the constant pool. - Allow REG-only and AUTINC-REG if handling TImode. Other symbol refs must - be forced though a static cell to ensure addressability. */ + Allow REG-only and AUTINC-REG if handling TImode or HImode. Other symbol + refs must be forced though a static cell to ensure addressability. */ #define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \ { \ if (BASE_REGISTER_RTX_P (X)) \ @@ -768,48 +1082,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) \ @@ -834,11 +1166,10 @@ do \ /* This is the kind of divide that is easiest to do in the general case. */ #define EASY_DIV_EXPR TRUNC_DIV_EXPR -/* 'char' is signed by default on RISCiX, unsigned on RISCOS. */ -#ifdef riscos +/* 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 0 -#else -#define DEFAULT_SIGNED_CHAR 1 #endif /* Don't cse the address of the function being compiled. */ @@ -848,10 +1179,17 @@ do \ in one reasonably fast instruction. */ #define MOVE_MAX 4 -/* Define if normal loads of shorter-than-word items from memory clears - the rest of the bigs in the register. - On the ARM, movhi does a garbage extend. */ -/* #define BYTE_LOADS_ZERO_EXTEND */ +/* Define if operations between registers always perform the operation + on the full register even if a narrower mode is specified. */ +#define WORD_REGISTER_OPERATIONS + +/* Define if loading in MODE, an integral mode narrower than BITS_PER_WORD + 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 \ + : ((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 @@ -866,10 +1204,11 @@ do \ that the native compiler puts too large (> 32) immediate shift counts into a register and shifts by the register, letting the ARM decide what to do instead of doing that itself. */ -#define SHIFT_COUNT_TRUNCATED 1 - -/* We have the vprintf function. */ -#define HAVE_VPRINTF 1 +/* This is all wrong. Defining SHIFT_COUNT_TRUNCATED tells combine that + code like (X << (Y % 32)) for register X, Y is equivalent to (X << Y). + On the arm, Y in a register is used modulo 256 for the shift. Only for + rotates is modulo 32 used. */ +/* #define SHIFT_COUNT_TRUNCATED 1 */ /* XX This is not true, is it? */ /* All integers have the same format so truncation is easy. */ @@ -891,83 +1230,149 @@ do \ /* The relative costs of various types of constants. Note that cse.c defines REG = 1, SUBREG = 2, any node = (2 + sum of subnodes). */ -#define CONST_COSTS(RTX, CODE, OUTER_CODE) \ - case CONST_INT: \ - if (const_ok_for_arm (INTVAL (RTX))) \ - return (2); \ - else \ - return (5); \ - \ - case CONST: \ - case LABEL_REF: \ - case SYMBOL_REF: \ - return (6); \ - \ - case CONST_DOUBLE: \ - if (const_double_rtx_ok_for_fpu (RTX)) \ - return(2); \ - else \ - return(7); +#define CONST_COSTS(RTX, CODE, OUTER_CODE) \ + case CONST_INT: \ + if (const_ok_for_arm (INTVAL (RTX))) \ + return (OUTER_CODE) == SET ? 2 : -1; \ + else if (OUTER_CODE == AND \ + && const_ok_for_arm (~INTVAL (RTX))) \ + return -1; \ + else if ((OUTER_CODE == COMPARE \ + || OUTER_CODE == PLUS || OUTER_CODE == MINUS) \ + && const_ok_for_arm (-INTVAL (RTX))) \ + return -1; \ + else \ + return 5; \ + case CONST: \ + case LABEL_REF: \ + case SYMBOL_REF: \ + return 6; \ + case CONST_DOUBLE: \ + if (const_double_rtx_ok_for_fpu (RTX)) \ + return (OUTER_CODE) == SET ? 2 : -1; \ + else if (((OUTER_CODE) == COMPARE || (OUTER_CODE) == PLUS) \ + && neg_const_double_rtx_ok_for_fpu (RTX)) \ + 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) \ + 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, but rtx cost returns + the same for practically all of them. So we weight the differnt 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 */ +#define BRANCH_COST 4 -/* Condition code information. */ +/* 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, + CCFPmode should be used with floating equalities. + CC_NOOVmode should be used with SImode integer equalites + CCmode should be used otherwise. */ + +#define EXTRA_CC_MODES CC_NOOVmode, CCFPmode, CCFPEmode + +#define EXTRA_CC_NAMES "CC_NOOV", "CCFP", "CCFPE" + +#define SELECT_CC_MODE(OP,X,Y) \ + (GET_MODE_CLASS (GET_MODE (X)) == MODE_FLOAT \ + ? ((OP == EQ || OP == NE) ? CCFPmode : CCFPEmode) \ + : ((GET_MODE (X) == SImode) \ + && ((OP) == EQ || (OP) == NE) \ + && (GET_CODE (X) == PLUS || GET_CODE (X) == MINUS \ + || 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) == 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 + stored from the compare operation. Note that we can't use "rtx" here + since it hasn't been defined! */ + +extern struct rtx_def *arm_compare_op0, *arm_compare_op1; +extern int arm_compare_fp; + +/* Define the codes that are matched by predicates in arm.c */ +#define PREDICATE_CODES \ + {"s_register_operand", {SUBREG, REG}}, \ + {"arm_add_operand", {SUBREG, REG, CONST_INT}}, \ + {"fpu_add_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"arm_rhs_operand", {SUBREG, REG, CONST_INT}}, \ + {"fpu_rhs_operand", {SUBREG, REG, CONST_DOUBLE}}, \ + {"arm_not_operand", {SUBREG, REG, CONST_INT}}, \ + {"shiftable_operator", {PLUS, MINUS, AND, IOR, XOR}}, \ + {"minmax_operator", {SMIN, SMAX, UMIN, UMAX}}, \ + {"shift_operator", {ASHIFT, ASHIFTRT, LSHIFTRT, ROTATERT, MULT}}, \ + {"di_operand", {SUBREG, REG, CONST_INT, 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}}, \ + {"reg_or_int_operand", {SUBREG, REG, CONST_INT}}, \ + {"multi_register_push", {PARALLEL}}, \ + {"cc_register", {REG}}, \ + {"reversible_cc_register", {REG}}, -/* 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. */ - -/* On the ARM nothing sets the condition code implicitly---apart from DImode - operations excluding moves---but we have to watch for registers in the - condition code value being clobbered. This clobbering includes (alas) - function calls. XXX They could just be considered to clobber regs 0-3 and - 10-15 with extra work. */ -#define NOTICE_UPDATE_CC(EXP, INSN) \ -{ \ - if (GET_MODE (EXP) == DImode \ - && GET_CODE (EXP) == SET \ - && GET_CODE (SET_SRC (EXP)) != REG \ - && GET_CODE (SET_SRC (EXP)) != MEM \ - && GET_CODE (SET_SRC (EXP)) != CONST_INT) \ - CC_STATUS_INIT; \ - else if (GET_CODE (EXP) == SET) \ - { \ - rtx dest = SET_DEST (EXP); \ - if (dest == cc0_rtx) \ - { \ - cc_status.flags = 0; \ - cc_status.value1 = SET_DEST (EXP); \ - cc_status.value2 = SET_SRC (EXP); \ - } \ - if (BASE_REGISTER_RTX_P (dest)) \ - { \ - if (cc_status.value1 \ - && reg_overlap_mentioned_p (dest, cc_status.value1)) \ - cc_status.value1 = 0; \ - if (cc_status.value2 \ - && reg_overlap_mentioned_p (dest, cc_status.value2)) \ - cc_status.value2 = 0; \ - } \ - } \ - else if (GET_CODE (INSN) != JUMP_INSN && GET_CODE (EXP) == PARALLEL) \ - { \ - CC_STATUS_INIT; \ - } \ -} /* Assembler output control */ +#ifndef ARM_OS_NAME +#define ARM_OS_NAME "(generic)" +#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/RISCiX\n", version_string); \ - 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,"%c Generated by gcc %s for ARM/%s\n", \ + ARM_COMMENT_CHAR, version_string, ARM_OS_NAME); \ + fprintf (STREAM,"%srfp\t.req\t%sr9\n", ARM_REG_PREFIX, ARM_REG_PREFIX); \ + fprintf (STREAM,"%ssl\t.req\t%sr10\n", ARM_REG_PREFIX, ARM_REG_PREFIX); \ + fprintf (STREAM,"%sfp\t.req\t%sr11\n", ARM_REG_PREFIX, ARM_REG_PREFIX); \ + fprintf (STREAM,"%sip\t.req\t%sr12\n", ARM_REG_PREFIX, ARM_REG_PREFIX); \ + fprintf (STREAM,"%ssp\t.req\t%sr13\n", ARM_REG_PREFIX, ARM_REG_PREFIX); \ + fprintf (STREAM,"%slr\t.req\t%sr14\n", ARM_REG_PREFIX, ARM_REG_PREFIX); \ + fprintf (STREAM,"%spc\t.req\t%sr15\n", ARM_REG_PREFIX, ARM_REG_PREFIX); \ } #define ASM_APP_ON "" @@ -977,26 +1382,69 @@ do \ #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. */ +/* 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", \ - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7" \ + "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 + +#define NO_DOLLAR_IN_LABEL /* DBX register number for a given compiler register number */ #define DBX_REGISTER_NUMBER(REGNO) (REGNO) -/* Generate DBX debugging information. */ +/* Generate DBX debugging information. riscix.h will undefine this because + the native assembler does not support stabs. */ #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). */ +#define DBX_OUTPUT_MAIN_SOURCE_FILENAME(STREAM,NAME) \ +do { \ + fprintf (STREAM, ".stabs \"%s\",%d,0,315,%s\n", (NAME), N_SO, \ + <ext_label_name[1]); \ + text_section (); \ + ASM_OUTPUT_INTERNAL_LABEL (STREAM, "Ltext", 0); \ +} while (0) + /* Output a label definition. */ #define ASM_OUTPUT_LABEL(STREAM,NAME) \ arm_asm_output_label ((STREAM), (NAME)) @@ -1025,12 +1473,17 @@ do \ { \ char *s = (char *) alloca (11 + strlen (PREFIX)); \ extern int arm_target_label, arm_ccfsm_state; \ + extern rtx arm_target_insn; \ \ - if (arm_ccfsm_state == 3 && arm_target_label == (NUM)) \ - arm_ccfsm_state = 0; \ - strcpy (s, "*"); \ - sprintf (&s[strlen (s)], "%s%d", (PREFIX), (NUM)); \ - arm_asm_output_label (STREAM, s); \ + if (arm_ccfsm_state == 3 && arm_target_label == (NUM) \ + && !strcmp (PREFIX, "L")) \ + { \ + arm_ccfsm_state = 0; \ + arm_target_insn = NULL; \ + } \ + strcpy (s, "*"); \ + sprintf (&s[strlen (s)], "%s%d", (PREFIX), (NUM)); \ + arm_asm_output_label (STREAM, s); \ } while (0) /* Nothing special is done about jump tables */ @@ -1043,13 +1496,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", ARM_REG_PREFIX, ARM_REG_PREFIX, \ + reg_names[REGNO]) + +#define ASM_OUTPUT_REG_POP(STREAM,REGNO) \ + fprintf(STREAM,"\tldmfd\t%ssp!,{%s%s}\n", ARM_REG_PREFIX, ARM_REG_PREFIX, \ + reg_names[REGNO]) /* Output a relative address. Not needed since jump tables are absolute but we must define it anyway. */ @@ -1058,22 +1511,60 @@ 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)) - -/* Output various types of constants. */ -#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ - (arm_increase_location (sizeof (double)) \ - , fprintf (STREAM, "\t.double\t%20.20f\n", VALUE)) - -#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ - (arm_increase_location (sizeof (float)) \ - , fprintf (STREAM, "\t.float\t%20.20f\n", VALUE)) + fprintf (STREAM, "\t.word\tL%d\n", VALUE) -#define ASM_OUTPUT_INT(STREAM, EXP) \ - (fprintf (STREAM, "\t.word\t"), \ - output_addr_const (STREAM, (EXP)), \ - arm_increase_location (4), \ +/* 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 + the riscix assembler doesn't understand (it also makes cross-assembling + less likely to fail). */ + +#define ASM_OUTPUT_LONG_DOUBLE(STREAM,VALUE) \ +do { char dstr[30]; \ + long l[3]; \ + arm_increase_location (12); \ + 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%c long double %s\n", \ + l[2], l[1], l[0], ARM_COMMENT_CHAR, dstr); \ + else \ + fprintf (STREAM, "\t.long 0x%lx,0x%lx,0x%lx\t%c long double %s\n",\ + l[0], l[1], l[2], ARM_COMMENT_CHAR, dstr); \ + } while (0) + + +#define ASM_OUTPUT_DOUBLE(STREAM, VALUE) \ +do { char dstr[30]; \ + long l[2]; \ + arm_increase_location (8); \ + 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%c double %s\n", l[0], \ + l[1], ARM_COMMENT_CHAR, dstr); \ + else \ + fprintf (STREAM, "\t.long 0x%lx, 0x%lx\t%c double %s\n", l[0], \ + l[1], ARM_COMMENT_CHAR, dstr); \ + } while (0) + +#define ASM_OUTPUT_FLOAT(STREAM, VALUE) \ +do { char dstr[30]; \ + long l; \ + arm_increase_location (4); \ + 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%c float %s\n", l, \ + ARM_COMMENT_CHAR, dstr); \ + else \ + fprintf (STREAM, "\t.word 0x%lx\t%c float %s\n", l, \ + ARM_COMMENT_CHAR, dstr); \ + } while (0); + +#define ASM_OUTPUT_INT(STREAM, EXP) \ + (fprintf (STREAM, "\t.word\t"), \ + output_addr_const (STREAM, (EXP)), \ + arm_increase_location (4), \ fputc ('\n', STREAM)) #define ASM_OUTPUT_SHORT(STREAM, EXP) \ @@ -1093,7 +1584,7 @@ do \ arm_increase_location (1)) #define ASM_OUTPUT_ASCII(STREAM, PTR, LEN) \ - output_ascii_pseudo_op ((STREAM), (PTR), (LEN)) + output_ascii_pseudo_op ((STREAM), (unsigned char *)(PTR), (LEN)) /* Output a gap. In fact we fill it with nulls. */ #define ASM_OUTPUT_SKIP(STREAM, NBYTES) \ @@ -1118,23 +1609,16 @@ do \ } 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%c%d\n", ROUNDED, ARM_COMMENT_CHAR, 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) */ @@ -1155,81 +1639,34 @@ do \ #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. */ -#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 == 1 || arm_ccfsm_state == 2) \ - { \ - fprintf (STREAM, "@ \t"); \ - arm_ccfsm_state += 2; \ - } \ - else if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4) \ - { \ - for (i = 0; *(PTR) != ' ' && *(PTR) != '\t' && i < 3; i++, (PTR)++) \ - putc (*(PTR), STREAM); \ - fprintf (STREAM, "%s", arm_condition_codes[arm_current_cc]); \ - for (; *(PTR) != ' ' && *(PTR) != '\t'; (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 ARM_COMMENT_CHAR +#define ARM_COMMENT_CHAR '@' +#endif + +/* Default is for register names not to have a prefix. */ +#ifndef ARM_REG_PREFIX +#define ARM_REG_PREFIX "" +#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) == '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) \ - { \ - union real_extract u; \ - u.i[0] = CONST_DOUBLE_LOW (X); \ - u.i[1] = CONST_DOUBLE_HIGH (X); \ - fprintf(STREAM,"#%20.20f",u.d); \ - } \ - 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) \ @@ -1237,14 +1674,14 @@ do \ 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]", ARM_REG_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). */ \ @@ -1259,31 +1696,29 @@ do \ offset = INTVAL (index); \ if (is_minus) \ offset = -offset; \ - fprintf (STREAM, "[%s, #%d]", base_reg_name, offset); \ + fprintf (STREAM, "[%s%s, #%d]", ARM_REG_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]", ARM_REG_PREFIX, \ + base_reg_name, is_minus ? "-" : "", \ + ARM_REG_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); \ + case ASHIFTRT: \ + case LSHIFTRT: \ + case ASHIFT: \ + case ROTATERT: \ + { \ + fprintf (STREAM, "[%s%s, %s%s%s", ARM_REG_PREFIX, \ + base_reg_name, is_minus ? "-" : "", ARM_REG_PREFIX,\ + reg_names[REGNO (XEXP (index, 0))]); \ + arm_print_operand (STREAM, index, 'S'); \ + fputs ("]", STREAM); \ break; \ + } \ \ default: \ abort(); \ @@ -1298,15 +1733,15 @@ do \ 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]!", ARM_REG_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", ARM_REG_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 */