home *** CD-ROM | disk | FTP | other *** search
- /* AE program profiling system.
- Machine-specific definitions for MIPS R2000/R3000 processors.
- Copyright (C) 1990 by James R. Larus (larus@cs.wisc.edu)
-
- AE and AEC are free software; you can redistribute it and/or modify it
- under the terms of the GNU General Public License as published by the
- Free Software Foundation; either version 1, or (at your option) any
- later version.
-
- AE and AEC are distributed in the hope that it will be useful, but
- WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with GNU CC; see the file COPYING. If not, write to James R.
- Larus, Computer Sciences Department, University of Wisconsin--Madison,
- 1210 West Dayton Street, Madison, WI 53706, USA or to the Free
- Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. */
-
-
- /* $Header: /var/home/larus/AE/AE/RCS/ae-mips.h,v 2.0 90/02/09 17:21:37 larus Exp Locker: larus $ */
-
-
- /* Define the base and bounds of the AE buffer that accumulates events in
- the executing program. */
-
-
- /* The pointer to the AE Buffer can either be in a register or in a
- variable stored in memory. If it is in a register, AE_BUFFER_REG
- contains the register's name, as a string. If it is in memory,
- AE_BUFFER_VAR contains the variable's name as a string.
- MAKE_AE_BUFFER_POINTER returns an rtx expression for this pointer. */
-
-
- /* On MIPS, we use R23 (aka) as the pointer to AE buffer. The limit
- is a fixed distance from the top of user memory, which is a negative
- number. */
-
- #define AE_BUFFER_REG "s7"
- #undef AE_BUFFER_VAR
-
- #define MAKE_AE_BUFFER_POINTER() gen_rtx (REG, Pmode, 23) /* 23 = s7 */
-
-
- /* The end of the AE Buffer can either be pointed to by a register or
- by a variable stored in memory. If it is in a register,
- AE_BUFFER_BOUND_REG contains the register's name, as a string. If it
- is in memory, AE_BUFFER_BOUND_VAR contains the variable's name as a
- string. MAKE_AE_BOUND_POINTER returns an rtx expression for this
- pointer. */
-
- #undef AE_BUFFER_BOUND_REG
- #undef AE_BUFFER_BOUND_VAR
-
- #define MAKE_AE_BOUND_POINTER()
-
-
- /* Alternatively, the end of the AE buffer can be a fixed distance
- from the top of the stack. */
-
- /* Here's the picture for MIPS:
-
- Top of memory --> @0x80000000
- (Reserved on MIPS) --> 4K
- Environemnt --> 10K max ??
- argv --> ?K max
- ae_start frame --> 16 bytes
- ... padding ...
- top of buffer --> @0x80000000-(32K-4K)
- */
-
- #define STACK_TOP 0x80000000
-
-
- /* Less than 32K to fit insn's 15-bit field */
-
- #define AE_BUFFER_STACK_OFFSET 32768-4096
-
-
- /* Size of AE buffer (bytes). */
-
- #define AE_BUFFER_SIZE 0x100000 /* 1MB */
-
-
- /* Size of a stack frame for the routine AE_START. */
-
- #define AE_START_FRAME_SIZE (16 * sizeof (int))
-
-
- /* Name of stack pointer register. */
-
- #define SP_REG "sp"
-
-
-
- /* One plus maximum number of instructions combine by peephole optimizer. */
-
- #define MAX_PEEP 3
-
-
- /* Return non-zero if register number REGNO can be defined upon
- function entry. */
-
- #define REGISTER_DEFINED_IN_CALL(REGNO) ((REGNO) == STACK_POINTER_REGNUM \
- || (REGNO) == FRAME_POINTER_REGNUM \
- || FUNCTION_ARG_REGNO_P ((REGNO)))
-
-
- /* Define the characters that proceed comments and assembler directives. */
-
- #define ASM_COMMENT_CHAR '#'
-
- #define ASM_DIRECTIVE_CHAR '.'
-
-
- /* Define the number of delayed instructions after a jump, conditional jump,
- or call instruction. Do not define these values if the instructions have
- no delays or the assembler hides them by doing code reorganization. */
-
- #undef JUMP_DELAY_SLOTS
-
- #undef CJUMP_DELAY_SLOTS
-
- #undef CALL_DELAY_SLOTS
-
-
- /* The size of most assembly instructions (in bytes). */
-
- #define STD_ASM_INSN_LENGTH 4
-
-
- /* Set of instruction-size pairs for instructions whose size is not
- standard. The table must be sorted by instruction name. */
-
- #define ASM_INSN_SIZE_EXCEPTIONS \
- "abs", (char *) 3, \
- "bge", (char *) 2, \
- "bgeu", (char *) 2, \
- "bgt", (char *) 2, \
- "bgtu", (char *) 2, \
- "ble", (char *) 2, \
- "bleu", (char *) 2, \
- "blt", (char *) 2, \
- "bltu", (char *) 2, \
- "div", (char *) 10, /* Guess */ \
- "divu", (char *) 10, /* Guess */ \
- "la", (char *) 2, \
- "li", (char *) 2, \
- "mul", (char *) 2, \
- "mulo", (char *) 5, \
- "mulou", (char *) 4, \
- "neg", (char *) 2, \
- "negu", (char *) 3, \
- "rem", (char *) 10, /* Guess */ \
- "remu", (char *) 10, /* Guess */ \
- "rol", (char *) 3, \
- "ror", (char *) 3, \
- "seq", (char *) 2, \
- "sge", (char *) 2, \
- "sgeu", (char *) 2, \
- "sgt", (char *) 2, \
- "sgtu", (char *) 2, \
- "sle", (char *) 2, \
- "sleu", (char *) 2, \
- "sne", (char *) 2, \
- "ulh", (char *) 2, \
- "ulhu", (char *) 2, \
- "ulw", (char *) 2, \
- "ush", (char *) 2, \
- "usw", (char *) 2
-
-
- /* Return non-zero if the assembly instruction is a branch that does
- not execute its (normally) delayed slot instruction. */
-
- #define BRANCH_IS_ANNULED(ASM_INSN) 0
-
-
- /* Return a pointer to the function name if an assembly instruction is
- a subroutine invocation. If it is not, return 0. */
-
- #define ASM_INSN_IS_CALL(ASM_INSN) (strncmp ((ASM_INSN), "jal", 3) \
- ? 0 : (ASM_INSN) + 3)
-
-
-
-
- /* Produce the schema corresponding the the standard function prologue
- and epilogue. Record values that are need upon function entry. */
-
- #define SCHEMA_PROLOGUE(RECORD_REG_ON_ENTRY) \
- { \
- /* Code from FUNCTION_PROLOGUE: */ \
- int frame_size = get_frame_size (); \
- register int regno; \
- register int mask = 0, fmask=0; \
- extern char call_used_regs []; \
- register int push_loc = 0, tsize = frame_size + 8; \
- \
- for (regno = 0; regno < 32; regno++) \
- if (MUST_SAVE_REG_LOGUES \
- || (regs_ever_live [regno] && !call_used_regs [regno])) \
- {tsize += 4; mask |= 1 << regno;} \
- \
- for (regno = 32; regno < FIRST_PSEUDO_REGISTER; regno += 2) \
- if (regs_ever_live [regno] && !call_used_regs [regno]) \
- {tsize += 8; fmask |= 1 << (regno-32);} \
- \
- if (THIS_VARARGS_SUSPECTED) tsize += 16; \
- \
- regno = STACK_POINTER_REGNUM; \
- tsize = AL_ADJUST_ALIGN (tsize); \
- \
- push_loc = 0; \
- \
- if (frame_pointer_needed \
- || regs_ever_live [29] || regs_ever_live [30] \
- || fmask || mask \
- || (frame_size > 0)) \
- record_sp (); \
- \
- for (regno = 31; regno >= 30; regno--) \
- if (MUST_SAVE_REG_LOGUES \
- || (regs_ever_live [regno] && !call_used_regs [regno])) \
- { \
- store_schema_int_offset (STACK_POINTER_REGNUM, push_loc, 0);\
- push_loc += 4; \
- } \
- \
- if (THIS_VARARGS_SUSPECTED) \
- { \
- int fregno; \
- simple_def_schema (9, 0, tsize); \
- store_schema_int_offset (STACK_POINTER_REGNUM, tsize - 4, 0);\
- for (fregno = 44; fregno< 48; fregno += 2) \
- { \
- store_schema_int_offset (STACK_POINTER_REGNUM, push_loc, 1);\
- push_loc += 8; \
- } \
- } \
- \
- for (regno = 29; regno >= 0; regno--) \
- if (MUST_SAVE_REG_LOGUES \
- || (regs_ever_live [regno] && !call_used_regs [regno]))\
- { \
- store_schema_int_offset (STACK_POINTER_REGNUM, push_loc, 0);\
- push_loc += 4; \
- } \
- \
- for (regno = 32; regno < FIRST_PSEUDO_REGISTER; regno += 2) \
- if (regs_ever_live [regno] && !call_used_regs [regno]) \
- { \
- store_schema_int_offset (STACK_POINTER_REGNUM, push_loc, 1);\
- push_loc += 8; \
- } \
- \
- if (frame_pointer_needed) \
- simple_def_schema (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM, tsize);\
- \
- for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno ++) \
- if (RECORD_REG_ON_ENTRY [regno] \
- && regno != STACK_POINTER_REGNUM \
- && regno != FRAME_POINTER_REGNUM) \
- { \
- unknown_def_schema (regno); \
- issue_event (gen_rtx (REG, Pmode, regno)); \
- } \
- }
-
-
- #define SCHEMA_EPILOGUE() \
- { \
- /* Code from FUNCTION_EPILOGUE: */ \
- int frame_size = get_frame_size (); \
- register int regno; \
- register int mask = 0, fmask = 0; \
- extern char call_used_regs []; \
- register int push_loc ; \
- \
- extern int current_function_total_framesize; \
- \
- push_loc = 0; \
- regno = STACK_POINTER_REGNUM; \
- \
- if (frame_pointer_needed) \
- simple_def_schema (8, FRAME_POINTER_REGNUM, 0); \
- \
- for (regno = 0; regno < 32; regno++) \
- if (MUST_SAVE_REG_LOGUES \
- || (regs_ever_live [regno] && !call_used_regs [regno])) \
- mask |= 1 << regno; \
- \
- for (regno = 31; regno >= 0; regno--) \
- { \
- if (MUST_SAVE_REG_LOGUES \
- || (regs_ever_live [regno] && !call_used_regs [regno]))\
- { \
- load_schema_int_offset ((frame_pointer_needed ? 8 : STACK_POINTER_REGNUM),\
- (frame_pointer_needed ? \
- push_loc - current_function_total_framesize:\
- push_loc), \
- 0); \
- push_loc += 4; \
- } \
- if (THIS_VARARGS_SUSPECTED && (regno == 30)) \
- push_loc += 16; \
- } \
- \
- for (regno = 32; regno < FIRST_PSEUDO_REGISTER; regno += 2) \
- if (regs_ever_live [regno] && !call_used_regs [regno]) \
- fmask |= 1 << (regno-32); \
- \
- for (regno = 32; regno < FIRST_PSEUDO_REGISTER; regno += 2) \
- if (regs_ever_live [regno] && !call_used_regs [regno]) \
- { \
- load_schema_int_offset ((frame_pointer_needed ? 8 : STACK_POINTER_REGNUM),\
- (frame_pointer_needed ? \
- push_loc - current_function_total_framesize:\
- push_loc), \
- \
- 1); \
- push_loc += 8; \
- } \
- \
- if (frame_pointer_needed) \
- simple_def_schema (STACK_POINTER_REGNUM, 8, 0); \
- else \
- if (regs_ever_live [29]|| regs_ever_live [30] \
- || fmask || mask \
- || (frame_size > 0)) \
- simple_def_schema (STACK_POINTER_REGNUM, STACK_POINTER_REGNUM,\
- current_function_total_framesize); \
- }
-
-
-
- /* Produce and write the the assembly output file code to record the
- various types of events. */
-
-
- /* Check that the AE buffer has SIZE bytes free. If not, empty the
- buffer. */
-
- #define GENERATE_SPACE_CHECK(COMMENT, SIZE) \
- { \
- rtx xops [1]; \
- rtx label = gen_label_rtx (); \
- char buffer [256]; \
- \
- sprintf (buffer, ".set noat\t\t\t\t# %s Event w/ check", COMMENT);\
- output_asm_insn (buffer, xops); \
- \
- xops [0] = ae_buffer_pointer; \
- sprintf (buffer, "addu $1,%%0,%d", AE_BUFFER_STACK_OFFSET + CHUNK_SIZE);\
- output_asm_insn (buffer, xops); \
- \
- xops [0] = label; \
- output_asm_insn ("bgtz $1,%l0", xops); \
- output_asm_insn (".set at", xops); \
- \
- output_asm_insn ("jal ae_flush_buffer", xops); \
- \
- ASM_OUTPUT_INTERNAL_LABEL (asm_out_file, "L", CODE_LABEL_NUMBER (label));\
- }
-
-
- /* Generate an event to record VALUE (an rtx register). */
-
- #define GENERATE_EVENT(VALUE) \
- { \
- rtx xops [2]; \
- \
- xops [0] = VALUE; \
- xops [1] = ae_buffer_pointer; \
- output_asm_insn ("usw\t%0,0(%1)", xops); \
- \
- xops [0] = ae_buffer_pointer; \
- output_asm_insn ("addiu\t%0,%0,4\t\t# End Event", xops); \
- }
-
-
- /* Generate an event to record the integer VALUE, which should be
- stored in BYTES bytes. */
-
- #define GENERATE_SHORT_EVENT(VALUE, BYTES) \
- { \
- rtx xops [2]; \
- \
- output_asm_insn (".set noat", xops); \
- xops [0] = gen_rtx (CONST_INT, VOIDmode, VALUE); \
- output_asm_insn ("addiu\t$1,$0,%0", xops); \
- \
- xops [0] = ae_buffer_pointer; \
- if (BYTES == 1) \
- output_asm_insn ("sb\t$1,0(%0)", xops); \
- else \
- output_asm_insn ("ush\t$1,0(%0)", xops); \
- output_asm_insn (".set at", xops); \
- \
- xops [0] = ae_buffer_pointer; \
- xops [1] = gen_rtx (CONST_INT, VOIDmode, BYTES); \
- output_asm_insn ("addiu\t%0,%0,%1\t\t# End Short Event", xops);\
- }
-
-
- /* Generate an event to record ADDRESS, which is made computed from BASE and
- OFFSET. */
-
- #define GENERATE_ADDRESS_EVENT(ADDRESS, BASE, OFFSET) \
- { \
- rtx xops [1]; \
- \
- output_asm_insn (".set noat", xops); \
- xops [0] = ADDRESS; \
- /* Causes assembler warning since LA is a macro, but produces \
- correct code. */ \
- output_asm_insn ("la\t$1,%0", xops); \
- \
- xops [0] = ae_buffer_pointer; \
- output_asm_insn ("usw\t$1,0(%0)", xops); \
- output_asm_insn (".set at", xops); \
- \
- xops [0] = ae_buffer_pointer; \
- output_asm_insn ("addiu\t%0,%0,4\t\t# End Address Event", xops);\
- }
-
-
-
- /* Assembly code routines for aecrt0.o. */
-
- #ifdef AE_START_ASM
- .align 2
- .globl ae_start
- .ent ae_start
- ae_start:
- .set nomove /* Do not allow the assembler to move insns.*/
- lw $4,0($sp)
- la $gp,_gp
- addiu $5,$sp,4
- addiu $6,$5,4
- sll $2,$4,2
- addu $6,$6,$2
- addiu $sp,$sp,-24
- sw $0,20($sp)
- sw $6,environ
- sw $5,__Argv
- sw $4,__Argc
- sw $0,errno
- jal ae_initialize /* Addition */
- lw $5,__Argv /* ditto */
- lw $4,__Argc /* ditto */
- jal main
- jal exit
- move $4,$2
- break 0
- .set move
- .end ae_start
- #endif
-
-
- #ifdef AE_FLUSH_BUFFER_ASM
- .align 2
- .globl ae_flush_buffer
- .ent ae_flush_buffer
- ae_flush_buffer:
- /*PROLOGUE */
- /* .mask 0xc0010000 */
- subu $29,152 /*temp= 128,saveregs= 24, sfo= -8 */
- sw $31,0($29)
- sw $30,4($29)
- sw $16,8($29)
- /* .fmask 0x0 */
- addiu $30,$29,152 /*Establish FramePTR */
- /*END PROLOGUE */
- .set noat
- addiu $16,$30,0xff78 /*addsi3 $30,-136 -> $16 */
- sw $1,4($16)
- .set at
- sw $2,8($16)
- sw $3,12($16)
- sw $4,16($16)
- sw $5,20($16)
- sw $6,24($16)
- sw $7,28($16)
- sw $8,32($16)
- sw $9,36($16)
- sw $10,40($16)
- sw $11,44($16)
- sw $12,48($16)
- sw $13,52($16)
- sw $14,56($16)
- sw $15,60($16)
- sw $17,68($16)
- sw $18,72($16)
- sw $19,76($16)
- sw $20,80($16)
- sw $21,84($16)
- sw $22,88($16)
- sw $24,96($16)
- sw $25,100($16)
- sw $26,104($16)
- sw $27,108($16)
- sw $28,112($16)
- addiu $29,$29,0xfff0 /*subsi3 $29,16 -> $29 */
- lw $4,ae_fd /*movsi ae_fd -> $4 */
- lw $5,ae_buffer_base /*movsi ae_buffer_base -> $5 */
- subu $6,$23,$5 /*subsi3 $23,$5 -> $6 */
- jal write /* call write regle 2-call (VOIDmode) */
- lw $23,ae_buffer_base /*movsi ae_buffer_base -> $23 */
- .set noat
- lw $1,4($16)
- .set at
- lw $2,8($16)
- lw $3,12($16)
- lw $4,16($16)
- lw $5,20($16)
- lw $6,24($16)
- lw $7,28($16)
- lw $8,32($16)
- lw $9,36($16)
- lw $10,40($16)
- lw $11,44($16)
- lw $12,48($16)
- lw $13,52($16)
- lw $14,56($16)
- lw $15,60($16)
- lw $17,68($16)
- lw $18,72($16)
- lw $19,76($16)
- lw $20,80($16)
- lw $21,84($16)
- lw $22,88($16)
- lw $24,96($16)
- lw $25,100($16)
- lw $26,104($16)
- lw $27,108($16)
- lw $28,112($16)
- addiu $29,$29,0x10 /*addsi3 $29,16 -> $29 */
- /*EPILOGUE */
- addu $29,$0,$30 /* sp not trusted here */
- /* .mask 0xc0010000 */
- lw $31,-152($29)
- lw $30,-148($29)
- lw $16,-144($29)
- /* .fmask 0x0 */
- j $31
- /*END EPILOGUE */
- .end ae_flush_buffer
- .comm ae_fd,8
- .comm ae_buffer_base,8
- #endif
-
-
-
- /* Definitions for AEC. */
-
- /* a.out file format is ECOFF, with the LDFCN library to find symbols. */
-
- #define ECOFF_AOUT
- #undef BSD_AOUT
-
-
- /* Function call returns this many bytes after call instruction. */
-
- /* We don't see delayed instructions on MIPS, so return to the next
- instruction.*/
-
- #define PC_OFFSET_AFTER_CALL 4
-
-
- /* Return non-zero if register N is local to a function, e.g. can
- have distinct values in different functions. */
-
- #define REG_LOCAL_TO_FUNCTION(N) (!call_used_regs [(N)] \
- || (N) == STACK_POINTER_REGNUM)
-
-
- /* Initialize registers before the generation program begins. */
-
- #define INITIALIZE_REGISTERS() \
- { \
- char buf [80]; \
- output_set_value (0, "0"); \
- sprintf (buf, "0x%x", symbol_address_or_die ("_gp")); \
- output_set_value (28, buf); \
- }
-