--- gcc/config/m88k.h 2018/04/24 17:51:33 1.1 +++ gcc/config/m88k.h 2018/04/24 18:04:42 1.1.1.4 @@ -83,6 +83,8 @@ enum m88k_instruction { extern char *m88k_pound_sign; extern char *m88k_short_data; +extern char *m88k_version; +extern char m88k_volatile_code; extern int m88k_gp_threshold; extern int m88k_prologue_done; @@ -90,22 +92,27 @@ extern int m88k_function_number; extern int m88k_fp_offset; extern int m88k_stack_size; extern int m88k_case_index; +extern int m88k_version_0300; extern struct rtx_def *m88k_compare_reg; extern struct rtx_def *m88k_compare_op0; extern struct rtx_def *m88k_compare_op1; -extern int null_epilogue (); +extern enum attr_cpu m88k_cpu; + +extern int null_prologue (); extern int integer_ok_for_set (); extern int m88k_debugger_offset (); -extern void m88k_handle_pragma_token (); extern void emit_bcnd (); extern void expand_block_move (); -extern void check_float_value (); extern void m88k_layout_frame (); -extern void m88k_output_prologue (); -extern void m88k_output_epilogue (); +extern void m88k_expand_prologue (); +extern void m88k_begin_prologue (); +extern void m88k_end_prologue (); +extern void m88k_expand_epilogue (); +extern void m88k_begin_epilogue (); +extern void m88k_end_epilogue (); extern void output_function_profiler (); extern void output_function_block_profiler (); extern void output_block_profiler (); @@ -184,6 +191,12 @@ extern char * reg_names[]; } \ } while (0) +/* If -m88100 is in effect, add -D__m88100__; similarly for -m88110. + Here, the CPU_DEFAULT is assumed to be -m88100. */ +#undef CPP_SPEC +#define CPP_SPEC "%{!m88000:%{!m88100:%{m88110:-D__m88110__}}} \ + %{!m88000:%{!m88110:-D__m88100__}}" + /* LIB_SPEC, LINK_SPEC, and STARTFILE_SPEC defined in svr3.h. ASM_SPEC, ASM_FINAL_SPEC, LIB_SPEC, LINK_SPEC, and STARTFILE_SPEC redefined in svr4.h. @@ -202,9 +215,9 @@ extern char * reg_names[]; /* Print subsidiary information on the compiler version in use. Redefined in m88kv4.h, and m88kluna.h. */ #define VERSION_INFO1 "88open OCS/BCS, " -#define VERSION_INFO2 "12 Feb 1992" +#define VERSION_INFO2 "10/21/92" #define VERSION_STRING version_string -#define TM_SCCS_ID "@(#)m88k.h 1.96.5.5 12 Feb 1992 12:59:25" +#define TM_SCCS_ID "@(#)m88k.h 2.2.14.1 10/21/92 23:03:03" /* Run-time compilation parameters selecting different hardware subsets. */ @@ -219,7 +232,6 @@ extern char * reg_names[]; #define MASK_OCS_DEBUG_INFO 0x00000004 /* Emit .tdesc info */ #define MASK_OCS_FRAME_POSITION 0x00000008 /* Debug frame = CFA, not r30 */ #define MASK_SVR4 0x00000010 /* Target is AT&T System V.4 */ -#define MASK_VERSION_0300 0x00000020 /* Use version 03.00 syntax */ #define MASK_NO_UNDERSCORES 0x00000040 /* Don't emit a leading `_' */ #define MASK_BIG_PIC 0x00000080 /* PIC with large got-rel's -fPIC */ #define MASK_TRAP_LARGE_SHIFT 0x00000100 /* Trap if shift not <= 31 */ @@ -229,10 +241,13 @@ extern char * reg_names[]; #define MASK_IDENTIFY_REVISION 0x00001000 /* Emit ident, with GCC rev */ #define MASK_WARN_PASS_STRUCT 0x00002000 /* Warn about passed structs */ #define MASK_OPTIMIZE_ARG_AREA 0x00004000 /* Save stack space */ +#define MASK_SERIALIZE_VOLATILE 0x00008000 /* Serialize volatile refs */ +#define MASK_NO_SERIALIZE_VOLATILE 0x00010000 /* Don't serialize */ #define MASK_88000 (MASK_88100 | MASK_88110) #define MASK_EITHER_LARGE_SHIFT (MASK_TRAP_LARGE_SHIFT | \ MASK_HANDLE_LARGE_SHIFT) +#define MASK_SERIALIZE (MASK_SERIALIZE_VOLATILE | MASK_NO_SERIALIZE_VOLATILE) #define TARGET_88100 ((target_flags & MASK_88000) == MASK_88100) #define TARGET_88110 ((target_flags & MASK_88000) == MASK_88110) @@ -241,7 +256,6 @@ extern char * reg_names[]; #define TARGET_OCS_DEBUG_INFO (target_flags & MASK_OCS_DEBUG_INFO) #define TARGET_OCS_FRAME_POSITION (target_flags & MASK_OCS_FRAME_POSITION) #define TARGET_SVR4 (target_flags & MASK_SVR4) -#define TARGET_VERSION_0300 (target_flags & MASK_VERSION_0300) #define TARGET_NO_UNDERSCORES (target_flags & MASK_NO_UNDERSCORES) #define TARGET_BIG_PIC (target_flags & MASK_BIG_PIC) #define TARGET_TRAP_LARGE_SHIFT (target_flags & MASK_TRAP_LARGE_SHIFT) @@ -251,6 +265,7 @@ extern char * reg_names[]; #define TARGET_IDENTIFY_REVISION (target_flags & MASK_IDENTIFY_REVISION) #define TARGET_WARN_PASS_STRUCT (target_flags & MASK_WARN_PASS_STRUCT) #define TARGET_OPTIMIZE_ARG_AREA (target_flags & MASK_OPTIMIZE_ARG_AREA) +#define TARGET_SERIALIZE_VOLATILE (target_flags & MASK_SERIALIZE_VOLATILE) #define TARGET_EITHER_LARGE_SHIFT (target_flags & MASK_EITHER_LARGE_SHIFT) @@ -269,7 +284,6 @@ extern char * reg_names[]; { "no-ocs-frame-position", -MASK_OCS_FRAME_POSITION }, \ { "svr4", MASK_SVR4 }, \ { "svr3", -MASK_SVR4 }, \ - { "version-03.00", MASK_VERSION_0300 }, \ { "no-underscores", MASK_NO_UNDERSCORES }, \ { "big-pic", MASK_BIG_PIC }, \ { "trap-large-shift", MASK_TRAP_LARGE_SHIFT }, \ @@ -281,6 +295,8 @@ extern char * reg_names[]; { "warn-passed-structs", MASK_WARN_PASS_STRUCT }, \ { "optimize-arg-area", MASK_OPTIMIZE_ARG_AREA }, \ { "no-optimize-arg-area", -MASK_OPTIMIZE_ARG_AREA }, \ + { "serialize-volatile", MASK_SERIALIZE_VOLATILE }, \ + { "no-serialize-volatile", MASK_NO_SERIALIZE_VOLATILE }, \ SUBTARGET_SWITCHES \ /* Default switches */ \ { "", TARGET_DEFAULT }, \ @@ -291,7 +307,8 @@ extern char * reg_names[]; /* Macro to define table for command options with values. */ -#define TARGET_OPTIONS { { "short-data-", &m88k_short_data } } +#define TARGET_OPTIONS { { "short-data-", &m88k_short_data }, \ + { "version-", &m88k_version } } /* Do any checking or such that is needed after processing the -m switches. */ @@ -302,19 +319,39 @@ extern char * reg_names[]; if ((target_flags & MASK_88000) == 0) \ target_flags |= CPU_DEFAULT; \ \ + m88k_cpu = (TARGET_88000 ? CPU_M88000 \ + : (TARGET_88100 ? CPU_M88100 : CPU_M88110)); \ + \ + if (! TARGET_88100 && (target_flags & MASK_SERIALIZE) == 0) \ + target_flags |= MASK_SERIALIZE_VOLATILE; \ + \ + if ((target_flags & MASK_NO_SERIALIZE_VOLATILE) != 0) \ + target_flags &= ~MASK_SERIALIZE_VOLATILE; \ + \ if (TARGET_BIG_PIC) \ flag_pic = 2; \ \ if ((target_flags & MASK_EITHER_LARGE_SHIFT) == MASK_EITHER_LARGE_SHIFT) \ error ("-mtrap-large-shift and -mhandle-large-shift are incompatible");\ \ + m88k_version_0300 = (m88k_version != 0 \ + && strcmp (m88k_version, "03.00") >= 0); \ + \ if (VERSION_0300_SYNTAX) \ { \ for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) \ reg_names[i]--; \ m88k_pound_sign = "#"; \ + if (m88k_version == 0) \ + m88k_version = "03.00"; \ + else if (strcmp (m88k_version, "03.00") < 0) \ + error ("Specified assembler version (%s) is less that 03.00", \ + m88k_version); \ } \ \ + m88k_version_0300 = (m88k_version != 0 \ + && strcmp (m88k_version, "03.00") >= 0); \ + \ if (m88k_short_data) \ { \ char *p = m88k_short_data; \ @@ -359,7 +396,7 @@ extern char * reg_names[]; instructions for them. */ #define WORDS_BIG_ENDIAN 1 -/* Number of bits in an addressible storage unit */ +/* Number of bits in an addressable storage unit */ #define BITS_PER_UNIT 8 /* Width in bits of a "word", which is the contents of a machine register. @@ -384,23 +421,30 @@ extern char * reg_names[]; /* Boundary (in *bits*) on which stack pointer should be aligned. */ #define STACK_BOUNDARY 128 -/* Allocation boundary (in *bits*) for the code of a function. - Pack code tightly when compiling crtstuff.c. */ -#define FUNCTION_BOUNDARY (flag_inhibit_size_directive ? 32 : 128) +/* Allocation boundary (in *bits*) for the code of a function. On the + m88100, it is desirable to align to a cache line. However, SVR3 targets + only provided 8 byte alignment. The m88110 cache is small, so align + to an 8 byte boundary. Pack code tightly when compiling crtstuff.c. */ +#define FUNCTION_BOUNDARY (flag_inhibit_size_directive ? 32 : \ + (TARGET_88100 && TARGET_SVR4 ? 128 : 64)) /* No data type wants to be aligned rounder than this. */ #define BIGGEST_ALIGNMENT 64 -/* Make strings word-aligned so strcpy from constants will be faster. */ +/* The best alignment to use in cases where we have a choice. */ +#define FASTEST_ALIGNMENT (TARGET_88100 ? 32 : 64) + +/* Make strings 4/8 byte 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)) + ((TREE_CODE (EXP) == STRING_CST \ + && (ALIGN) < FASTEST_ALIGNMENT) \ + ? FASTEST_ALIGNMENT : (ALIGN)) -/* Make arrays of chars word-aligned for the same reasons. */ +/* Make arrays of chars 4/8 byte aligned for the same reasons. */ #define DATA_ALIGNMENT(TYPE, ALIGN) \ (TREE_CODE (TYPE) == ARRAY_TYPE \ && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \ - && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN)) + && (ALIGN) < FASTEST_ALIGNMENT ? FASTEST_ALIGNMENT : (ALIGN)) /* Alignment of field after `int : 0' in a structure. Ignored with PCC_BITFIELD_TYPE_MATTERS. */ @@ -409,9 +453,9 @@ extern char * reg_names[]; /* Every structure's size must be a multiple of this. */ #define STRUCTURE_SIZE_BOUNDARY 8 -/* Define this if move instructions will actually fail to work +/* Set this nonzero if move instructions will actually fail to work when given unaligned data. */ -#define STRICT_ALIGNMENT +#define STRICT_ALIGNMENT 1 /* A bitfield declared as `int' forces `int' alignment for the struct. */ #define PCC_BITFIELD_TYPE_MATTERS 1 @@ -420,10 +464,10 @@ extern char * reg_names[]; replaces a BLKmode type. */ /* #define MAX_FIXED_MODE_SIZE 0 */ -/* Report errors on floating point, if we are given NaN's, or such. Leave - the number as is, though, since we output the number in hex, and the - assemble won't choak on it. */ -#define CHECK_FLOAT_VALUE(MODE,VALUE) check_float_value (MODE, VALUE) +/* Check a `double' value for validity for a particular machine mode. + This is defined to avoid crashes outputting certain constants. + Since we output the number in hex, the assembler won't choke on it. */ +/* #define CHECK_FLOAT_VALUE(MODE,VALUE) */ /* A code distinguishing the floating point format of the target machine. */ /* #define TARGET_FLOAT_FORMAT IEEE_FLOAT_FORMAT */ @@ -436,21 +480,107 @@ extern char * reg_names[]; All registers that the compiler knows about must be given numbers, even those that are not normally considered general registers. - The m88100 has 32 fullword registers. - - The pseudo argument pointer is said to be register 0. This prohibits - the use of r0 as a general register and causes no trouble. - Using register 0 is useful, in that it keeps the number of - registers down to 32, and GNU can use a long as a bitmask - for the registers. */ -#define FIRST_PSEUDO_REGISTER 32 - -/* 1 for registers that have pervasive standard uses - and are not available for the register allocator. - Registers 14-25 are expected to be preserved across - function calls. + The m88100 has a General Register File (GRF) of 32 32-bit registers. + The m88110 adds an Extended Register File (XRF) of 32 80-bit registers. */ +#define FIRST_PSEUDO_REGISTER 64 +#define FIRST_EXTENDED_REGISTER 32 + +/* General notes on extended registers, their use and misuse. + + Possible good uses: + + spill area instead of memory. + -waste if only used once + + floating point calculations + -probably a waste unless we have run out of general purpose registers + + freeing up general purpose registers + -e.g. may be able to have more loop invariants if floating + point is moved into extended registers. + + + I've noticed wasteful moves into and out of extended registers; e.g. a load + into x21, then inside a loop a move into r24, then r24 used as input to + an fadd. Why not just load into r24 to begin with? Maybe the new cse.c + will address this. This wastes a move, but the load,store and move could + have been saved had extended registers been used throughout. + E.g. in the code following code, if z and xz are placed in extended + registers, there is no need to save preserve registers. + + long c=1,d=1,e=1,f=1,g=1,h=1,i=1,j=1,k; + + double z=0,xz=4.5; + + foo(a,b) + long a,b; + { + while (a < b) + { + k = b + c + d + e + f + g + h + a + i + j++; + z += xz; + a++; + } + printf("k= %d; z=%f;\n", k, z); + } + + I've found that it is possible to change the constraints (putting * before + the 'r' constraints int the fadd.ddd instruction) and get the entire + addition and store to go into extended registers. However, this also + forces simple addition and return of floating point arguments to a + function into extended registers. Not the correct solution. + + Found the following note in local-alloc.c which may explain why I can't + get both registers to be in extended registers since two are allocated in + local-alloc and one in global-alloc. Doesn't explain (I don't believe) + why an extended register is used instead of just using the preserve + register. + + from local-alloc.c: + We have provision to exempt registers, even when they are contained + within the block, that can be tied to others that are not contained in it. + This is so that global_alloc could process them both and tie them then. + But this is currently disabled since tying in global_alloc is not + yet implemented. + + The explanation of why the preserved register is not used is as follows, + I believe. The registers are being allocated in order. Tying is not + done so efficiently, so when it comes time to do the first allocation, + there are no registers left to use without spilling except extended + registers. Then when the next pseudo register needs a hard reg, there + are still no registers to be had for free, but this one must be a GRF + reg instead of an extended reg, so a preserve register is spilled. Thus + the move from extended to GRF is necessitated. I do not believe this can + be 'fixed' through the config/*m88k* files. + + gcc seems to sometimes make worse use of register allocation -- not counting + moves -- whenever extended registers are present. For example in the + whetstone, the simple for loop (slightly modified) + for(i = 1; i <= n1; i++) + { + x1 = (x1 + x2 + x3 - x4) * t; + x2 = (x1 + x2 - x3 + x4) * t; + x3 = (x1 - x2 + x3 + x4) * t; + x4 = (x1 + x2 + x3 + x4) * t; + } + in general loads the high bits of the addresses of x2-x4 and i into registers + outside the loop. Whenever extended registers are used, it loads all of + these inside the loop. My conjecture is that since the 88110 has so many + registers, and gcc makes no distinction at this point -- just that they are + not fixed, that in loop.c it believes it can expect a number of registers + to be available. Then it allocates 'too many' in local-alloc which causes + problems later. 'Too many' are allocated because a large portion of the + registers are extended registers and cannot be used for certain purposes + ( e.g. hold the address of a variable). When this loop is compiled on its + own, the problem does not occur. I don't know the solution yet, though it + is probably in the base sources. Possibly a different way to calculate + "threshold". */ + +/* 1 for registers that have pervasive standard uses and are not available + for the register allocator. Registers r14-r25 and x22-x29 are expected + to be preserved across function calls. - On the 88000, these are: + On the 88000, the standard uses of the General Register File (GRF) are: Reg 0 = Pseudo argument pointer (hardware fixed to 0). Reg 1 = Subroutine return pointer (hardware). Reg 2-9 = Parameter registers (OCS). @@ -461,11 +591,29 @@ extern char * reg_names[]; Reg 14-25 = Preserved register set. Reg 26-29 = Reserved by OCS and ABI. Reg 30 = Frame pointer (Common use). - Reg 31 = Stack pointer. */ + Reg 31 = Stack pointer. + + The following follows the current 88open UCS specification for the + Extended Register File (XRF): + Reg 32 = x0 Always equal to zero + Reg 33-53 = x1-x21 Temporary registers (Caller Save) + Reg 54-61 = x22-x29 Preserver registers (Callee Save) + Reg 62-63 = x30-x31 Reserved for future ABI use. + + Note: The current 88110 extended register mapping is subject to change. + The bias towards caller-save registers is based on the + presumption that memory traffic can potentially be reduced by + allowing the "caller" to save only that part of the register + which is actually being used. (i.e. don't do a st.x if a st.d + is sufficient). Also, in scientific code (a.k.a. Fortran), the + large number of variables defined in common blocks may require + that almost all registers be saved across calls anyway. */ #define FIXED_REGISTERS \ - {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1} + {1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, \ + 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \ + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1} /* 1 for registers not available across function calls. These must include the FIXED_REGISTERS and also any @@ -476,13 +624,25 @@ extern char * reg_names[]; #define CALL_USED_REGISTERS \ {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, \ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1} + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, \ + 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1} /* Macro to conditionally modify fixed_regs/call_used_regs. */ #define CONDITIONAL_REGISTER_USAGE \ { \ + if (! TARGET_88110) \ + { \ + register int i; \ + for (i = FIRST_EXTENDED_REGISTER; i < FIRST_PSEUDO_REGISTER; i++) \ + { \ + fixed_regs[i] = 1; \ + call_used_regs[i] = 1; \ + } \ + } \ if (flag_pic) \ { \ + /* Current hack to deal with -fpic -O2 problems. */ \ fixed_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ call_used_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ global_regs[PIC_OFFSET_TABLE_REGNUM] = 1; \ @@ -499,21 +659,27 @@ extern char * reg_names[]; This is ordinarily the length in words of a value of mode MODE but can be less for certain modes in special long registers. - On the m88000, ordinary registers hold 32 bits worth; - a single floating point register is always enough for - anything that can be stored in them at all. */ -#define HARD_REGNO_NREGS(REGNO, MODE) \ - ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) + On the m88000, GRF registers hold 32-bits and XRF registers hold 80-bits. + An XRF register can hold any mode, but two GRF registers are required + for larger modes. */ +#define HARD_REGNO_NREGS(REGNO, MODE) \ + ((REGNO < FIRST_PSEUDO_REGISTER && REGNO >= FIRST_EXTENDED_REGISTER) \ + ? 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. For double integers, we never put the value into an odd register so that the operators don't run into the situation where the high part of one of - the inputs is the low part of the result register (it's ok if the output - registers are the same as the input registers. */ -#define HARD_REGNO_MODE_OK(REGNO, MODE) \ - (((MODE) != DImode && (MODE) != DFmode && (MODE) != DCmode) || \ - ((REGNO) & 1) == 0) + the inputs is the low part of the result register. (It's ok if the output + registers are the same as the input registers.) The XRF registers can + hold all modes, but only DF and SF modes can be manipulated in these + registers. The compiler should be allowed to use these as a fast spill + area. */ +#define HARD_REGNO_MODE_OK(REGNO, MODE) \ + ((REGNO < FIRST_PSEUDO_REGISTER && REGNO >= FIRST_EXTENDED_REGISTER) \ + ? TARGET_88110 \ + : (((MODE) != DImode && (MODE) != DFmode && (MODE) != DCmode) \ + || ((REGNO) & 1) == 0)) /* Value is 1 if it is a good idea to tie two pseudo registers when one has mode MODE1 and one has mode MODE2. @@ -555,13 +721,41 @@ extern char * reg_names[]; /* Order in which registers are preferred (most to least). Use temp registers, then param registers top down. Preserve registers are top down to maximize use of double memory ops for register save. - The 88open reserved registers (26-29) may commonly be used in most - environments with the -fcall-used- or -fcall-saved- options. */ -#define REG_ALLOC_ORDER \ - {13, 12, 11, 10, 29, 28, 27, 26, \ - 1, 9, 8, 7, 6, 5, 4, 3, \ - 2, 25, 24, 23, 22, 21, 20, 19, \ - 18, 17, 16, 15, 14, 30, 31, 0} + The 88open reserved registers (r26-r29 and x30-x31) may commonly be used + in most environments with the -fcall-used- or -fcall-saved- options. */ +#define REG_ALLOC_ORDER \ + { \ + 13, 12, 11, 10, 29, 28, 27, 26, \ + 62, 63, 9, 8, 7, 6, 5, 4, \ + 3, 2, 1, 53, 52, 51, 50, 49, \ + 48, 47, 46, 45, 44, 43, 42, 41, \ + 40, 39, 38, 37, 36, 35, 34, 33, \ + 25, 24, 23, 22, 21, 20, 19, 18, \ + 17, 16, 15, 14, 61, 60, 59, 58, \ + 57, 56, 55, 54, 30, 31, 0, 32} + +/* Order for leaf functions. */ +#define REG_LEAF_ALLOC_ORDER \ + { \ + 9, 8, 7, 6, 13, 12, 11, 10, \ + 29, 28, 27, 26, 62, 63, 5, 4, \ + 3, 2, 0, 53, 52, 51, 50, 49, \ + 48, 47, 46, 45, 44, 43, 42, 41, \ + 40, 39, 38, 37, 36, 35, 34, 33, \ + 25, 24, 23, 22, 21, 20, 19, 18, \ + 17, 16, 15, 14, 61, 60, 59, 58, \ + 57, 56, 55, 54, 30, 31, 1, 32} + +/* Switch between the leaf and non-leaf orderings. The purpose is to avoid + write-over scoreboard delays between caller and callee. */ +#define ORDER_REGS_FOR_LOCAL_ALLOC \ +{ \ + static int leaf[] = REG_LEAF_ALLOC_ORDER; \ + static int nonleaf[] = REG_ALLOC_ORDER; \ + \ + bcopy (regs_ever_live[1] ? nonleaf : leaf, reg_alloc_order, \ + FIRST_PSEUDO_REGISTER * sizeof (int)); \ +} /*** Register Classes ***/ @@ -585,34 +779,45 @@ extern char * reg_names[]; For any two classes, it is very desirable that there be another class that represents their union. */ -/* The m88100 hardware has one kind of register. However, we denote +/* The m88000 hardware has two kinds of registers. In addition, we denote the arg pointer as a separate class. */ -enum reg_class { NO_REGS, AP_REG, GENERAL_REGS, ALL_REGS, LIM_REG_CLASSES }; +enum reg_class { NO_REGS, AP_REG, XRF_REGS, GENERAL_REGS, AGRF_REGS, + XGRF_REGS, ALL_REGS, LIM_REG_CLASSES }; #define N_REG_CLASSES (int) LIM_REG_CLASSES /* Give names of register classes as strings for dump file. */ -#define REG_CLASS_NAMES {"NO_REGS", "AP_REG", "GENERAL_REGS", "ALL_REGS" } +#define REG_CLASS_NAMES {"NO_REGS", "AP_REG", "XRF_REGS", "GENERAL_REGS", \ + "AGRF_REGS", "XGRF_REGS", "ALL_REGS" } /* Define which registers fit in which classes. This is an initializer for a vector of HARD_REG_SET of length N_REG_CLASSES. */ -#define REG_CLASS_CONTENTS {0, 1, -2, -1} +#define REG_CLASS_CONTENTS {{0x00000000, 0x00000000}, \ + {0x00000001, 0x00000000}, \ + {0x00000000, 0xffffffff}, \ + {0xfffffffe, 0x00000000}, \ + {0xffffffff, 0x00000000}, \ + {0xfffffffe, 0xffffffff}, \ + {0xffffffff, 0xffffffff}} /* 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) ? GENERAL_REGS : AP_REG) +#define REGNO_REG_CLASS(REGNO) \ + ((REGNO) ? ((REGNO < 32) ? GENERAL_REGS : XRF_REGS) : AP_REG) /* The class value for index registers, and the one for base regs. */ -#define BASE_REG_CLASS ALL_REGS +#define BASE_REG_CLASS AGRF_REGS #define INDEX_REG_CLASS GENERAL_REGS -/* Get reg_class from a letter such as appears in the machine description. */ - -#define REG_CLASS_FROM_LETTER(C) NO_REGS +/* Get reg_class from a letter such as appears in the machine description. + For the 88000, the following class/letter is defined for the XRF: + x - Extended register file */ +#define REG_CLASS_FROM_LETTER(C) \ + (((C) == 'x') ? XRF_REGS : NO_REGS) /* Macros to check register numbers against specific register classes. These assume that REGNO is a hard or pseudo reg number. @@ -620,31 +825,43 @@ enum reg_class { NO_REGS, AP_REG, GENERA or a pseudo reg currently allocated to a suitable hard reg. Since they use reg_renumber, they are safe only once reg_renumber has been allocated, which happens in local-alloc.c. */ -#define REGNO_OK_FOR_BASE_P(REGNO) \ - ((REGNO) < FIRST_PSEUDO_REGISTER || \ - (unsigned) reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER) -#define REGNO_OK_FOR_INDEX_P(REGNO) \ - (((REGNO) && (REGNO) < FIRST_PSEUDO_REGISTER) || \ - (unsigned) reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER) +#define REGNO_OK_FOR_BASE_P(REGNO) \ + ((REGNO) < FIRST_EXTENDED_REGISTER \ + || (unsigned) reg_renumber[REGNO] < FIRST_EXTENDED_REGISTER) +#define REGNO_OK_FOR_INDEX_P(REGNO) \ + (((REGNO) && (REGNO) < FIRST_EXTENDED_REGISTER) \ + || (unsigned) reg_renumber[REGNO] < FIRST_EXTENDED_REGISTER) /* Given an rtx X being reloaded into a reg required to be in class CLASS, return the class of reg to actually use. In general this is just CLASS; but on some machines in some cases it is preferable to use a more restrictive class. Double constants should be in a register iff they can be made cheaply. */ -#define PREFERRED_RELOAD_CLASS(X,CLASS) (CLASS) +#define PREFERRED_RELOAD_CLASS(X,CLASS) \ + (CONSTANT_P(X) && (CLASS == XRF_REGS) ? NO_REGS : (CLASS)) + +/* Return the register class of a scratch register needed to load IN + into a register of class CLASS in MODE. On the m88k, when PIC, we + need a temporary when loading some addresses into a register. */ +#define SECONDARY_INPUT_RELOAD_CLASS(CLASS, MODE, IN) \ + ((flag_pic \ + && GET_CODE (IN) == CONST \ + && GET_CODE (XEXP (IN, 0)) == PLUS \ + && GET_CODE (XEXP (XEXP (IN, 0), 0)) == CONST_INT \ + && ! SMALL_INT (XEXP (XEXP (IN, 0), 1))) ? GENERAL_REGS : NO_REGS) /* Return the maximum number of consecutive registers needed to represent mode MODE in a register of class CLASS. */ -#define CLASS_MAX_NREGS(CLASS, MODE) \ - ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD) +#define CLASS_MAX_NREGS(CLASS, MODE) \ + ((((CLASS) == XRF_REGS) ? 1 \ + : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))) /* Letters in the range `I' through `P' in a register constraint string can be used to stand for particular ranges of immediate operands. The C expression is true iff C is a known letter and VALUE is appropriate for that letter. - For the m88000, the following contraints are used: + For the m88000, the following constants are used: `I' requires a non-negative 16-bit value. `J' requires a non-positive 16-bit value. `K' is unused. @@ -872,7 +1089,10 @@ enum reg_class { NO_REGS, AP_REG, GENERA #define EXPAND_BUILTIN_SAVEREGS(ARGLIST) m88k_builtin_saveregs (ARGLIST) /* Generate the assembly code for function entry. */ -#define FUNCTION_PROLOGUE(FILE, SIZE) m88k_output_prologue(FILE, SIZE) +#define FUNCTION_PROLOGUE(FILE, SIZE) m88k_begin_prologue(FILE, SIZE) + +/* Perform special actions at the point where the prologue ends. */ +#define FUNCTION_END_PROLOGUE(FILE) m88k_end_prologue(FILE) /* Output assembler code to FILE to increment profiler label # LABELNO for profiling a function entry. Redefined in m88kv3.h, m88kv4.h and @@ -880,15 +1100,25 @@ enum reg_class { NO_REGS, AP_REG, GENERA #define FUNCTION_PROFILER(FILE, LABELNO) \ output_function_profiler (FILE, LABELNO, "mcount", 1) +/* Maximum length in instructions of the code output by FUNCTION_PROFILER. */ +#define FUNCTION_PROFILER_LENGTH (5+3+1+5) + /* Output assembler code to FILE to initialize basic-block profiling for the current module. LABELNO is unique to each instance. */ #define FUNCTION_BLOCK_PROFILER(FILE, LABELNO) \ output_function_block_profiler (FILE, LABELNO) +/* Maximum length in instructions of the code output by + FUNCTION_BLOCK_PROFILER. */ +#define FUNCTION_BLOCK_PROFILER_LENGTH (3+5+2+5) + /* Output assembler code to FILE to increment the count associated with the basic block number BLOCKNO. */ #define BLOCK_PROFILER(FILE, BLOCKNO) output_block_profiler (FILE, BLOCKNO) +/* Maximum length in instructions of the code output by BLOCK_PROFILER. */ +#define BLOCK_PROFILER_LENGTH 4 + /* EXIT_IGNORE_STACK should be nonzero if, when returning from a function, the stack pointer does not matter. The value is tested only in functions that have frame pointers. @@ -896,16 +1126,10 @@ enum reg_class { NO_REGS, AP_REG, GENERA #define EXIT_IGNORE_STACK (1) /* Generate the assembly code for function exit. */ -#define FUNCTION_EPILOGUE(FILE, SIZE) m88k_output_epilogue(FILE, SIZE) +#define FUNCTION_EPILOGUE(FILE, SIZE) m88k_end_epilogue(FILE, SIZE) -/* Define the number of delay slots needed for the function epilogue. - These are used for scheduling the function epilogue and depend on - what the epilogue looks like. */ -#define DELAY_SLOTS_FOR_EPILOGUE delay_slots_for_epilogue () - -/* Define whether INSN can be placed in delay slot N for the epilogue. */ -#define ELIGIBLE_FOR_EPILOGUE_DELAY(INSN,N) \ - eligible_for_epilogue_delay (INSN) +/* Perform special actions at the point where the epilogue begins. */ +#define FUNCTION_BEGIN_EPILOGUE(FILE) m88k_begin_epilogue(FILE) /* Value should be nonzero if functions must have frame pointers. Zero means the frame pointer need not be set up (and parms @@ -987,7 +1211,7 @@ enum reg_class { NO_REGS, AP_REG, GENERA This is really two components. The first 32 bytes are fixed and must be copied; the last 12 bytes are just storage that's filled in later. So for allocation purposes, it's 32+12 bytes, but for - initializaiton purposes, it's 32 bytes. */ + initialization purposes, it's 32 bytes. */ #define TRAMPOLINE_SIZE (32+12) @@ -1168,7 +1392,7 @@ enum reg_class { NO_REGS, AP_REG, GENERA force_operand (XEXP (X, 1), 0)); \ if (GET_CODE (X) == SYMBOL_REF || GET_CODE (X) == CONST \ || GET_CODE (X) == LABEL_REF) \ - (X) = legitimize_address (flag_pic, X, gen_reg_rtx (Pmode)); \ + (X) = legitimize_address (flag_pic, X, 0, 0); \ if (memory_address_p (MODE, X)) \ goto WIN; } @@ -1220,6 +1444,11 @@ enum reg_class { NO_REGS, AP_REG, GENERA {"equality_op", {EQ, NE}}, \ {"pc_or_label_ref", {PC, LABEL_REF}}, +/* The case table contains either words or branch instructions. This says + which. We always claim that the vector is PC-relative. It is position + independent when -fpic is used. */ +#define CASE_VECTOR_INSNS (TARGET_88100 || flag_pic) + /* An alias for a machine mode name. This is the machine mode that elements of a jump-table should have. */ #define CASE_VECTOR_MODE SImode @@ -1232,6 +1461,15 @@ enum reg_class { NO_REGS, AP_REG, GENERA actually ignored by the `case' insn proper. */ /* #define CASE_DROPS_THROUGH */ +/* Define this to be the smallest number of different values for which it + is best to use a jump-table instead of a tree of conditional branches. + The default is 4 for machines with a casesi instruction and 5 otherwise. + The best 88110 number is around 7, though the exact number isn't yet + known. A third alternative for the 88110 is to use a binary tree of + bb1 instructions on bits 2/1/0 if the range is dense. This may not + win very much though. */ +#define CASE_VALUES_THRESHOLD (TARGET_88100 ? 4 : 7) + /* Specify the tree operation to be used to convert reals to integers. */ #define IMPLICIT_FIX_EXPR FIX_ROUND_EXPR @@ -1247,41 +1485,15 @@ enum reg_class { NO_REGS, AP_REG, GENERA /* Allow and ignore #sccs directives */ #define SCCS_DIRECTIVE -/* Code to handle #pragma directives. The interface is a bit messy, - but there's no simpler way to do this while still using yylex. */ -#define HANDLE_PRAGMA(FILE) \ - do { \ - while (c == ' ' || c == '\t') \ - c = getc (FILE); \ - if (c == '\n' || c == EOF) \ - { \ - m88k_handle_pragma_token (0, 0); \ - return c; \ - } \ - ungetc (c, FILE); \ - switch (yylex ()) \ - { \ - case IDENTIFIER: \ - case TYPENAME: \ - case STRING: \ - case CONSTANT: \ - m88k_handle_pragma_token (token_buffer, yylval.ttype); \ - break; \ - default: \ - m88k_handle_pragma_token (token_buffer, 0); \ - } \ - if (nextchar >= 0) \ - c = nextchar, nextchar = -1; \ - else \ - c = getc (FILE); \ - } while (1) +/* Handle #pragma pack and sometimes #pragma weak. */ +#define HANDLE_SYSV_PRAGMA /* Tell when to handle #pragma weak. This is only done for V.4. */ #define HANDLE_PRAGMA_WEAK TARGET_SVR4 /* Max number of bytes we can move from memory to memory in one reasonably fast instruction. */ -#define MOVE_MAX 64 +#define MOVE_MAX 8 /* Define if normal loads of shorter-than-word items from memory clears the rest of the bigs in the register. */ @@ -1324,6 +1536,39 @@ enum reg_class { NO_REGS, AP_REG, GENERA so give the MEM rtx word mode. */ #define FUNCTION_MODE SImode +/* A barrier will be aligned so account for the possible expansion. + A volatile load may be preceeded by a serializing instruction. + Account for profiling code output at NOTE_INSN_PROLOGUE_END. + Account for block profiling code at basic block boundaries. */ +#define ADJUST_INSN_LENGTH(RTX, LENGTH) \ + if (GET_CODE (RTX) == BARRIER \ + || (TARGET_SERIALIZE_VOLATILE \ + && GET_CODE (RTX) == INSN \ + && GET_CODE (PATTERN (RTX)) == SET \ + && ((GET_CODE (SET_SRC (PATTERN (RTX))) == MEM \ + && MEM_VOLATILE_P (SET_SRC (PATTERN (RTX))))))) \ + LENGTH += 1; \ + else if (GET_CODE (RTX) == NOTE \ + && NOTE_LINE_NUMBER (RTX) == NOTE_INSN_PROLOGUE_END) \ + { \ + if (profile_block_flag) \ + LENGTH += FUNCTION_BLOCK_PROFILER_LENGTH; \ + if (profile_flag) \ + LENGTH += (FUNCTION_PROFILER_LENGTH + REG_PUSH_LENGTH \ + + REG_POP_LENGTH); \ + } \ + else if (profile_block_flag \ + && (GET_CODE (RTX) == CODE_LABEL \ + || GET_CODE (RTX) == JUMP_INSN \ + || (GET_CODE (RTX) == INSN \ + && GET_CODE (PATTERN (RTX)) == SEQUENCE \ + && GET_CODE (XVECEXP (PATTERN (RTX), 0, 0)) == JUMP_INSN)))\ + LENGTH += BLOCK_PROFILER_LENGTH; + +/* Track the state of the last volatile memory reference. Clear the + state with CC_STATUS_INIT for now. */ +#define CC_STATUS_INIT m88k_volatile_code = '\0' + /* Compute the cost of computing a constant rtl expression RTX whose rtx-code is CODE. The body of this macro is a portion of a switch statement. If the code is computed here, @@ -1337,7 +1582,7 @@ enum reg_class { NO_REGS, AP_REG, GENERA is as good as a register; since it can't be placed in any insn, it won't do anything in cse, but it will cause expand_binop to pass the constant to the define_expands). */ -#define CONST_COSTS(RTX,CODE) \ +#define CONST_COSTS(RTX,CODE,OUTER_CODE) \ case CONST_INT: \ if (SMALL_INT (RTX)) \ return 0; \ @@ -1358,7 +1603,7 @@ enum reg_class { NO_REGS, AP_REG, GENERA return 0; /* Provide the costs of an addressing mode that contains ADDR. - If ADDR is not a valid address, it's cost is irrelavent. + If ADDR is not a valid address, its cost is irrelevant. REG+REG is made slightly more expensive because it might keep a register live for longer than we might like. */ #define ADDRESS_COST(ADDR) \ @@ -1371,7 +1616,7 @@ enum reg_class { NO_REGS, AP_REG, GENERA /* Provide the costs of a rtl expression. This is in the body of a switch on CODE. */ -#define RTX_COSTS(X,CODE) \ +#define RTX_COSTS(X,CODE,OUTER_CODE) \ case MEM: \ return COSTS_N_INSNS (2); \ case MULT: \ @@ -1389,6 +1634,23 @@ enum reg_class { NO_REGS, AP_REG, GENERA /* Provide the cost of a branch. Exact meaning under development. */ #define BRANCH_COST (TARGET_88100 ? 1 : 2) +/* A C statement (sans semicolon) to update the integer variable COST + based on the relationship between INSN that is dependent on + DEP_INSN through the dependence LINK. The default is to make no + adjustment to COST. On the m88k, ignore the cost of anti- and + output-dependencies. On the m88100, a store can issue two cycles + before the value (not the address) has finished computing. */ +#define ADJUST_COST(INSN,LINK,DEP_INSN,COST) \ + do { \ + if (REG_NOTE_KIND (LINK) != 0) \ + (COST) = 0; /* Anti or output dependence. */ \ + else if (! TARGET_88100 \ + && recog_memoized (INSN) >= 0 \ + && get_attr_type (INSN) == TYPE_STORE \ + && SET_SRC (PATTERN (INSN)) == SET_DEST (PATTERN (DEP_INSN))) \ + (COST) -= 4; /* 88110 store reservation station. */ \ + } while (0) + /* Define this to be nonzero if the character `$' should be allowed by default in identifier names. */ #define DOLLARS_IN_IDENTIFIERS 1 @@ -1406,7 +1668,6 @@ enum reg_class { NO_REGS, AP_REG, GENERA /* Allow pseudo-ops to be overridden. Override these in svr[34].h. */ #undef INT_ASM_OP #undef ASCII_DATA_ASM_OP -#undef INIT_SECTION_ASM_OP #undef CONST_SECTION_ASM_OP #undef CTORS_SECTION_ASM_OP #undef DTORS_SECTION_ASM_OP @@ -1414,70 +1675,77 @@ enum reg_class { NO_REGS, AP_REG, GENERA #undef FINI_SECTION_ASM_OP #undef TYPE_ASM_OP #undef SIZE_ASM_OP +#undef WEAK_ASM_OP +#undef SET_ASM_OP +#undef SKIP_ASM_OP +#undef COMMON_ASM_OP +#undef ALIGN_ASM_OP +#undef IDENT_ASM_OP /* These are used in varasm.c as well. */ -#define TEXT_SECTION_ASM_OP "\ttext" -#define DATA_SECTION_ASM_OP "\tdata" +#define TEXT_SECTION_ASM_OP "text" +#define DATA_SECTION_ASM_OP "data" /* Other sections. */ #define CONST_SECTION_ASM_OP (VERSION_0300_SYNTAX \ - ? "\tsection\t .rodata,\"a\"\n" \ - : "\tsection\t .rodata,\"x\"\n") + ? "section\t .rodata,\"a\"" \ + : "section\t .rodata,\"x\"") #define TDESC_SECTION_ASM_OP (VERSION_0300_SYNTAX \ - ? "\tsection\t .tdesc,\"a\"" \ - : "\tsection\t .tdesc,\"x\"") + ? "section\t .tdesc,\"a\"" \ + : "section\t .tdesc,\"x\"") /* These must be constant strings for crtstuff.c. */ -#define CTORS_SECTION_ASM_OP "\tsection\t .ctors,\"d\"\n" -#define DTORS_SECTION_ASM_OP "\tsection\t .dtors,\"d\"\n" -#define INIT_SECTION_ASM_OP "\tsection\t .init,\"x\"" -#define FINI_SECTION_ASM_OP "\tsection\t .fini,\"x\"" +#define CTORS_SECTION_ASM_OP "section\t .ctors,\"d\"" +#define DTORS_SECTION_ASM_OP "section\t .dtors,\"d\"" +#define INIT_SECTION_ASM_OP "section\t .init,\"x\"" +#define FINI_SECTION_ASM_OP "section\t .fini,\"x\"" /* These are pretty much common to all assemblers. */ -#define IDENT_ASM_OP "\tident" -#define FILE_ASM_OP "\tfile" -#define SECTION_ASM_OP "\tsection" -#define DEF_ASM_OP "\tdef" -#define GLOBAL_ASM_OP "\tglobal" -#define ALIGN_ASM_OP "\talign" -#define SKIP_ASM_OP "\tzero" -#define COMMON_ASM_OP "\tcomm" -#define LOCAL_ASM_OP "\tbss" -#define FLOAT_ASM_OP "\tfloat" -#define DOUBLE_ASM_OP "\tdouble" -#define INT_ASM_OP "\tword" +#define IDENT_ASM_OP "ident" +#define FILE_ASM_OP "file" +#define SECTION_ASM_OP "section" +#define SET_ASM_OP "def" +#define GLOBAL_ASM_OP "global" +#define ALIGN_ASM_OP "align" +#define SKIP_ASM_OP "zero" +#define COMMON_ASM_OP "comm" +#define BSS_ASM_OP "bss" +#define FLOAT_ASM_OP "float" +#define DOUBLE_ASM_OP "double" +#define INT_ASM_OP "word" #define ASM_LONG INT_ASM_OP -#define SHORT_ASM_OP "\thalf" -#define CHAR_ASM_OP "\tbyte" -#define ASCII_DATA_ASM_OP "\tstring" +#define SHORT_ASM_OP "half" +#define CHAR_ASM_OP "byte" +#define ASCII_DATA_ASM_OP "string" /* These are particular to the global pool optimization. */ -#define SBSS_ASM_OP "\tsbss" -#define SCOMM_ASM_OP "\tscomm" -#define SDATA_SECTION_ASM_OP "\tsdata" +#define SBSS_ASM_OP "sbss" +#define SCOMM_ASM_OP "scomm" +#define SDATA_SECTION_ASM_OP "sdata" /* These are specific to PIC. */ -#define TYPE_ASM_OP "\ttype" -#define SIZE_ASM_OP "\tsize" -#define WEAK_ASM_OP "\tweak" +#define TYPE_ASM_OP "type" +#define SIZE_ASM_OP "size" +#define WEAK_ASM_OP "weak" #ifndef AS_BUG_POUND_TYPE /* Faulty assemblers require @ rather than #. */ #undef TYPE_OPERAND_FMT #define TYPE_OPERAND_FMT "#%s" #endif /* These are specific to version 03.00 assembler syntax. */ -#define INTERNAL_ASM_OP "\tlocal" -#define VERSION_ASM_OP "\tversion" -#define ASM_DWARF_POP_SECTION(FILE) fputs ("\tprevious\n", FILE) -#define UNALIGNED_SHORT_ASM_OP "\tuahalf" -#define UNALIGNED_INT_ASM_OP "\tuaword" +#define INTERNAL_ASM_OP "local" +#define VERSION_ASM_OP "version" +#define UNALIGNED_SHORT_ASM_OP "uahalf" +#define UNALIGNED_INT_ASM_OP "uaword" +#define PUSHSECTION_ASM_OP "section" +#define POPSECTION_ASM_OP "previous" /* Output any initial stuff to the assembly file. Always put out a file directive, even if not debugging. Immediately after putting out the file, put out a "sem." declaration. This should be harmless on other systems, and - is used in DG/UX by the debuggers to suppliment COFF. The + is used in DG/UX by the debuggers to supplement COFF. The fields in the integer value are as follows: Bits Value Meaning @@ -1513,8 +1781,8 @@ enum reg_class { NO_REGS, AP_REG, GENERA #define ASM_FIRST_LINE(FILE) \ do { \ - if (VERSION_0300_SYNTAX) \ - fprintf (FILE, "%s\t \"03.00\"\n", VERSION_ASM_OP); \ + if (m88k_version) \ + fprintf (FILE, "\t%s\t \"%s\"\n", VERSION_ASM_OP, m88k_version); \ } while (0) /* Override svr[34].h. */ @@ -1526,7 +1794,7 @@ enum reg_class { NO_REGS, AP_REG, GENERA #undef ASM_FILE_END #define ASM_OUTPUT_SOURCE_FILENAME(FILE, NAME) \ - fprintf (FILE, "%s\t \"%s\"\n", FILE_ASM_OP, NAME) + fprintf (FILE, "\t%s\t \"%s\"\n", FILE_ASM_OP, NAME) #ifdef SDB_DEBUGGING_INFO #define ASM_OUTPUT_SOURCE_LINE(FILE, LINE) \ @@ -1541,7 +1809,7 @@ enum reg_class { NO_REGS, AP_REG, GENERA #define ASM_OUTPUT_IDENT(FILE, NAME) #else #define ASM_OUTPUT_IDENT(FILE, NAME) \ - fprintf(FILE, "%s\t \"%s\"\n", IDENT_ASM_OP, NAME) + output_ascii (FILE, IDENT_ASM_OP, 4000, NAME, strlen (NAME)); #endif /* Output to assembler file text saying following lines @@ -1578,7 +1846,19 @@ enum reg_class { NO_REGS, AP_REG, GENERA {"#r0"+1, "#r1"+1, "#r2"+1, "#r3"+1, "#r4"+1, "#r5"+1, "#r6"+1, "#r7"+1, \ "#r8"+1, "#r9"+1, "#r10"+1,"#r11"+1,"#r12"+1,"#r13"+1,"#r14"+1,"#r15"+1,\ "#r16"+1,"#r17"+1,"#r18"+1,"#r19"+1,"#r20"+1,"#r21"+1,"#r22"+1,"#r23"+1,\ - "#r24"+1,"#r25"+1,"#r26"+1,"#r27"+1,"#r28"+1,"#r29"+1,"#r30"+1,"#r31"+1} + "#r24"+1,"#r25"+1,"#r26"+1,"#r27"+1,"#r28"+1,"#r29"+1,"#r30"+1,"#r31"+1,\ + "#x0"+1, "#x1"+1, "#x2"+1, "#x3"+1, "#x4"+1, "#x5"+1, "#x6"+1, "#x7"+1, \ + "#x8"+1, "#x9"+1, "#x10"+1,"#x11"+1,"#x12"+1,"#x13"+1,"#x14"+1,"#x15"+1,\ + "#x16"+1,"#x17"+1,"#x18"+1,"#x19"+1,"#x20"+1,"#x21"+1,"#x22"+1,"#x23"+1,\ + "#x24"+1,"#x25"+1,"#x26"+1,"#x27"+1,"#x28"+1,"#x29"+1,"#x30"+1,"#x31"+1} + +/* Define additional names for use in asm clobbers and asm declarations. + + We define the fake Condition Code register as an alias for reg 0 (which + is our `condition code' register), so that condition codes can easily + be clobbered by an asm. The carry bit in the PSR is now used. */ + +#define ADDITIONAL_REGISTER_NAMES {"psr", 0, "cc", 0} /* How to renumber registers for dbx and gdb. */ #define DBX_REGISTER_NUMBER(REGNO) (REGNO) @@ -1593,7 +1873,7 @@ enum reg_class { NO_REGS, AP_REG, GENERA do { \ if (DECLARE_ASM_NAME) \ { \ - fprintf (FILE, "%s\t ", TYPE_ASM_OP); \ + fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ assemble_name (FILE, NAME); \ putc (',', FILE); \ fprintf (FILE, TYPE_OPERAND_FMT, "function"); \ @@ -1608,14 +1888,14 @@ enum reg_class { NO_REGS, AP_REG, GENERA do { \ if (DECLARE_ASM_NAME) \ { \ - fprintf (FILE, "%s\t ", TYPE_ASM_OP); \ + fprintf (FILE, "\t%s\t ", TYPE_ASM_OP); \ assemble_name (FILE, NAME); \ putc (',', FILE); \ fprintf (FILE, TYPE_OPERAND_FMT, "object"); \ putc ('\n', FILE); \ if (!flag_inhibit_size_directive) \ { \ - fprintf (FILE, "%s\t ", SIZE_ASM_OP); \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ assemble_name (FILE, NAME); \ fprintf (FILE, ",%d\n", int_size_in_bytes (TREE_TYPE (decl))); \ } \ @@ -1636,7 +1916,7 @@ enum reg_class { NO_REGS, AP_REG, GENERA labelno++; \ ASM_GENERATE_INTERNAL_LABEL (label, "Lfe", labelno); \ ASM_OUTPUT_INTERNAL_LABEL (FILE, "Lfe", labelno); \ - fprintf (FILE, "%s\t ", SIZE_ASM_OP); \ + fprintf (FILE, "\t%s\t ", SIZE_ASM_OP); \ assemble_name (FILE, (FNAME)); \ fprintf (FILE, ",%s-", &label[1]); \ assemble_name (FILE, (FNAME)); \ @@ -1654,7 +1934,7 @@ enum reg_class { NO_REGS, AP_REG, GENERA defined for reference from other files. */ #define ASM_GLOBALIZE_LABEL(FILE,NAME) \ do { \ - fprintf (FILE, "%s\t ", GLOBAL_ASM_OP); \ + fprintf (FILE, "\t%s\t ", GLOBAL_ASM_OP); \ assemble_name (FILE, NAME); \ putc ('\n', FILE); \ } while (0) @@ -1673,9 +1953,10 @@ enum reg_class { NO_REGS, AP_REG, GENERA PREFIX is the class of label and NUM is the number within the class. For V.4, labels use `.' rather than `@'. */ +#undef ASM_OUTPUT_INTERNAL_LABEL #ifdef AS_BUG_DOT_LABELS /* The assembler requires a declaration of local. */ #define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ - fprintf (FILE, VERSION_0300_SYNTAX ? ".%s%d:\n%s\t .%s%d\n" : "@%s%d:\n", \ + fprintf (FILE, VERSION_0300_SYNTAX ? ".%s%d:\n\t%s\t .%s%d\n" : "@%s%d:\n", \ PREFIX, NUM, INTERNAL_ASM_OP, PREFIX, NUM) #else #define ASM_OUTPUT_INTERNAL_LABEL(FILE,PREFIX,NUM) \ @@ -1689,6 +1970,7 @@ enum reg_class { NO_REGS, AP_REG, GENERA with ASM_OUTPUT_INTERNAL_LABEL above, except for being prefixed with an `*'. */ +#undef ASM_GENERATE_INTERNAL_LABEL #define ASM_GENERATE_INTERNAL_LABEL(LABEL,PREFIX,NUM) \ sprintf (LABEL, VERSION_0300_SYNTAX ? "*.%s%d" : "*@%s%d", PREFIX, NUM) @@ -1734,7 +2016,7 @@ enum reg_class { NO_REGS, AP_REG, GENERA do { \ union { REAL_VALUE_TYPE d; long l[2]; } x; \ x.d = (VALUE); \ - fprintf (FILE, "%s\t 0x%.8x, 0x%.8x\n", INT_ASM_OP, \ + fprintf (FILE, "\t%s\t 0x%.8x, 0x%.8x\n", INT_ASM_OP, \ x.l[0], x.l[1]); \ } while (0) @@ -1743,48 +2025,64 @@ enum reg_class { NO_REGS, AP_REG, GENERA do { \ int i; \ FLOAT_TO_INT_INTERNAL (VALUE, i); \ - fprintf (FILE, "%s\t 0x%.8x\n", INT_ASM_OP, i); \ + fprintf (FILE, "\t%s\t 0x%.8x\n", INT_ASM_OP, i); \ } while (0) /* Likewise for `int', `short', and `char' constants. */ #define ASM_OUTPUT_INT(FILE,VALUE) \ -( fprintf (FILE, "%s\t ", INT_ASM_OP), \ +( fprintf (FILE, "\t%s\t ", INT_ASM_OP), \ output_addr_const (FILE, (VALUE)), \ fprintf (FILE, "\n")) #define ASM_OUTPUT_SHORT(FILE,VALUE) \ -( fprintf (FILE, "%s\t ", SHORT_ASM_OP), \ +( fprintf (FILE, "\t%s\t ", SHORT_ASM_OP), \ output_addr_const (FILE, (VALUE)), \ fprintf (FILE, "\n")) #define ASM_OUTPUT_CHAR(FILE,VALUE) \ -( fprintf (FILE, "%s\t ", CHAR_ASM_OP), \ +( fprintf (FILE, "\t%s\t ", CHAR_ASM_OP), \ output_addr_const (FILE, (VALUE)), \ fprintf (FILE, "\n")) /* This is how to output an assembler line for a numeric constant byte. */ #define ASM_OUTPUT_BYTE(FILE,VALUE) \ - fprintf (FILE, "%s\t 0x%x\n", CHAR_ASM_OP, (VALUE)) + fprintf (FILE, "\t%s\t 0x%x\n", CHAR_ASM_OP, (VALUE)) -/* The singl-byte pseudo-op is the default. Override svr[34].h. */ +/* The single-byte pseudo-op is the default. Override svr[34].h. */ #undef ASM_BYTE_OP -#define ASM_BYTE_OP "\tbyte" +#define ASM_BYTE_OP "byte" #undef ASM_OUTPUT_ASCII #define ASM_OUTPUT_ASCII(FILE, P, SIZE) \ - output_ascii ((FILE), (P), (SIZE)) + output_ascii (FILE, ASCII_DATA_ASM_OP, 48, P, SIZE) + +/* Override svr4.h. Change to the readonly data section for a table of + addresses. final_scan_insn changes back to the text section. */ +#undef ASM_OUTPUT_CASE_LABEL +#define ASM_OUTPUT_CASE_LABEL(FILE, PREFIX, NUM, TABLE) \ + do { \ + if (! CASE_VECTOR_INSNS) \ + { \ + readonly_data_section (); \ + ASM_OUTPUT_ALIGN (FILE, 2); \ + } \ + ASM_OUTPUT_INTERNAL_LABEL (FILE, PREFIX, NUM); \ + } while (0) /* Epilogue for case labels. This jump instruction is called by casesi to transfer to the appropriate branch instruction within the table. The label `@Le' is coined to mark the end of the table. */ #define ASM_OUTPUT_CASE_END(FILE, NUM, TABLE) \ do { \ - char label[256]; \ - ASM_GENERATE_INTERNAL_LABEL (label, "L", NUM); \ - fprintf (FILE, "%se:\n", &label[1]); \ - if (! flag_delayed_branch) \ - fprintf (FILE, "\tlda\t %s,%s[%s]\n", reg_names[1], reg_names[1], \ - reg_names[m88k_case_index]); \ - fprintf (FILE, "\tjmp\t %s\n", reg_names[1]); \ + if (CASE_VECTOR_INSNS) \ + { \ + char label[256]; \ + ASM_GENERATE_INTERNAL_LABEL (label, "L", NUM); \ + fprintf (FILE, "%se:\n", &label[1]); \ + if (! flag_delayed_branch) \ + fprintf (FILE, "\tlda\t %s,%s[%s]\n", reg_names[1], \ + reg_names[1], reg_names[m88k_case_index]); \ + fprintf (FILE, "\tjmp\t %s\n", reg_names[1]); \ + } \ } while (0) /* This is how to output an element of a case-vector that is absolute. */ @@ -1792,7 +2090,8 @@ enum reg_class { NO_REGS, AP_REG, GENERA do { \ char buffer[256]; \ ASM_GENERATE_INTERNAL_LABEL (buffer, "L", VALUE); \ - fprintf (FILE, "\tbr\t %s\n", &buffer[1]); \ + fprintf (FILE, CASE_VECTOR_INSNS ? "\tbr\t %s\n" : "\tword\t %s\n", \ + &buffer[1]); \ } while (0) /* This is how to output an element of a case-vector that is relative. */ @@ -1804,17 +2103,19 @@ enum reg_class { NO_REGS, AP_REG, GENERA to a multiple of 2**LOG bytes. */ #define ASM_OUTPUT_ALIGN(FILE,LOG) \ if ((LOG) != 0) \ - fprintf (FILE, "%s\t %d\n", ALIGN_ASM_OP, 1<<(LOG)) + fprintf (FILE, "\t%s\t %d\n", ALIGN_ASM_OP, 1<<(LOG)) -/* Align the text address to half a cache boundary when it can only be - reached by jumping. Pack code tightly when compiling crtstuff.c. */ +/* On the m88100, align the text address to half a cache boundary when it + can only be reached by jumping. Pack code tightly when compiling + crtstuff.c. */ #define ASM_OUTPUT_ALIGN_CODE(FILE) \ - ASM_OUTPUT_ALIGN (FILE, (flag_inhibit_size_directive ? 2 : 3)) + ASM_OUTPUT_ALIGN (FILE, \ + (TARGET_88100 && !flag_inhibit_size_directive ? 3 : 2)) /* Override svr[34].h. */ #undef ASM_OUTPUT_SKIP #define ASM_OUTPUT_SKIP(FILE,SIZE) \ - fprintf (FILE, "%s\t %u\n", SKIP_ASM_OP, (SIZE)) + fprintf (FILE, "\t%s\t %u\n", SKIP_ASM_OP, (SIZE)) /* Override svr4.h. */ #undef ASM_OUTPUT_EXTERNAL_LIBCALL @@ -1825,18 +2126,18 @@ enum reg_class { NO_REGS, AP_REG, GENERA #undef ASM_OUTPUT_COMMON #undef ASM_OUTPUT_ALIGNED_COMMON #define ASM_OUTPUT_COMMON(FILE, NAME, SIZE, ROUNDED) \ -( fprintf ((FILE), "%s\t ", \ - (ROUNDED) <= m88k_gp_threshold ? SCOMM_ASM_OP : COMMON_ASM_OP), \ +( fprintf ((FILE), "\t%s\t ", \ + ((SIZE) ? (SIZE) : 1) <= m88k_gp_threshold ? SCOMM_ASM_OP : COMMON_ASM_OP), \ assemble_name ((FILE), (NAME)), \ fprintf ((FILE), ",%u\n", (SIZE) ? (SIZE) : 1)) -/* This says how to output an assember line to define a local common +/* This says how to output an assembler line to define a local common symbol. Override svr[34].h. */ #undef ASM_OUTPUT_LOCAL #undef ASM_OUTPUT_ALIGNED_LOCAL #define ASM_OUTPUT_LOCAL(FILE, NAME, SIZE, ROUNDED) \ -( fprintf ((FILE), "%s\t ", \ - (ROUNDED) <= m88k_gp_threshold ? SBSS_ASM_OP : LOCAL_ASM_OP), \ +( fprintf ((FILE), "\t%s\t ", \ + ((SIZE) ? (SIZE) : 1) <= m88k_gp_threshold ? SBSS_ASM_OP : BSS_ASM_OP), \ assemble_name ((FILE), (NAME)), \ fprintf ((FILE), ",%u,%d\n", (SIZE) ? (SIZE) : 1, (SIZE) <= 4 ? 4 : 8)) @@ -1857,6 +2158,9 @@ enum reg_class { NO_REGS, AP_REG, GENERA reg_names[REGNO], \ reg_names[STACK_POINTER_REGNUM]) +/* Length in instructions of the code output by ASM_OUTPUT_REG_PUSH. */ +#define REG_PUSH_LENGTH 2 + /* This is how to output an insn to pop a register from the stack. */ #define ASM_OUTPUT_REG_POP(FILE,REGNO) \ fprintf (FILE, "\tld\t %s,%s,0\n\taddu\t %s,%s,%d\n", \ @@ -1866,6 +2170,9 @@ enum reg_class { NO_REGS, AP_REG, GENERA reg_names[STACK_POINTER_REGNUM], \ (STACK_BOUNDARY / BITS_PER_UNIT)) +/* Length in instructions of the code output by ASM_OUTPUT_REG_POP. */ +#define REG_POP_LENGTH 2 + /* Define the parentheses used to group arithmetic operations in assembler code. */ #define ASM_OPEN_PAREN "(" @@ -2093,20 +2400,21 @@ enum reg_class { NO_REGS, AP_REG, GENERA #define USE_CONST_SECTION DECLARE_ASM_NAME -#if defined(CTORS_SECTION_FUNCTION) /* SVR4 */ +#if defined(USING_SVR4_H) #define EXTRA_SECTIONS in_const, in_tdesc, in_sdata, in_ctors, in_dtors #define INIT_SECTION_FUNCTION #define FINI_SECTION_FUNCTION -#elif defined(FINI_SECTION_FUNCTION) /* SVR3 */ +#else +#if defined(USING_SVR3_H) -#define EXTRA_SECTIONS in_const, in_tdesc, in_sdata, in_init, in_fini -#define CTORS_SECTION_FUNCTION -#define DTORS_SECTION_FUNCTION +#define EXTRA_SECTIONS in_const, in_tdesc, in_sdata, in_ctors, in_dtors, \ + in_init, in_fini #else /* m88kluna or other not based on svr[34].h. */ +#undef INIT_SECTION_ASM_OP #define EXTRA_SECTIONS in_const, in_tdesc, in_sdata #define CONST_SECTION_FUNCTION \ void \ @@ -2119,7 +2427,8 @@ const_section () \ #define INIT_SECTION_FUNCTION #define FINI_SECTION_FUNCTION -#endif /* CTORS_SECTION_FUNCTION */ +#endif /* USING_SVR3_H */ +#endif /* USING_SVR4_H */ #undef EXTRA_SECTION_FUNCTIONS #define EXTRA_SECTION_FUNCTIONS \ @@ -2150,8 +2459,6 @@ sdata_section () \ INIT_SECTION_FUNCTION \ FINI_SECTION_FUNCTION -#undef READONLY_DATA_SECTION - /* A C statement or statements to switch to the appropriate section for output of DECL. DECL is either a `VAR_DECL' node or a constant of some sort. RELOC indicates whether forming @@ -2185,6 +2492,11 @@ sdata_section () \ const_section (); \ } +/* Jump tables consist of branch instructions and should be output in + the text section. When we use a table of addresses, we explicitly + change to the readonly data section. */ +#define JUMP_TABLES_IN_TEXT_SECTION 1 + /* Define this macro if references to a symbol must be treated differently depending on something about the variable or function named by the symbol (such as what section it is in).