home *** CD-ROM | disk | FTP | other *** search
- /* AE program profiling system.
- Code to produce schemas and instrument assembly code.
- Copyright (C) 1989, 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-output.c,v 2.2 90/02/14 09:20:01 larus Exp Locker: larus $ */
-
-
- #include <stdio.h>
- #include <string.h>
- #include "config.h"
- #include "rtl.h"
- #include "basic-block.h"
- #include "flags.h"
- #include "regs.h"
- #include "ae.h"
- #include "ae-machine.h"
- #include "schema.h"
-
-
- void ae_after_block_end ();
- void ae_after_call_insn ();
- void ae_after_easy_insn ();
- void ae_after_impossible_insn ();
- void ae_after_load_insn ();
- void ae_after_store_insn ();
- void ae_before_block_end ();
- void ae_before_call_insn ();
- void ae_before_easy_insn ();
- void ae_before_impossible_insn ();
- void ae_before_load_insn ();
- void ae_before_store_insn ();
- void ae_block_start ();
- void ae_function_end ();
- void ae_function_start ();
- int asm_insn_size ();
- void block_end_cjump_schema ();
- void block_end_jump_schema ();
- void block_end_schema ();
- void block_start_schema ();
- void call_indirect_schema ();
- void call_schema ();
- void call_schema_str ();
- int cjump_target_p ();
- void compute_def_schema ();
- int condjump_p ();
- list defns_reaching_insn ();
- void edge_schema ();
- rtx find_block_head ();
- void find_mem_refs ();
- void flush_uneventful_insn ();
- void free_list ();
- void function_end_schema ();
- void function_start_schema ();
- rtx gen_rtx ();
- int get_frame_size ();
- int head_to_block_number ();
- int implicit_last_block ();
- void issue_address_event ();
- void issue_event ();
- void issue_event_space_check ();
- void issue_short_event ();
- void load_schema_int_offset ();
- void load_schema_reg_offset ();
- void load_symbol_schema ();
- void load_unknown_schema ();
- int multiway_jump_p ();
- rtx next_insn_or_label ();
- void note_stores ();
- void output_asm_insn ();
- void peek_ahead ();
- void process_block_start ();
- void process_insn_after ();
- void process_insn_before ();
- int record_fp ();
- void record_insn_effects ();
- int record_sp ();
- void rtx_arg_out ();
- char *rtx_op_out ();
- void save_store_dest ();
- void simple_def_schema ();
- int simplejump_p ();
- void store_schema_int_offset ();
- void store_schema_reg_offset ();
- void store_symbol_schema ();
- void store_unknown_schema ();
- int substring ();
- void symbol_def_schema ();
- void uneventful_schema ();
- void unknown_def_schema ();
-
-
- rtx *basic_block_end;
- rtx *basic_block_head;
-
- extern aux_insn_info *insn_info; /* Information on instructions */
-
- extern char record_reg_on_entry []; /* Non-zero => save register upon entry. */
-
- extern FILE *asm_out_file; /* Assembly output file. */
-
- extern FILE *schema_out_file; /* Schema output file. */
-
- extern char *fun_name; /* Name of function being processed. */
-
-
- /* Maintain a circular queue of the next MAX_PEEP instructions and
- their patterns, so we can look ahead (LA) to account for the effects
- of instructions deleted by peephole optimization. */
-
- static rtx la_insn [MAX_PEEP];
-
- static rtx la_pattern [MAX_PEEP];
-
-
- /* H points one position before first item in queue. T points to the
- last element in queue. */
-
- static int la_h = 0, la_t = 0;
-
-
- /* Non-zero if the assembly code for an instruction is not yet output. */
-
- static int before_insn_flg;
-
-
- /* Number of block being processed. */
-
- static int block_no;
-
-
- /* Used to retrieve destination of store instruction via NOTE_STORE. */
-
- static rtx store_dest;
-
-
- /* Used in THUNK_FOR_LOAD/STORE_INSN. */
-
- static rtx check_insn;
-
-
- /* Number of uneventful instructions since the last eventful one. */
-
- static int num_uneventful_insn = 0;
-
-
- /* Non-zero when outputing instructions to record event. */
-
- static int issuing_event = 0;
-
-
- /* Non-zero when processing rtx CALL insn. */
-
- static int in_rtx_call_insn = 0;
-
-
- /* rtx code for register containing pointer to AE buffer */
-
- static rtx ae_buffer_pointer = NULL;
-
-
- /* rtx code for register containing pointer to end of AE buffer */
-
- #if (defined (AE_BUFFER_BOUND_REG) || defined (AE_BUFFER_BOUND_VAR))
- static rtx ae_buffer_end_pointer = NULL;
- #endif
-
-
- /* Non-zero means last branch instruction was annuled and so did not
- execute its delay slots. */
-
- #if (defined (JUMP_DELAY_SLOTS) || defined (CJUMP_DELAY_SLOTS))
- static int annuled_branch_seen = 0;
- #endif
-
-
- /* Amount of space left in the AE buffer from the amount available
- upon block entry. */
-
- static int space_left_in_chunk = 0;
-
-
-
- /* Invoke just before assembly code for an instruction or label is
- output. Notice interesting events and issue a schema command and/or
- produce code to record the event. */
-
- void
- watch_insn_output (insn)
- register rtx insn;
- {
- rtx par_1;
- register int i;
-
- if (GET_CODE (insn) == INSN
- && GET_CODE (PATTERN (insn)) == PARALLEL
- && (par_1 = XVECEXP (PATTERN (insn), 0, 0))
- && ! (GET_CODE (par_1) == SET
- || GET_CODE (par_1) == USE
- || GET_CODE (par_1) == CLOBBER
- || GET_CODE (par_1) == CALL
- || GET_CODE (par_1) == RETURN))
- /* Instruction munged by peephole optimization. We don't have a
- real pattern that we can interpret and the following instruction
- is deleted. Luckily, we record the patterns of instructions
- ahead of the current instruction. */
- {
- rtx next_insn = next_insn_or_label (insn, 1);
- register int i, num_examined = 0;
-
- while (la_t != la_h && la_insn [la_h] != next_insn)
- {
- /* Examine effects of instructions up to next (undeleted)
- instruction. */
- if (la_insn [la_h])
- record_insn_effects (la_insn [la_h], la_pattern [la_h]);
- la_h = (la_h + 1) % MAX_PEEP;
- num_examined += 1;
- }
- /* Record instructions MAX_PEEP ahead for this instruction
- (minus 1 for deleted next instruction) and deleted instructions. */
- for (i = 0; i < num_examined; i ++)
- peek_ahead (next_insn_or_label (insn, MAX_PEEP - 1 + i));
- }
- else
- {
- peek_ahead (next_insn_or_label (insn, MAX_PEEP));
- record_insn_effects (insn, PATTERN (insn));
- }
- }
-
-
- /* Initialize the look ahead buffer by filling it with the first instructions
- in a function. */
-
- void
- initialize_look_ahead_buffer ()
- {
- register int i;
-
- la_h = la_t = 0;
- if (n_basic_blocks > 0)
- for (i = 0; i < MAX_PEEP; i++)
- peek_ahead (insn_or_label (basic_block_head [0], i + 1));
- }
-
-
- /* Remember the instruction MAX_PEEP instructions further along, so
- that we can find its pattern even if it is destroyed by peephole
- optimization. */
-
- static void
- peek_ahead (nth_insn)
- rtx nth_insn;
- {
- la_t = (la_t + 1) % MAX_PEEP;
- if (la_t == la_h) la_h = (la_h + 1) % MAX_PEEP;
- la_insn [la_t] = nth_insn;
- la_pattern [la_t] = (nth_insn == (rtx) NULL
- || GET_CODE (nth_insn) == CODE_LABEL
- ? NULL : PATTERN (nth_insn));
- }
-
-
- /* Capture the an instruction's events by either producing a schema or
- adding code to the assembly file to record values or both. We
- maintain an one instruction look-ahead buffer so that routines for
- each type of instruction can be invoked before and after the assembly
- code for the instruction is produced. */
-
- void
- record_insn_effects (insn, pattern)
- register rtx insn, pattern;
- {
- static rtx prev_insn = NULL;
- static rtx prev_pattern = NULL;
-
- if (prev_insn)
- process_insn_after (prev_insn, prev_pattern);
- if (insn)
- process_insn_before (insn, pattern);
- prev_insn = insn;
- prev_pattern = pattern;
- }
-
-
- /* Invoke the appropriate routine for each type of instruction BEFORE its
- assembly code is written to the file. */
-
- static void
- process_insn_before (insn, pattern)
- rtx insn, pattern;
- {
- register aux_insn_info *info = &insn_info [INSN_UID (insn)];
- register int flags = info->flags;
- void thunk_for_load_insn ();
-
- store_dest = NULL;
- /* Function start is processed before any instructions. Block start
- is process before instructions, but after labels. */
- if (flags & FUNCTION_START_FLAG)
- ae_function_start ();
-
- if ((flags & BLOCK_START_FLAG) && GET_CODE (insn) != CODE_LABEL)
- process_block_start (insn);
-
- if (GET_CODE (insn) == CODE_LABEL)
- ;
- else if (flags & (EASY_INSN_FLAG | HARD_INSN_FLAG))
- ae_before_easy_insn (insn, pattern);
- else if (GET_CODE (insn) == CALL_INSN)
- {
- ae_before_call_insn (insn, flags & IMPOSSIBLE_INSN_FLAG);
- if (flags & IMPOSSIBLE_INSN_FLAG)
- note_stores (pattern, save_store_dest);
- goto may_be_impossible;
- }
- else /* Load and stores */
- {
- note_stores (pattern, save_store_dest);
-
- if (store_dest
- && (GET_CODE (store_dest) == MEM
- || GET_CODE (store_dest) == CONST))
- ae_before_store_insn (insn, store_dest);
- else
- {
- check_insn = insn;
- before_insn_flg = 1;
- if (GET_CODE (pattern) == SET)
- /* Only interested in loads at this point. */
- find_mem_refs (SET_SRC (pattern), thunk_for_load_insn);
- else
- APPLY_TO_EXP_IN_INSN (pattern,
- e,
- find_mem_refs (e, thunk_for_load_insn));
-
- may_be_impossible:
- if (flags & IMPOSSIBLE_INSN_FLAG)
- ae_before_impossible_insn (insn, store_dest);
- }
- }
-
- if (flags & BLOCK_END_FLAG)
- ae_before_block_end (insn, block_no);
- }
-
-
- void
- process_block_start (insn)
- rtx insn;
- {
- block_no = head_to_block_number (find_block_head (insn));
- ae_block_start (insn, block_no,
- cjump_target_p (basic_block_head [block_no]));
- }
-
-
- /* Invoke the appropriate routine for each type of instruction AFTER its
- assembly code is written to the file. */
-
- static void
- process_insn_after (insn, pattern)
- rtx insn, pattern;
- {
- register aux_insn_info *info = &insn_info [INSN_UID (insn)];
- register int flags = info->flags;
- void thunk_for_load_insn ();
-
- if ((flags & BLOCK_START_FLAG) && GET_CODE (insn) == CODE_LABEL)
- process_block_start (insn);
-
- if (GET_CODE (insn) == CODE_LABEL)
- ;
- else if (flags & (EASY_INSN_FLAG | HARD_INSN_FLAG))
- ae_after_easy_insn (insn, pattern);
- else if (GET_CODE (insn) == CALL_INSN)
- {
- ae_after_call_insn (insn, flags & IMPOSSIBLE_INSN_FLAG);
- if (flags & IMPOSSIBLE_INSN_FLAG)
- note_stores (pattern, save_store_dest);
- goto may_be_impossible;
- }
- else /* Load and stores */
- {
- store_dest = NULL;
- note_stores (pattern, save_store_dest);
-
- if (store_dest
- && (GET_CODE (store_dest) == MEM || GET_CODE (store_dest) == CONST))
- ae_after_store_insn (insn, store_dest);
- else
- {
- check_insn = insn;
- before_insn_flg = 0;
- if (GET_CODE (pattern) == SET)
- /* Only interested in loads at this point. */
- find_mem_refs (SET_SRC (pattern), thunk_for_load_insn);
- else
- APPLY_TO_EXP_IN_INSN (pattern,
- e,
- find_mem_refs (e, thunk_for_load_insn));
-
- may_be_impossible:
- if (flags & IMPOSSIBLE_INSN_FLAG)
- ae_after_impossible_insn (insn, store_dest);
- }
- }
-
- if (flags & BLOCK_END_FLAG)
- ae_after_block_end (insn, block_no);
- }
-
-
- /* Set STORE_DEST to the destination of a store instruction. */
-
- static void
- save_store_dest (d, x) rtx d, x; {store_dest = d;}
-
-
- static void
- thunk_for_load_insn (exp, base, offset)
- rtx exp, base, offset;
- {
- if (before_insn_flg)
- ae_before_load_insn (check_insn, exp);
- else
- ae_after_load_insn (check_insn, exp);
- }
-
-
- /* Return 1 if function contains an implicit final block and 0
- otherwise. */
-
- int
- implicit_last_block ()
- {
- int l = n_basic_blocks - 1;
-
- if (l > 0)
- {
- rtx last_end = basic_block_end [l];
- if (GET_CODE (last_end) == JUMP_INSN
- && !simplejump_p (last_end)
- && condjump_p (last_end))
- return 1;
- else
- return 0;
- }
- return 0;
- }
-
-
-
- /* Table of instructions that take up more than one word. These are
- usually pseudo-instructions allowed by the assembler. Even elements
- are instructions' names. Odd elements are the size (in number of
- words). All other instructions are assumed to be STD_ASM_INSN_LENGTH
- bytes. Table must be sorted by instruction name. */
-
- static char *asm_insn_size_tbl [] = {
- #ifdef ASM_INSN_SIZE_EXCEPTIONS
- ASM_INSN_SIZE_EXCEPTIONS
- #else
- 0
- #endif
- };
-
-
- /* Invoked by OUTPUT_ASM_INSN before each instruction or label is
- written to assembly file. */
-
- void
- watch_asm_insn_output (template, operands)
- register char *template;
- rtx *operands;
- {
- register char *e;
-
- #if (defined (JUMP_DELAY_SLOTS) || defined (CJUMP_DELAY_SLOTS))
- annuled_branch_seen = 0;
- #endif
-
- if (!issuing_event)
- while (*template != '\0')
- {
- /* Skip white space */
- while (*template == ' ' || *template == '\t') template ++;
- if ((*template == ASM_COMMENT_CHAR))
- ;
- else if ((*template == ASM_DIRECTIVE_CHAR))
- ;
- else if (!in_rtx_call_insn && (e = ASM_INSN_IS_CALL (template)))
- {
- /* Instruction contains a call to a subroutine (whose name
- probably begins with a ".") that is not apparent in rtx code. */
-
- register char buf [256], *p;
-
- flush_uneventful_insn (0);
- /* Find end of subroutine name: */
- for (p = e; *p != ',' && *p != ' ' && *p != '\n' && *p != '\0'; )
- p ++;
- buf [0] = '*'; /* Do not prepend an '_' */
- strncpy (buf + 1, e, p - e);
- buf [p - e + 1] = '\0';
- call_schema_str (buf);
- }
- else
- {
- #if (defined (JUMP_DELAY_SLOTS) || defined (CJUMP_DELAY_SLOTS))
- if (BRANCH_IS_ANNULED (template))
- annuled_branch_seen = 1;
- #endif
- num_uneventful_insn += asm_insn_size (template);
- }
-
- /* Check for multiple instructions in one string. */
- while (*template != '\0' && *template != '\n') template ++;
- if (*template == '\n') template ++;
- }
- }
-
-
- static int
- asm_insn_size (template)
- register char *template;
- {
- #ifdef ASM_INSN_SIZE_EXCEPTIONS
- register int low = 0;
- register int hi = ((sizeof (asm_insn_size_tbl) / sizeof (char *)) / 2) - 1;
-
- while (low <= hi)
- {
- register int mid = (low + hi) / 2;
- register char *t = template, *p = asm_insn_size_tbl [2 * mid];
-
- while (*t == *p) {t++; p++;}
-
- if (*p == '\0') /* End of pattern */
- return (int) asm_insn_size_tbl [2 * mid + 1];
- else if (*t > *p)
- low = mid + 1;
- else
- hi = mid - 1;
- }
- #endif
-
- return 1; /* Most instructions are 1 word long */
- }
-
-
- /* Return non-zero if S2 is a substring of S1. */
-
- static int
- substring (s1, s2)
- register char *s1, *s2;
- {
- for ( ; *s1 != '\0'; s1 ++)
- {
- register char *ss1 = s1, *ss2 = s2;
-
- for ( ; *ss1 && *ss2 && *ss1 == *ss2; ss1 ++, ss2 ++ );
- if (*ss2 == '\0') return 1;
- }
- return 0;
- }
-
-
-
- void
- ae_function_start ()
- {
- function_start_schema (fun_name, n_basic_blocks + implicit_last_block ());
- ae_buffer_pointer = MAKE_AE_BUFFER_POINTER ();
- #if (defined (AE_BUFFER_BOUND_REG) || defined (AE_BUFFER_BOUND_VAR))
- ae_buffer_end_pointer = MAKE_AE_BOUND_POINTER ();
- #endif
- SCHEMA_PROLOGUE (record_reg_on_entry);
- }
-
-
- static int
- record_sp ()
- {
- unknown_def_schema (STACK_POINTER_REGNUM);
- issue_event (stack_pointer_rtx);
- return 1;
- }
-
-
- static int
- record_fp ()
- {
- unknown_def_schema (FRAME_POINTER_REGNUM);
- issue_event (frame_pointer_rtx);
- return 1;
- }
-
-
- void
- ae_function_end ()
- {
- SCHEMA_EPILOGUE ();
- function_end_schema (fun_name);
- }
-
-
-
- /* If a conditional jumps to a block, then issue an event upon entry. */
-
- void
- ae_block_start (insn, block_no, cjump_target_p)
- rtx insn;
- int block_no, cjump_target_p;
- {
- space_left_in_chunk = 0;
- flush_uneventful_insn (0); /* Previous block's delayed instruction */
- if (cjump_target_p)
- {
- block_start_schema (block_no, 1);
- /* Plus 1 since function m */
- issue_short_event (block_no, n_basic_blocks + implicit_last_block ());
- }
- else
- block_start_schema (block_no, 0);
- }
-
-
- void
- ae_before_block_end (insn, block_no)
- rtx insn;
- int block_no;
- {
- }
-
-
- void
- ae_after_block_end (insn, block_no)
- rtx insn;
- int block_no;
- {
- if (insn == NULL)
- {
- flush_uneventful_insn (0);
- block_end_schema (insn, block_no, 0);
- }
- else if (GET_CODE (insn) == JUMP_INSN)
- {
- if (simplejump_p (insn))
- {
- #ifdef JUMP_DELAY_SLOTS
- if (annuled_branch_seen)
- flush_uneventful_insn (1);
- else
- {
- flush_uneventful_insn (1 + JUMP_DELAY_SLOTS);
- num_uneventful_insn += JUMP_DELAY_SLOTS;
- }
- #else
- flush_uneventful_insn (1);
- #endif
- block_end_jump_schema (insn,
- block_no,
- head_to_block_number (JUMP_LABEL (insn)),
- cjump_target_p (JUMP_LABEL (insn)));
- }
- else if (condjump_p (insn) || multiway_jump_p (insn))
- {
- #ifdef CJUMP_DELAY_SLOTS
- flush_uneventful_insn (1 + CJUMP_DELAY_SLOTS);
- num_uneventful_insn += 1;
- #else
- flush_uneventful_insn (1);
- #endif
- block_end_cjump_schema (insn, block_no);
- }
- else
- {
- /* A multiway branch appears as:
- (jump_insn (parallel [(set (pc) (reg #)) (use (label_ref ##))]))
- where ## is the label of the instruction containing the address
- vector (which is not passed to us by final). Process the address
- vector, no this blind jump. */
- ae_after_block_end (NEXT_INSN (NEXT_INSN
- (CONTAINING_INSN
- (XEXP (XVECEXP (PATTERN (insn),
- 0, 1),
- 0)))),
- block_no);
- }
- }
- else
- {
- flush_uneventful_insn (0);
- /* Block ends with non-jump instruction. */
- block_end_schema (insn,
- block_no,
- cjump_target_p (next_insn_or_label (insn, 1)));
- }
- }
-
-
- static void
- ae_before_call_insn (insn, impossible_flag)
- rtx insn;
- int impossible_flag;
- {
- in_rtx_call_insn = 1;
- }
-
-
- static void
- ae_after_call_insn (insn, impossible_flag)
- rtx insn;
- int impossible_flag;
- {
- rtx p = PATTERN (insn);
- rtx x = (GET_CODE (p) == PARALLEL ? XVECEXP (p, 0, 0) : p);
- rtx c = (GET_CODE (x) == SET ? SET_SRC (x) : x);
- rtx callee = XEXP (c, 0);
-
- #ifdef CALL_DELAY_SLOTS
- flush_uneventful_insn (1 + CALL_DELAY_SLOTS);
- if (impossible_flag)
- num_uneventful_insn += 2; /* To account for NOP before call is output */
- else
- num_uneventful_insn += 1; /* To account for NOP */
- #else
- flush_uneventful_insn (1);
- #endif
- in_rtx_call_insn = 0;
- if (GET_CODE (callee) == MEM && GET_CODE (XEXP (callee, 0)) == SYMBOL_REF)
- call_schema (XEXP (callee, 0));
- else if (GET_CODE (callee) == MEM && GET_CODE (XEXP (callee, 0)) == REG)
- {
- list defs = defns_reaching_insn (insn, XEXP (callee, 0));
-
- if (defs != NULL && CDR (defs) == NULL) /* 1 element list */
- {
- rtx def = PATTERN ((rtx) CAR (defs));
-
- if (GET_CODE (def) == SET && GET_CODE (SET_SRC (def)) == SYMBOL_REF)
- call_schema (SET_SRC (def));
- else
- goto indirect_call;
- }
- else
- /* Otherwise, do an indirect call to an address that is saved (since
- the instruction appears to be impossible). */
- indirect_call:
- call_indirect_schema (XEXP (callee, 0));
- free_list (defs);
- }
- else
- error ("Unknown quantity to call_indirect");
- }
-
-
- static void
- ae_before_easy_insn (insn, pattern)
- rtx insn, pattern;
- {
- }
-
-
- static void
- ae_after_easy_insn (insn, pattern)
- rtx insn, pattern;
- {
- flush_uneventful_insn (1);
- if (GET_CODE (pattern) == SET)
- {
- register rtx d = SET_DEST (pattern);
- register rtx e = SET_SRC (pattern);
-
- while (1)
- switch (GET_CODE (e))
- {
- case PLUS:
- case MINUS:
- case MULT:
- case DIV:
- case MOD:
- case AND:
- case IOR:
- case LSHIFT:
- case ASHIFT:
- case LSHIFTRT:
- compute_def_schema (REGNO (d), GET_CODE (e), XEXP (e, 0),
- XEXP (e, 1));
- return;
-
- case NEG:
- case NOT:
- compute_def_schema (REGNO (d), GET_CODE (e), XEXP (e, 0), NULL);
- return;
-
- case SYMBOL_REF:
- if (*XSTR (e, 0) == '*')
- /* Probably a local symbol, so record value */
- {
- unknown_def_schema (REGNO (d));
- issue_event (d);
- }
- else
- symbol_def_schema (REGNO (d), XSTR (e, 0), 0);
- return;
-
- case SIGN_EXTEND:
- e = XEXP (e, 0);
- break;
-
- case CONST:
- {
- /* Instruction is: rx <- @sym or rx <- @sym + c. */
- rtx t = XEXP (e, 0);
- rtx base, offset;
-
- if (GET_CODE (t) == PLUS)
- {
- base = XEXP (t, 0), offset = XEXP (t, 1);
- if (GET_CODE (base) == SYMBOL_REF
- && GET_CODE (offset) == CONST_INT)
- {
- char *symbol_name = XSTR (base, 0);
-
- if (*symbol_name == '*')
- {
- unknown_def_schema (REGNO (d));
- issue_event (d);
- }
- else
- symbol_def_schema (REGNO (d), symbol_name,
- XINT (offset, 0));
- }
- else
- goto unknown;
- }
- else if (GET_CODE (t) == SYMBOL_REF)
- symbol_def_schema (REGNO (d), XEXP (t, 0), 0);
- else
- goto unknown;
- return;
- }
-
- case SUBREG:
- d = SUBREG_REG (d);
- /* Fall through */
-
- case CONST_INT:
- case REG:
- compute_def_schema (REGNO (d), NIL, e, NULL);
- return;
-
- case LABEL_REF:
- unknown_def_schema (REGNO (d));
- issue_event (d);
- return;
-
- default:
- goto unknown;
- }
- }
- else if (GET_CODE (pattern) == PARALLEL)
- {
- register int i;
-
- for (i = 0; i < XVECLEN (pattern, 0); i ++)
- ae_before_easy_insn (insn, XVECEXP (pattern, 0, i));
- }
- else
- {
- unknown:
- print_rtl(stderr, insn);
- error ("Easy insn wasn't so easy."); /*NOTREACHED*/
- }
- }
-
-
-
- void
- ae_before_impossible_insn (insn, store_dest)
- rtx insn, store_dest;
- {
- }
-
-
- void
- ae_after_impossible_insn (insn, store_dest)
- rtx insn, store_dest;
- {
- flush_uneventful_insn (1);
- unknown_def_schema (REGNO (store_dest));
- issue_event (store_dest);
- }
-
-
- void
- ae_before_load_insn (insn, exp)
- rtx insn, exp;
- {
- void thunk_for_load_before ();
-
- find_mem_refs (exp, thunk_for_load_before);
- }
-
-
- void
- ae_after_load_insn (insn, exp)
- rtx insn, exp;
- {
- void thunk_for_load_after ();
-
- flush_uneventful_insn (1);
- find_mem_refs (exp, thunk_for_load_after);
- }
-
-
- static void
- thunk_for_load_before (exp, base, offset)
- rtx exp, base, offset;
- {
- if (GET_CODE (base) == SYMBOL_REF)
- {
- if (*XSTR (base, 0) == '*')
- goto unknown; /* Probably a local symbol, so record value */
- else if (offset == NULL)
- ;
- else if (GET_CODE (offset) == CONST_INT)
- ;
- else
- goto unknown;
- }
- else if (REG_P (base))
- {
- if (offset == NULL)
- ;
- else if (GET_CODE (offset) == CONST_INT)
- ;
- else if (REG_P (offset))
- ;
- else
- goto unknown;
- }
- else if (GET_CODE (base) == CONST
- && GET_CODE (XEXP (base, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (base, 0), 0)) == SYMBOL_REF)
- {
- if (*XSTR (base, 0) == '*')
- goto unknown; /* Probably a local symbol, so record value */
- }
- else
- {
- unknown:
- issue_address_event (exp, base, offset);
- }
- }
-
-
- static void
- thunk_for_load_after (exp, base, offset)
- rtx exp, base, offset;
- {
- if (GET_CODE (base) == SYMBOL_REF)
- {
- char *symbol_name = XSTR (base, 0);
-
- if (*symbol_name == '*')
- goto unknown; /* Probably a local symbol, so record value */
- else if (offset == NULL)
- load_symbol_schema (symbol_name, 0);
- else if (GET_CODE (offset) == CONST_INT)
- load_symbol_schema (symbol_name, XINT (offset, 0));
- else
- goto unknown;
- }
- else if (REG_P (base))
- {
- if (offset == NULL)
- load_schema_int_offset (REGNO (base), 0, 0);
- else if (GET_CODE (offset) == CONST_INT)
- load_schema_int_offset (REGNO (base), XINT (offset, 0), 0);
- else if (REG_P (offset))
- load_schema_reg_offset (REGNO (base), offset, 0);
- else
- goto unknown;
- }
- else if (GET_CODE (base) == CONST
- && GET_CODE (XEXP (base, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (base, 0), 0)) == SYMBOL_REF)
- {
- char *symbol_name = XSTR (XEXP (XEXP (base, 0), 0), 0);
- if (*symbol_name == '*')
- goto unknown; /* Probably a local symbol, so record value */
- else
- load_symbol_schema (symbol_name, XINT (XEXP (XEXP (base, 0), 1), 0));
- }
- else
- {
- unknown:
- load_unknown_schema ();
- }
- }
-
-
- void
- ae_before_store_insn (insn, store_dest)
- rtx insn, store_dest;
- {
- void thunk_for_store_before ();
-
- find_mem_refs (store_dest, thunk_for_store_before);
- }
-
-
- void
- ae_after_store_insn (insn, store_dest)
- rtx insn, store_dest;
- {
- void thunk_for_store_after ();
-
- flush_uneventful_insn (1);
- find_mem_refs (store_dest, thunk_for_store_after);
- }
-
-
- static void
- thunk_for_store_before (exp, base, offset)
- rtx exp, base, offset;
- {
- if (GET_CODE (base) == SYMBOL_REF)
- {
- if (*XSTR (base, 0) == '*')
- goto unknown; /* Probably a local symbol, so record value */
- else if (offset == NULL)
- ;
- else if (GET_CODE (offset) == CONST_INT)
- ;
- else
- goto unknown;
- }
- else if (REG_P (base))
- {
- if (offset == NULL)
- ;
- else if (GET_CODE (offset) == CONST_INT)
- ;
- else if (REG_P (offset))
- ;
- else
- goto unknown;
- }
- else if (GET_CODE (base) == CONST
- && GET_CODE (XEXP (base, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (base, 0), 0)) == SYMBOL_REF)
- {
- if (*XSTR (base, 0) == '*')
- goto unknown; /* Probably a local symbol, so record value */
- }
- else
- {
- unknown:
- issue_address_event (exp, base, offset);
- }
- }
-
-
- static void
- thunk_for_store_after (exp, base, offset)
- rtx exp, base, offset;
- {
- if (GET_CODE (base) == SYMBOL_REF)
- {
- char *symbol_name = XSTR (base, 0);
-
- if (*symbol_name == '*')
- goto unknown; /* Probably a local symbol, so record value */
- else if (offset == NULL)
- store_symbol_schema (symbol_name, 0);
- else if (GET_CODE (offset) == CONST_INT)
- store_symbol_schema (symbol_name, XINT (offset, 0));
- else
- goto unknown;
- }
- else if (REG_P (base))
- {
- if (offset == NULL)
- store_schema_int_offset (REGNO (base), 0, 0);
- else if (GET_CODE (offset) == CONST_INT)
- store_schema_int_offset (REGNO (base), XINT (offset, 0), 0);
- else if (REG_P (offset))
- store_schema_reg_offset (REGNO (base), offset, 0);
- else
- goto unknown;
- }
- else if (GET_CODE (base) == CONST
- && GET_CODE (XEXP (base, 0)) == PLUS
- && GET_CODE (XEXP (XEXP (base, 0), 0)) == SYMBOL_REF)
- {
- char *symbol_name = XSTR (XEXP (XEXP (base, 0), 0), 0);
-
- if (*symbol_name == '*')
- goto unknown;
- else
- store_symbol_schema (symbol_name, XINT (XEXP (XEXP (base, 0), 1), 0));
- }
- else
- {
- unknown:
- store_unknown_schema ();
- }
- }
-
-
- static void
- flush_uneventful_insn (num_current)
- int num_current;
- {
- if (num_uneventful_insn - num_current > 0)
- uneventful_schema (num_uneventful_insn - num_current, STD_ASM_INSN_LENGTH);
- num_uneventful_insn = 0;
- }
-
-
-
- /* Issue a schema by writing to the schema file. */
-
-
- static void
- function_start_schema (fun_name, n_blocks)
- char *fun_name;
- int n_blocks;
- {
- fprintf (schema_out_file, "%s ", FUNCTION_START);
- assemble_name (schema_out_file, fun_name);
- fprintf (schema_out_file, " %d\n", n_blocks);
- }
-
-
- static void
- function_end_schema (fun_name)
- char *fun_name;
- {
- fprintf (schema_out_file, "%s ", FUNCTION_END);
- assemble_name (schema_out_file, fun_name);
- fprintf (schema_out_file, "\n\n");
- }
-
-
- static void
- block_start_schema (block_no, target_p)
- int block_no, target_p;
- {
- fprintf (schema_out_file, "\n%s %d\n",
- (target_p ? BLOCK_START_TARGET : BLOCK_START), block_no);
- }
-
-
- static void
- block_end_schema (insn, block_no, next_target_p)
- rtx insn;
- int block_no, next_target_p;
- {
- fprintf (schema_out_file, "%s %d",
- (next_target_p ? BLOCK_END_NEXT_TARGET : BLOCK_END), block_no);
- edge_schema (insn);
- }
-
-
- static void
- block_end_jump_schema (insn, block_no, target_block_no, next_target_p)
- rtx insn;
- int block_no, target_block_no, next_target_p;
- {
- fprintf (schema_out_file, "%s %d %d",
- (next_target_p ? BLOCK_END_JUMP_NEXT_TARGET : BLOCK_END_JUMP),
- block_no, target_block_no);
- edge_schema (insn);
- }
-
-
- static void
- edge_schema (insn)
- rtx insn;
- {
- if (insn != NULL)
- {
- /* List exit before backedges */
- DOLIST (e, list, insn_info [INSN_UID (insn)].exit_edge,
- {fprintf (schema_out_file, " %s(%d %d)",
- LOOP_EXIT, CAR (e), CDR(e));
- free (e);});
- DOLIST (e, list, insn_info [INSN_UID (insn)].back_edge,
- {fprintf (schema_out_file, " %s(%d %d)",
- LOOP_BACK, CAR (e), CDR (e));
- free (e);});
- DOLIST (e, list, insn_info [INSN_UID (insn)].entry_edge,
- {fprintf (schema_out_file, " %s(%d %d)",
- LOOP_ENTRY, CAR (e), CDR (e));
- free (e);});
- }
- fprintf (schema_out_file, "\n");
- }
-
-
- static void
- block_end_cjump_schema (insn, block_no)
- rtx insn;
- int block_no;
- {
- fprintf (schema_out_file, "%s %d", BLOCK_END_CJUMP, block_no);
- if (condjump_p (insn))
- fprintf (schema_out_file, " %d %d", block_no + 1,
- head_to_block_number (JUMP_LABEL (insn)));
- else
- {
- rtx body = PATTERN (insn);
- register int vlen, i;
-
- vlen = XVECLEN (body, 0);
- for (i = 0; i < vlen; i++)
- fprintf (schema_out_file, " %d",
- head_to_block_number (XEXP (XVECEXP (body, 0, i), 0)));
- }
- edge_schema (insn);
- }
-
-
- static void
- simple_def_schema (rd, r1, value)
- int rd, r1, value;
- {
- fprintf (schema_out_file, "%s2 R%d #R%d + #I%d\n",
- COMPUTE_DEFN_, rd, r1, value);
- }
-
-
- static void
- compute_def_schema (rd, code, a1, a2)
- int rd;
- RTX_CODE code;
- rtx a1, a2;
- {
- if (code == NIL) /* Nullary */
- {
- fprintf (schema_out_file, "%s0 R%d ", COMPUTE_DEFN_, rd);
- rtx_arg_out (schema_out_file, a1);
- }
- else if (a2 == NULL) /* Unary */
- {
- fprintf (schema_out_file, "%s1 R%d %s ", COMPUTE_DEFN_, rd,
- rtx_op_out (code));
- rtx_arg_out (schema_out_file, a1);
- }
- else /* Binary */
- {
- fprintf (schema_out_file, "%s2 R%d ", COMPUTE_DEFN_, rd);
- rtx_arg_out (schema_out_file, a1);
- fprintf (schema_out_file, " %s ", rtx_op_out (code));
- rtx_arg_out (schema_out_file, a2);
- }
- fprintf (schema_out_file, "\n");
- }
-
-
- static void
- rtx_arg_out (file, a)
- FILE *file;
- rtx a;
- {
- switch (GET_CODE (a))
- {
- case REG:
- fprintf (file, "#R%d", REGNO (a));
- break;
- case SUBREG:
- rtx_arg_out (file, SUBREG_REG (a));
- break;
- case CONST_INT:
- fprintf (file, "#I%d", INTVAL (a));
- break;
- case SYMBOL_REF:
- fprintf (file, "#S");
- assemble_name (file, XEXP (a, 0));
- break;
- default: error ("Unknown object to output"); /*NOTREACHED*/
- }
- }
-
-
- char *
- rtx_op_out (code)
- RTX_CODE code;
- {
- switch (code)
- {
- case PLUS: return "+";
- case MINUS: return "-";
- case MULT: return "*";
- case DIV: return "/";
- case MOD: return "%";
- case AND: return "&";
- case IOR: return "|";
- case LSHIFT: return "<<";
- case ASHIFT: return "<<";
- case LSHIFTRT: return ">>";
- case NEG: return "-";
- case NOT: return "~";
- default: error ("Unknown operator to output"); /*NOTREACHED*/
- }
- }
-
-
- static void
- symbol_def_schema (rd, symbol, offset)
- int rd;
- char *symbol;
- int offset;
- {
- fprintf (schema_out_file, "%s2 R%d #I%d + #S", COMPUTE_DEFN_, rd, offset);
- assemble_name (schema_out_file, symbol);
- fprintf (schema_out_file, "\n");
- }
-
-
- static void
- unknown_def_schema (rd)
- int rd;
- {fprintf (schema_out_file, "%s R%d\n", UNKNOWN_DEFN, rd);}
-
-
- static void
- store_schema_int_offset (reg_no, offset, double_p)
- int reg_no, offset, double_p;
- {
- fprintf (schema_out_file, "%s #R%d + #I%d\n",
- (double_p ? STORE_D_INST : STORE_INST), reg_no, offset);
- }
-
-
- static void
- store_schema_reg_offset (reg_no, offset_reg, double_p)
- int reg_no;
- rtx offset_reg;
- int double_p;
- {
- fprintf (schema_out_file, "%s #R%d + #R%d\n",
- (double_p ? STORE_D_INST : STORE_INST), reg_no, REGNO (offset_reg));
- }
-
-
- static void
- store_symbol_schema (symbol, offset)
- char *symbol;
- int offset;
- {
- fprintf (schema_out_file, "%s #I%d + #S", STORE_INST, offset);
- assemble_name (schema_out_file, symbol);
- fprintf (schema_out_file, "\n");
- }
-
-
- static void
- store_unknown_schema ()
- {fprintf (schema_out_file, "%s\n", STORE_UNKNOWN_INST);}
-
-
- static void
- load_schema_int_offset (reg_no, offset, double_p)
- int reg_no, offset, double_p;
- {
- fprintf (schema_out_file, "%s #R%d + #I%d\n",
- (double_p ? LOAD_D_INST : LOAD_INST), reg_no, offset);
- }
-
- static void
- load_schema_reg_offset (reg_no, offset_reg, double_p)
- int reg_no;
- rtx offset_reg;
- int double_p;
- {
- fprintf (schema_out_file, "%s #R%d + #R%d\n",
- (double_p ? LOAD_D_INST : LOAD_INST), reg_no, REGNO (offset_reg));
- }
-
-
- static void
- load_symbol_schema (symbol, offset)
- char *symbol;
- int offset;
- {
- fprintf (schema_out_file, "%s #I%d + #S", LOAD_INST, offset);
- assemble_name (schema_out_file, symbol);
- fprintf (schema_out_file, "\n");
- }
-
-
- static void
- load_unknown_schema ()
- {fprintf (schema_out_file, "%s\n", LOAD_UNKNOWN_INST);}
-
-
- static void
- call_schema (callee)
- rtx callee;
- {call_schema_str (XSTR (callee, 0));}
-
-
- static void
- call_schema_str (callee)
- char *callee;
- {
- fprintf (schema_out_file, "%s ", CALL_INST);
- assemble_name (schema_out_file, callee);
- fprintf (schema_out_file, "\n");
- }
-
-
- static void
- call_indirect_schema (callee_reg)
- rtx callee_reg;
- {
- fprintf (schema_out_file, "%s R%d\n", CALL_INDIRECT_INST,
- REGNO (callee_reg));
- }
-
-
- static void
- uneventful_schema (num_insn, size_insn)
- int num_insn, size_insn;
- {
- fprintf (schema_out_file, "%s %d %d\n", UNEVENTFUL_INST,
- num_insn, size_insn);
- }
-
-
-
- /* The instruction sequence to store a full-word event in the AE
- buffer looks like:
-
- CMP RB, RL
- BLE OK ! Check if buffer is full
- CALL AE_FLUSH_BUFFER
- OK:
-
- ST VALUE, 0 + RB ! Store word.
- ADD RB, 4, RB ! Bump pointer
-
- RB is the register or variable containing a pointer to next free byte
- in AE buffer. RL can be a register or variable containing a pointer
- to end of this buffer - CHUNK_SIZE. Or, RL can be a constant value
- (e.g., first negative number minus a small offset) pointing to the end
- of this buffer.
-
- We cheat a bit and only perform the space check on the first event in
- a block. At this test, we check for enough memory for all events in
- the block. However, when we see the first event, we don't know how
- many more events will be in the block, so we check for a lot
- (CHUNK_SIZE) of space. If we overestimate the amount, it does not
- matter since RB rarely is near the end of the buffer.
-
- Also, on most machines, we cannot do a simple store of the value since
- the buffer contains: unsigned chars, unsigned shorts, and longs and
- hence is byte-aligned. */
-
-
- /* Produce the space check at the beginning of a block. */
-
- static void
- issue_event_space_check (comment, size)
- char *comment;
- int size;
- {
- char buffer[256];
-
- if (space_left_in_chunk > size)
- {
- sprintf (buffer, "\t\t\t%c %s Event", ASM_COMMENT_CHAR, comment);
- output_asm_insn (buffer, NULL);
- space_left_in_chunk -= size;
- return;
- }
- else
- {
- space_left_in_chunk = CHUNK_SIZE;
- GENERATE_SPACE_CHECK (comment, size);
- }
- }
-
-
- static void
- issue_event (value)
- rtx value;
- {
- issuing_event = 1;
- issue_event_space_check ("", 4);
- GENERATE_EVENT (value);
- issuing_event = 0;
- }
-
-
- static void
- issue_short_event (value, max_value)
- int value, max_value;
- {
- rtx xops [2];
- int bytes = (max_value < 256 ? 1 : 2);
-
- issuing_event = 1;
- issue_event_space_check ("Short", bytes);
- GENERATE_SHORT_EVENT (value, bytes);
- issuing_event = 0;
- }
-
-
- static void
- issue_address_event (address, base, offset)
- rtx address, base, offset;
- {
- issuing_event = 1;
- issue_event_space_check ("Address", 4);
- GENERATE_ADDRESS_EVENT(address, base, offset);
- issuing_event = 0;
- }
-