home *** CD-ROM | disk | FTP | other *** search
- Path: wuarchive!wugate!uunet!bbn.com!rsalz
- From: rsalz@uunet.uu.net (Rich Salz)
- Newsgroups: comp.sources.unix
- Subject: v20i082: "Cheap dynamic instruction counting"
- Message-ID: <2099@papaya.bbn.com>
- Date: 27 Oct 89 17:38:13 GMT
- Lines: 1688
- Approved: rsalz@uunet.UU.NET
-
- Submitted-by: Paul Haahr <haahr@princeton.edu>
- Posting-number: Volume 20, Issue 82
- Archive-name: lcomp
-
- [ This is a poor summary of Paul's excellent README; I'm not sure why
- I think it's so great, but I do. /r$ ]
-
- This package is based on Peter Weinberger's "Cheap Dynamic Instruction
- Counting" from the AT&T Bell Labs Tech Journal Unix(tm) issue of a
- few years ago (Vol 63, No 8, Oct 1984, pp 1815-1826). These programs
- were written for a class taught by David Hanson at Princeton University
- in Spring 1988. (Computer Science 596, Systems Programming Workshop)
-
- This code runs on Sun-3s (68020s) and Vaxen (4.3 bsd and ultrix). The
- files 68020.l and vax.l are lex programs that match the instructions in an
- assembly program. I did the 68020 port in about an hour. If people are
- interested, I will maintain a library of machine.l files.
-
- paul haahr
- princeton!haahr haahr@princeton.edu
-
- # to unbundle, sh this file
- # bundled by haahr on elliot at Sun May 8 14:48:31 EDT 1988
- echo README 1>&2
- sed 's/^-//' > README <<'end of README'
- -README for lcomp and lprint
- -cheap dynamic instruction counting
- -
- -This package is based on Peter Weinberger's "Cheap Dynamic Instruction
- -Counting" from the AT&T Bell Labs Tech Journal Unix(tm) issue of a
- -few years ago (Vol 63, No 8, Oct 1984, pp 1815-1826). These programs
- -were written for a class taught by David Hanson at Princeton University
- -in Spring 1988. (Computer Science 596, Systems Programming Workshop)
- -
- -This code runs on Sun-3s (68020s) and Vaxen (4.3 bsd and ultrix). Since it
- -works with the assembly language output of compilers, it needs to make
- -some assumptions. The files 68020.l and vax.l are lex programs that match
- -the instructions in an assembly program. For new machines, if the assembler
- -is a unix-like assembler and the compiler doesn't do too many strange things,
- -it should be possible to easily change one of the included .l files to work
- -if you look at the code a bit and know the relevant assembly language. If
- -people are interested, I will maintain a library of machine.l files.
- -
- -To get this working on a vax or a sun, edit the makefile to set TARGET
- -to 68020 or vax, and change BIN, LIB, and MAN and do a make install.
- -BIN, LIB, and MAN may not be the current directory. If you do not want
- -to install the programs, edit lcomp to change the LIB directory to the
- -current directory.
- -
- -See the enclosed manual page (and Weinberger's paper) for how to use
- -and interpret the results of these programs.
- -
- -The interesting thing about this package is the use of lex to drive the
- -instruction recognizer. I like this approach, and would defend it,
- -because i did my port to the sun 68020 compiler in less than an hour by
- -changing the patterns matched and the inserted assembly code (all in
- -the lex source). Only two small changes had to be made to the machine
- -independent code (bb.c) to support the sun, but this was just because
- -of a few vax-centrist assumptions I had made when writing the original code.
- -See the file INTERNALS for a description of how to write the driver for
- -a new machine.
- -
- -lcomp functions as either cc or f77. I have not found a case where it
- -breaks. Note that you must use -F when linking fortran .o files if
- -there are no .f files listed as arguments.
- -
- -lprint is modelled on the Ninth Edition manual page for Weinberger's code,
- -but I wrote it from memory and confused the meaning of all of his
- -options. Since my lprint and his have different functionality and I
- -thought my names made more sense for my program, I kept my version of
- -the option names.
- -
- -For a different approach to writing a package like this, see Sun's tcov,
- -which add profiling code to C source rather than compiler output.
- -
- -
- -This code is wholly within the public domain. It is not copy(right|left)ed
- -by anyone or any organization. Do with it what you wish.
- -
- -Paul Haahr
- -princeton!haahr (haahr@princeton.edu)
- end of README
- echo makefile 1>&2
- sed 's/^-//' > makefile <<'end of makefile'
- -CFLAGS = -O
- -LIBS = -ll
- -TARGET = vax
- -GENDEP = /lib/cpp -M # on ultrix, use /lib/cpp -Em
- -
- -SRC = README makefile INTERNALS lcomp.1 lcomp \
- - bbexit.c bbfile.c \
- - bb.h new.h bool.h \
- - bb.c lprint.c ealloc.c efopen.c \
- - vax.l 68020.l
- -
- -LPRINT = lprint.o ealloc.o efopen.o
- -BB = bb.o ealloc.o efopen.o $(TARGET).o
- -
- -HOME = /u/haahr
- -BIN = $(HOME)/bin
- -LIB = $(HOME)/lib/bb
- -MAN = $(HOME)/lib/man/man1
- -
- -# normal targets
- -
- -all : bb bbexit.o bbfile.o lprint
- -
- -bb : $(BB)
- - $(CC) $(CFLAGS) -o bb $(BB) $(LIBS)
- -
- -lprint : $(LPRINT)
- - $(CC) $(CFLAGS) -o lprint $(LPRINT)
- -
- -
- -# c code checking
- -
- -# using V8 cyntax
- -CYNTAX = cyntax
- -CYN = O
- -CYNLIB =
- -
- -# using sun system V lint
- -#CYNTAX = /usr/5bin/lint
- -#CYN = ln
- -#CYNLIB = -ll
- -
- -
- -CLPRINT = lprint.$(CYN) ealloc.$(CYN) efopen.$(CYN)
- -CBB = bb.$(CYN) ealloc.$(CYN) efopen.$(CYN) $(TARGET).$(CYN)
- -
- -.SUFFIXES: .$(CYN)
- -
- -.c.$(CYN):
- - -$(CYNTAX) $(CFLAGS) -c $*.c
- -
- -cyntax : Cbb Clprint bbexit.$(CYN) bbfile.$(CYN)
- -
- -Cbb : $(CBB)
- - -$(CYNTAX) $(CFLAGS) $(CBB) $(CYNLIB)
- -
- -Clprint : $(CLPRINT)
- - -$(CYNTAX) $(CFLAGS) $(CLPRINT)
- -
- -$(TARGET).$(CYN) : $(TARGET).l
- - lex $(LFLAGS) -t $(TARGET).l > $(TARGET).c
- - -$(CYNTAX) $(CFLAGS) -c $(TARGET).c
- - rm -f $(TARGET).c
- -
- -
- -# installation procedure
- -
- -install : bin lib man
- -bin : $(BIN)/lprint $(BIN)/lcomp
- -lib : $(LIB)/bb $(LIB)/bbexit.o $(LIB)/bbfile.o
- -man : $(MAN)/lcomp.1
- -
- -$(BIN)/lcomp : lcomp
- - sed 's+^LIB=.*$$+LIB='$(LIB)+ lcomp > $(BIN)/lcomp
- -
- -$(BIN)/lprint : lprint
- - cp lprint $(BIN)
- - strip $(BIN)/lprint
- -
- -$(LIB)/bb : bb
- - cp bb $(LIB)
- - strip $(LIB)/bb
- -
- -$(LIB)/bbexit.o : bbexit.o
- - cp bbexit.o $(LIB)
- -
- -$(LIB)/bbfile.o : bbfile.o
- - cp bbfile.o $(LIB)
- -
- -$(MAN)/lcomp.1 : lcomp.1
- - sed 's+\$$LIB+'$(LIB)+g lcomp.1 > $(MAN)/lcomp.1
- -
- -bundle : $(SRC)
- - @bundle $(SRC)
- -
- -wc :
- - @wc $(SRC)
- -
- -delta : $(SRC)
- - @echo "message for $?"
- - @cat > .cimsg
- - @ci -q -l -m"`cat .cimsg`" $?
- - @rm -f .cimsg
- - @touch delta
- -
- -clean :
- - rm -f a.out prof.out bb lprint lex.yy.c makefile.dep *.sL *.[Oos] *%
- -
- -depend :
- - sed '/^# --- cut here ---$$/q' makefile > makefile.dep
- - for i in *.[cly]; do $(GENDEP) $$i; done >> makefile.dep
- - mv makefile.dep makefile
- -
- -# --- cut here ---
- -68020.o: 68020.l
- -68020.o: /usr/include/stdio.h
- -68020.o: /usr/include/ctype.h
- -68020.o: /usr/include/string.h
- -68020.o: ./bool.h
- -68020.o: ./bb.h
- -bb.o: bb.c
- -bb.o: /usr/include/stdio.h
- -bb.o: /usr/include/ctype.h
- -bb.o: /usr/include/string.h
- -bb.o: ./new.h
- -bb.o: ./bool.h
- -bb.o: ./bb.h
- -bbexit.o: bbexit.c
- -bbexit.o: /usr/include/stdio.h
- -ealloc.o: ealloc.c
- -ealloc.o: /usr/include/stdio.h
- -ealloc.o: ./new.h
- -ealloc.o: /usr/include/string.h
- -efopen.o: efopen.c
- -efopen.o: /usr/include/stdio.h
- -lprint.o: lprint.c
- -lprint.o: /usr/include/stdio.h
- -lprint.o: /usr/include/string.h
- -lprint.o: ./bool.h
- -lprint.o: ./new.h
- -max.o: max.c
- -panic.o: panic.c
- -panic.o: /usr/include/stdio.h
- -vax.o: vax.l
- -vax.o: /usr/include/stdio.h
- -vax.o: /usr/include/ctype.h
- -vax.o: /usr/include/string.h
- -vax.o: ./bool.h
- -vax.o: ./bb.h
- end of makefile
- echo INTERNALS 1>&2
- sed 's/^-//' > INTERNALS <<'end of INTERNALS'
- -INTERNALS for lcomp
- -(or how to write a driver for a new instruction set)
- -
- -The driver for lcomp (actually, bb) is a lex program which matches the
- -instruction field of a compiler's assembly output. General machine
- -code for most architectures would be very hard to write basic block
- -counting code for, as many things that one wants to be able to find are
- -hard to identify (for example, can one tell the difference
- -between a normal label and the start of a functions). Therefore, the
- -driver for most machines will have to take advantage of the idiosyncratic
- -nature of compiler output.
- -
- -The included drivers both are based on the output from the Portable C
- -Compiler (PCC). 68020.l was written for the Sun 3; it has been tested
- -with SunOS 3.3 throught 3.5. vax.l is for Digital Vaxen; it has been
- -tested on BSD 4.3 and Ultrix 2.0. I have not tried using either with
- -(and assume they will break on) the output of the GNU C compiler, but I
- -am sure it would not take long to port from a PCC version to a GNU
- -version. It would be very difficult to port this code to work with a
- -compiler that directly generates object code with no provision for
- -creating assembler source. Sorry.
- -
- -My approach for writing a new driver is to start with one of the
- -existing drivers included in this package and modify it appropriately.
- -A good way to become familiar with one of these drivers is to examine
- -some compiler output for a vax or a sun and compare it with the output
- -of bb for that machine. Reasonable knowledge of the machine you are
- -working on and it's function call/return protocol is useful if not
- -necessary for porting the driver.
- -
- -The driver reads one file (a .s file generated by the compiler) and
- -generates two (a .s file with block counting code and a .sL file which
- -maps basic blocks to line numbers). The generated code, when executed,
- -appends to a file called prof.out which contains a counter for each
- -basic block. (The -r option to lcomp and lprint picks a name other
- -than prof.out. Using an absolute path name can be extremely useful for
- -profiling a program that is run from a public bin directory, so that
- -users don't get a prof.out file every time they run the program, and
- -the developer of the program can get useful profiling data.)
- -
- -The prof.out file is a series of entries of the form
- - <.sL file> <n>
- - <count for block 0>
- - <count for block 1>
- - .
- - .
- - .
- - <count for block n-1>
- -One such entry is written for each file compiled with lcomp.
- -
- -A .sL file has two parts. The first part is a set of n (obtained from
- -prof.out) lines, one per basic block, each with four whitespace
- -separated records, containing the sourcefile name (these should all be
- -the same in any one .sL if one does not make too creative use of the C
- -preprocessor), first line of the basic block, last line of the block,
- -and number of instructions in the block. This section is followed by a
- -line of the form "<m> functions", followed by m lines, one for each
- -function in the compilation unit (source file). Each function line is
- -the name of the function and its first basic block.
- -
- -The .l file must match instructions and generate code to do the
- -instruction counting (and link a file's count table with the routine that
- -prints counts), and write a .sL file. Start with the vax or 68020 code
- -and modify it appropriately. The following functions are predefined
- -(in bb.c) to handle common cases:
- -
- - passline() -- pass a line through unchanged
- - inst() -- a normal instruction that does not use
- - the condition codes and does alter them
- - safe() -- an instruction that uses the condition codes
- - or does not change them
- - branch() -- a jump or branch (conditional or unconditional)
- - unconditional subroutine call does not go here
- - stabd() -- handle unix .stabd or .stabn lines
- - stabs() -- handle unix .stabs lines
- - function(s, n) -- declare that function named s starts at block n
- - functionmap() -- write the function map for the end of the .sL file
- -
- -stabd() and stabs() read the .stab directives put out by the compiler for
- -debugger information. They should work with both dbx and sdb style compiler
- -output.
- -
- -The following functions must be provided by the driver:
- -
- - labelstartsblock(label) -- return a non-zero value if the named label
- - could be the target of a branch. if there
- - is a systematic way of telling that a label
- - only exists for a debugger, this function
- - should return false (zero) in that case.
- - this feature is used in the sun version
- - increment() -- increment a basic block counter. output
- - at the beginning of a basic block.
- - safeincrement() -- same as increment(), but does not change condition
- - codes. this is normally possible on most machines,
- - but can require tricky code.
- - epilogue() -- takes one argument, the name of a map file,
- - which must be linked with count information into
- - the counting table. see bbexit.c. the structures
- - are normally defined here.
- -
- -
- -There's more to it than what I have described here, but the best way to
- -figure it out is to try to write a driver for some machine. I'll be
- -glad to answer questions on how to write a driver. I will also be
- -willing to keep an archive of drivers that other people have written
- -for other machines, if there is interest.
- -
- -paul haahr
- -princeton!haahr haahr@princeton.edu
- end of INTERNALS
- echo lcomp.1 1>&2
- sed 's/^-//' > lcomp.1 <<'end of lcomp.1'
- -.TH LCOMP 1 "15 April 1988"
- -.SH NAME
- -lcomp, lprint \- statement and instruction counting
- -.SH SYNOPSIS
- -.B lcomp
- -[
- -.B \-r
- -.I prof.out
- -file
- -]
- -[
- -.B \-FC
- -]
- -.I cc
- -or
- -.I f77
- -arguments ...
- -.PP
- -.B lprint
- -[
- -.B \-blaipfc
- -]
- -[
- -.B \-r
- -.I prof.out
- -file
- -] [ srcfile ] ...
- -.SH DESCRIPTION
- -.LP
- -.I Lcomp
- -compiles a C or \s-2FORTRAN\s0 program into an executable that produces
- -instruction counts. \fILcomp\fP behaves similarly to
- -.I cc
- -and \fIf77\fP,
- -and accepts the same arguments and options as those programs, except that:
- -.TP
- -.B \-C
- -All named .c files are C++ programs and should be compiled with
- -.I CC
- -instead of
- -.I cc .
- -.TP
- -.B \-F
- -Link with \s-2FORTRAN\s0 libraries. Implied if a named .f file is included,
- -but necessary if only object files are listed.
- -.TP
- -.BI \-r " file"
- -Generate code that puts the output in the named file, rather than
- -\fIprof.out\fP.
- -.LP
- -For each .c or .f file named, a .sL file is created, which maps
- -basic blocks to line numbers. The source is compiled into a .o
- -file which is instrumented for counting basic blocks.
- -.LP
- -In the executable file, the function \fI_bbdump\fP(), which is called
- -automatically be \fIexit\fP(), writes the
- -.I prof.out
- -file. \fI_bbdump\fP() clears it's data structures, so it is safe to
- -call from a signal handler (as long as it is safe to I/O from a signal
- -handler on your machine). This is useful for gethering statistics on
- -a program that is not supposed to exit.
- -.LP
- -.I Lprint
- -analyzes the results of executing a program compiled with
- -.I lcomp .
- -The default behavior is to print an execution count in the left margin
- -of each named file for the first basic block on that line.
- -If no files are listed on the command line,
- -all that were executed are printed.
- -.SH OPTIONS
- -.TP
- -.B \-b
- -Print counts for basic blocks (default, unless one of
- -.B \-ipf
- -is selected).
- -.TP
- -.B \-l
- -Print counts for all lines, not just the first line of each basic block.
- -.TP
- -.B \-a
- -Print all basic blocks, not just the first one from a line.
- -.TP
- -.B \-i
- -Print instruction counts. If a basic block is not executed, the
- -number of instructions in that block is printed in parentheses.
- -.TP
- -.B \-f
- -Summarize by file. For instructions and basic blocks, the number executed,
- -the total number in the file, and the number not executed are printed.
- -.TP
- -.B \-p
- -Summarize by function. As \fB-f\fP, but the number of times each
- -function is called is also printed.
- -.TP
- -.B \-c
- -Compresses the
- -.I prof.out
- -file. The file grows every time the profile program is executed.
- -.TP
- -.BI \-r " file"
- -Read counting data from the named file, instead of \fIprof.out\fP.
- -.SH "EXAMPLES"
- -.ta 2.0i
- -.nf
- -$ lcomp file.c # compile with counting code
- -$ a.out # generate instruction counts
- -$ lprint file.c # print statement counts for file.c
- -.PP
- -$ lcomp -o prog *.f # compile all fortran programs in directory
- -$ prog ... # generate instruction counts
- -$ lprint -fp # print summary information for all files
- -.PP
- -$ make "CC=lcomp" # tell make to use count generating compiler
- -.fi
- -.SH "SEE ALSO"
- -cc(1), f77(1), prof(1), gprof(1), exit(2)
- -.br
- -tcov(1) in SunOS
- -.PP
- -Peter J. Weinberger, ``Cheap Dynamic Instruction Counting,''
- -in \fIAT&T Bell Laboratories Technical Journal\fP,
- -Volume 63, No. 8, October 1984.
- -.SH FILES
- -.PD 0
- -.TP 1.5i
- -.I file .sL
- -mapping from basic blocks to lines and functions
- -.TP
- -.I prof.out
- -default output file for counts
- -.TP
- -$LIB/bb
- -assembly language post-processor to insert statement counts
- -.TP
- -$LIB/bbexit.o
- -exit routine for statement counting
- -.TP
- -$LIB/bbfile.o
- -contains name of file to dump to, normally
- -.I prof.out
- -.PD
- -.SH BUGS
- -.LP
- -The analyzed program must call
- -.I exit (2),
- -either explictly or implictly by returning from
- -\fImain\fP() for the coverage information to be written to the
- -.I prof.out
- -file.
- -.LP
- -The order that \fIlprint\fP prints files in if no names are
- -mentioned on the command line is determinate but not too useful.
- -.LP
- -Profiling the kernel is possible, but some code must be written
- -to grab the data out of kernel memory,
- -rather than using \fI_bbdump\fP().
- end of lcomp.1
- echo lcomp 1>&2
- sed 's/^-//' > lcomp <<'end of lcomp'
- -#! /bin/sh
- -
- -LIB=$HOME/cs/596/lcomp
- -PATH=$LIB:$PATH
- -export PATH
- -CC=cc
- -
- -CFILES=
- -FFILES=
- -SFILES=
- -OFILES=
- -RMFILES=
- -
- -LIBS=
- -FLIBS=
- -PROF=prof.out
- -LINK=true
- -EXEC=a.out
- -FFLAGS='-u _MAIN_'
- -FORTRAN='-lF77 -lI77 -lU77 -lm'
- -
- -while [ $# != 0 ]
- -do
- - case "$1" in
- - *.c) CFILES="$CFILES $1" ;;
- - *.[fF]) FFILES="$FFILES $1" ; FLIBS="$FORTRAN" ;;
- - *.[sS]) SFILES="$SFILES $1" ;;
- - *.o) OFILES="$OFILES $1" ;;
- - -r) shift ; PROF=$1 ;;
- - -C) CC=CC ;;
- - -F) FLIBS="$FORTRAN" ;;
- - -O) ;;
- - -c) LINK=false ;;
- - -o) shift ; EXEC=$1 ;;
- - -l*|*.a)LIBS="$LIBS $1" ;;
- - -*) FLAGS="$FLAGS $1" ;;
- - esac
- - shift
- -done
- -
- -for i in $CFILES
- -do
- - file=`echo $i | sed 's/\.c$//'`
- - $CC -g -S $FLAGS $file.c || exit $?
- - bb $file.s || exit $?
- - SFILES="$SFILES $file.s"
- - RMFILES="$RMFILES $file.s"
- -done
- -
- -for i in $FFILES
- -do
- - file=`echo $i | sed 's/\.[fF]$//'`
- - f77 -g -S $FLAGS $i || exit $?
- - bb $file.s || exit $?
- - SFILES="$SFILES $file.s"
- - RMFILES="$RMFILES $file.s"
- -done
- -
- -for i in $SFILES
- -do
- - file=`echo $i | sed 's/\.[sS]$//'`
- - $CC -c $FLAGS $i || exit $?
- - OFILES="$OFILES $file.o"
- -done
- -
- -if $LINK
- -then
- - if [ "$PROF" = prof.out ]
- - then
- - OFILES="$OFILES $LIB/bbfile.o"
- - else
- - echo "char *_bbfile = \"$PROF\";" > $$bbfile.c
- - $CC -c $$bbfile.c
- - OFILES="$OFILES $$bbfile.o"
- - RMFILES="$RMFILES $$bbfile.c $$bbfile.o"
- - fi
- -
- - if [ "$FLIBS" != "" ]
- - then
- - FLAGS="$FLAGS $FFLAGS"
- - fi
- - $CC -o $EXEC $FLAGS $OFILES $LIB/bbexit.o $LIBS $FLIBS || exit $?
- -fi
- -rm -f $RMFILES
- end of lcomp
- chmod +x lcomp
- echo bbexit.c 1>&2
- sed 's/^-//' > bbexit.c <<'end of bbexit.c'
- -/* bbexit.c -- exit routine for basic block counting */
- -
- -#include <stdio.h>
- -
- -typedef struct Entry Entry;
- -struct Entry {
- - Entry *next;
- - int len, *counts;
- - char *mapfile;
- -};
- -
- -Entry *_bblist = NULL;
- -extern char *_bbfile;
- -
- -extern char *malloc();
- -
- -_bbdump()
- -{
- - Entry *e;
- - FILE *fp = fopen(_bbfile, "a");
- - if (fp == NULL) {
- - fprintf(stderr, "couldn't open %s\n", _bbfile);
- - return;
- - }
- - for (e = _bblist; e != NULL; e = e->next) {
- - int i;
- - fprintf(fp, "%s %d\n", e->mapfile, e->len);
- - for (i = 0; i < e->len; i++) {
- - fprintf(fp, "%d\n", e->counts[i]);
- - e->counts[i] = 0;
- - }
- - }
- - fclose(fp);
- -}
- -
- -exit(status)
- - int status;
- -{
- - _bbdump();
- - _cleanup();
- - _exit(status);
- -}
- end of bbexit.c
- echo bbfile.c 1>&2
- sed 's/^-//' > bbfile.c <<'end of bbfile.c'
- -char *_bbfile = "prof.out";
- end of bbfile.c
- echo bb.h 1>&2
- sed 's/^-//' > bb.h <<'end of bb.h'
- -/* bb.h -- basic block counting definitions */
- -
- -#define WORDSIZE 256
- -#define NOPRINT -1000
- -
- -#define streq(s, t) (strcmp((s), (t)) == 0)
- -#define atoi(s) strtol((s), (char *) NULL, 0)
- -
- -
- -extern FILE *out; /* generated .s file */
- -extern FILE *map; /* generated .sL file */
- -
- -extern int lineno; /* original source line number */
- -extern char filename[]; /* original source filename */
- -
- -extern char *yystring; /* input to lex */
- -extern char *tail; /* tail of line (everything after opcode) */
- -extern char line[]; /* input line */
- -extern char label[]; /* most recent label */
- -
- -extern bool text; /* in text segment? */
- -extern bool newblock; /* started new basic block? */
- -extern int block; /* current basic block number */
- -extern int instructions; /* counter of instructions */
- -extern int reached; /* last line reached in basic block */
- -
- -
- -extern void inst(); /* normal instruction */
- -extern void safe(); /* instruction that uses condition codes */
- -extern void branch(); /* any flow of control */
- -extern void stabd(), stabs(); /* debugger symbol table */
- -extern void passline(); /* no-op */
- -
- -
- -extern bool labelstartsblock(); /* supplied in $TARGET.l */
- -
- -
- -#ifdef YYLERR /* lex */
- -
- -#undef output
- -#undef input
- -#undef unput
- -
- -#define input() (*yystring == '\0' ? 0 : *yystring++)
- -#define unput(c) (*--yystring = (c))
- -#define output(c) (c) /* force evaluation */
- -
- -#endif
- end of bb.h
- echo new.h 1>&2
- sed 's/^-//' > new.h <<'end of new.h'
- -/* new.h -- dynamic memory allocation */
- -
- -extern char *malloc(), *ealloc(), *realloc(), *erealloc(), *strdup();
- -extern int free();
- -extern void panic();
- -
- -#ifndef NULL
- -#define NULL 0
- -#endif
- -
- -#define new(t, n) ((t *) ealloc((n) * sizeof (t)))
- -#define renew(t, p, n) (((p) == NULL) \
- - ? new(t, n) \
- - : ((t *) erealloc((char *) (p), (n) * sizeof (t))))
- -#define delete(p) (((p) == NULL) ? 0 : free(p))
- end of new.h
- echo bool.h 1>&2
- sed 's/^-//' > bool.h <<'end of bool.h'
- -/* bool.h -- boolean type */
- -
- -typedef int bool;
- -#define FALSE 0
- -#define TRUE 1
- -
- -#define strbool(t) ((t) ? "TRUE" : "FALSE")
- end of bool.h
- echo bb.c 1>&2
- sed 's/^-//' > bb.c <<'end of bb.c'
- -/* bb.c -- insert basic block counting code */
- -
- -#include <stdio.h>
- -#include <ctype.h>
- -#include <string.h>
- -#include "new.h"
- -#include "bool.h"
- -#include "bb.h"
- -
- -extern FILE *efopen();
- -extern char *memcpy();
- -
- -char *progname = "bb";
- -
- -static void usage()
- -{
- - fprintf(stderr, "usage: %s file.s ...\n", progname);
- - exit(1);
- -}
- -
- -
- -/* globals shared with $TARGET.l */
- -
- -FILE *out = NULL; /* generated .s file */
- -FILE *map = NULL; /* generated .sL file */
- -
- -int lineno = 0; /* original source line number */
- -char filename[WORDSIZE]; /* original source filename */
- -
- -char *yystring; /* input to lex */
- -char *tail; /* tail of line (everything after opcode) */
- -char line[BUFSIZ]; /* input line */
- -char label[WORDSIZE]; /* most recent label */
- -
- -bool text = TRUE; /* in text segment? */
- -bool newblock = TRUE; /* started new basic block? */
- -int block = 0; /* current basic block number */
- -int instructions = NOPRINT; /* counter of instructions */
- -int reached = 0; /* last line reached in basic block */
- -
- -
- -/* associate functions with basic blocks*/
- -
- -#define MAXFUNC 1000
- -int nfunc;
- -struct {
- - char *name;
- - int bb;
- -} func[MAXFUNC];
- -
- -function(s, bb)
- - char *s;
- - int bb;
- -{
- - if (nfunc >= MAXFUNC)
- - panic("too many functions (>%d), on %s\n", MAXFUNC, s);
- - func[nfunc].name = strdup(s);
- - func[nfunc].bb = bb;
- - nfunc++;
- -}
- -
- -functionmap()
- -{
- - int i;
- - fprintf(map, "%d functions\n", nfunc);
- - for (i = 0; i < nfunc; i++) {
- - fprintf(map, "%s %d\n", func[i].name, func[i].bb);
- - free(func[i].name);
- - func[i].name = NULL;
- - }
- - nfunc = 0;
- -}
- -
- -
- -/* parse file, pass to yylex from $TARGET.l */
- -void bb(infile)
- - char *infile;
- -{
- - char outfile[BUFSIZ], mapfile[BUFSIZ];
- - static char pid[10] = "";
- - FILE *in;
- -
- - in = efopen(infile, "r");
- -
- - strcpy(mapfile, infile);
- - strcat(mapfile, "L");
- - map = efopen(mapfile, "w");
- -
- - if (pid[0] == '\0')
- - sprintf(pid, ".%d", getpid());
- - strcpy(outfile, infile);
- - strcat(outfile, pid);
- - out = efopen(outfile, "w");
- -
- - lineno = 0;
- - filename[0] = '\0';
- -
- - while (fgets(line, sizeof line, in) != NULL) {
- - char *s = line, opcode[WORDSIZE];
- - int i;
- -startofline:
- - for (; isspace(*s); s++)
- - ;
- - if (*s == '\0') {
- - fputs(line, out);
- - continue;
- - }
- - for (i = 0; isgraph(s[i]); i++)
- - if (s[i] == ':') {
- - if (text) {
- - memcpy(label, s, i);
- - label[i] = '\0';
- - if (labelstartsblock(label))
- - newblock = TRUE;
- - }
- - s += i + 1;
- - goto startofline;
- - }
- - tail = s + i;
- - memcpy(opcode, s, i);
- - opcode[i] = '\n';
- - opcode[i + 1] = '\0';
- - yystring = opcode;
- - yylex();
- - }
- -
- - epilogue(mapfile);
- - functionmap();
- -
- - fclose(in);
- - fclose(out);
- - fclose(map);
- - map = out = NULL;
- -
- - if (unlink(infile) == -1)
- - panic("couldn't unlink %s -- output in %s\n", infile, outfile);
- - if (rename(outfile, infile) == -1)
- - panic("couldn't rename %s to %s\n", outfile, infile);
- -}
- -
- -int main(argc, argv)
- - int argc;
- - char *argv[];
- -{
- - progname = argv[0];
- - if (argc == 1)
- - usage();
- - for (--argc, ++argv; argc != 0; --argc, ++argv)
- - bb(*argv);
- - return 0;
- -}
- -
- -/* functions for use in $TARGET.l -- common to most machines */
- -
- -void passline()
- -{
- - fputs(line, out);
- -}
- -
- -void inst()
- -{
- - if (text) {
- - if (newblock)
- - increment();
- - reached = lineno;
- - instructions++;
- - }
- - passline();
- -}
- -
- -void safe()
- -{
- - if (text) {
- - if (newblock)
- - safeincrement();
- - reached = lineno;
- - instructions++;
- - }
- - passline();
- -}
- -
- -void branch()
- -{
- - if (text) {
- - if (newblock)
- - safeincrement();
- - reached = lineno;
- - instructions++;
- - newblock = TRUE;
- - }
- - passline();
- -}
- -
- -#define STAB_LINE 0104 /* N_SLINE from <stab.h> */
- -#define STAB_FILE 0144 /* N_SO from <stab.h> */
- -
- -void stabd()
- -{
- - char *s;
- - passline();
- - if (atoi(tail) != STAB_LINE)
- - return;
- - if ((s = strchr(line, ',')) == NULL || (s = strchr(s + 1, ',')) == NULL)
- - panic("bad directive: .stabn%s", tail);
- - lineno = atoi(s + 1);
- -}
- -
- -void stabs()
- -{
- - char *s, *t;
- - int len;
- - passline();
- - if ((s = strchr(tail, ',')) == NULL)
- - panic("bad directive: .stabs%s", tail);
- - if (atoi(s + 1) != STAB_FILE)
- - return;
- - if ((s = strchr(tail, '"')) == NULL || (t = strchr(s + 1, '"')) == NULL)
- - panic("bad directive: .stabs%s", tail);
- - len = t - s - 1;
- - memcpy(filename, s + 1, len);
- - filename[len] = '\0';
- -}
- end of bb.c
- echo lprint.c 1>&2
- sed 's/^-//' > lprint.c <<'end of lprint.c'
- -/* lprint.c -- print out statement counts */
- -
- -#include <stdio.h>
- -#include <string.h>
- -#include "bool.h"
- -#include "new.h"
- -
- -#define streq(s, t) (strcmp((s), (t)) == 0)
- -
- -extern FILE *efopen();
- -
- -char *progname = "lprint";
- -
- -void usage()
- -{
- - fprintf(stderr, "usage: %s [-blaipf] [-c] [-r file] [file ...]\n", progname);
- - fprintf(stderr, " -b print basic block counts (default)\n");
- - fprintf(stderr, " -l print counts for all lines\n");
- - fprintf(stderr, " -a print all basic blocks\n");
- - fprintf(stderr, " -i print instruction counts\n");
- - fprintf(stderr, " -p print function summaries\n");
- - fprintf(stderr, " -f print file summaries\n");
- - fprintf(stderr, " -c compress prof.out file\n");
- - fprintf(stderr, " -r select alternate prof.out file\n");
- - exit(1);
- -}
- -
- -int flags = 0;
- -
- -#define BLOCKS 0x01
- -#define LINES 0x02
- -#define ALL 0x04
- -#define INST 0x08
- -#define FILESUM 0x10
- -#define FUNCSUM 0x20
- -
- -#define DEFAULT BLOCKS
- -
- -typedef struct Mapfile Mapfile;
- -typedef struct Mapblock Mapblock;
- -typedef struct Sourcefile Sourcefile;
- -typedef struct Block Block;
- -typedef struct Func Func;
- -
- -struct Mapfile {
- - char *name;
- - int n, nfunc;
- - struct Mapblock {
- - long count;
- - int inst;
- - Sourcefile *source;
- - } *block;
- - Mapfile *next;
- -};
- -
- -Mapfile *maplist = NULL;
- -
- -struct Block {
- - int line, last, inst;
- - long count;
- -};
- -
- -struct Sourcefile {
- - char *name;
- - int nblock, maxblock;
- - Block *block;
- - Sourcefile *next;
- -};
- -Sourcefile *sourcelist = NULL;
- -
- -struct Func {
- - char *name;
- - Mapfile *map;
- - int block;
- -};
- -
- -Func *functab = NULL;
- -int nfunc = 0, maxfunc = 0;
- -
- -void gather(fp)
- - FILE *fp;
- -{
- - int i, n;
- - char name[BUFSIZ];
- - while (fscanf(fp, "%s %d\n", name, &n) != EOF) {
- - Mapfile *p;
- - for (p = maplist; p != NULL; p = p->next)
- - if (streq(name, p->name)) {
- - if (n != p->n)
- - panic("prof.out: bad counts for %s: %d and %d\n",
- - name, p->n, n);
- - goto found;
- - }
- - p = new(Mapfile, 1);
- - p->next = maplist;
- - maplist = p;
- - p->name = strdup(name);
- - p->n = n;
- - p->block = new(struct Mapblock, n);
- - for (i = 0; i < n; i++)
- - p->block[i].count = 0;
- - found:
- - for (i = 0; i < n; i++) {
- - long count;
- - if (fscanf(fp, "%ld", &count) == EOF)
- - panic("prof.out: early EOF\n");
- - p->block[i].count += count;
- - }
- - }
- -}
- -
- -void writeprof(fp)
- - FILE *fp;
- -{
- - Mapfile *p;
- - for (p = maplist; p != NULL; p = p->next) {
- - int i;
- - fprintf(fp, "%s %d\n", p->name, p->n);
- - for (i = 0; i < p->n; i++)
- - fprintf(fp, "%ld\n", p->block[i].count);
- - }
- -}
- -
- -Sourcefile *install(name, line, last, inst, count, n)
- - char *name;
- - int line, last, inst, n;
- - long count;
- -{
- - int i;
- - static Sourcefile *p = NULL;
- - if (p != NULL && streq(name, p->name))
- - goto found;
- - for (p = sourcelist; p != NULL; p = p->next)
- - if (streq(name, p->name))
- - goto found;
- -
- - p = new(Sourcefile, 1);
- - p->name = strdup(name);
- - p->block = new(Block, n);
- - p->maxblock = n;
- - p->nblock = 0;
- - p->next = sourcelist;
- - sourcelist = p;
- -
- -found:
- - if (p->nblock >= p->maxblock) {
- - p->maxblock *= 4;
- - p->block = renew(Block, p->block, p->maxblock);
- - }
- -
- - /* insertion sort, but (in practice) very rarely executed */
- - for (i = p->nblock++; i > 0 && line < p->block[i - 1].line; i--)
- - p->block[i] = p->block[i - 1];
- -
- - p->block[i].line = line;
- - p->block[i].last = last;
- - p->block[i].inst = inst;
- - p->block[i].count = count;
- - return p;
- -}
- -
- -void correlate(map)
- - Mapfile *map;
- -{
- - int i;
- - FILE *fp = efopen(map->name, "r");
- - for (i = 0; i < map->n; i++) {
- - char filename[BUFSIZ];
- - int line, lastline;
- - if (fscanf(fp, "%s %d %d %d\n", filename,
- - &line, &lastline, &map->block[i].inst) != 4)
- - panic("%s, line %d: bad map entry\n", map->name, i + 1);
- - map->block[i].source = install(filename, line, lastline,
- - map->block[i].inst, map->block[i].count, map->n);
- - }
- - if (fscanf(fp, "%d functions\n", &map->nfunc) != 1)
- - panic("%s, line %d: bad function line\n", map->name, map->n);
- - while (nfunc + map->nfunc >= maxfunc) {
- - if (maxfunc == 0)
- - maxfunc = 200;
- - else
- - maxfunc *= 8;
- - functab = renew(Func, functab, maxfunc);
- - }
- - for (i = 0; i < map->nfunc; i++, nfunc++) {
- - char name[BUFSIZ];
- - int block;
- - if (fscanf(fp, "%s %d\n", name, &block) != 2)
- - panic("%s, line %d: bad function entry\n",
- - map->name, map->n + 1 + 1);
- - functab[nfunc].name = strdup(name);
- - functab[nfunc].map = map;
- - functab[nfunc].block = block;
- - }
- - fclose(fp);
- -}
- -
- -void printline(s, count, inst)
- - char *s;
- - long count;
- - int inst;
- -{
- - if (flags & BLOCKS)
- - printf("%10ld ", count);
- - if (flags & INST) {
- - if (count == 0) {
- - char buf[20];
- - sprintf(buf, "(%d)", inst);
- - printf("%11s ", buf);
- - } else
- - printf("%10ld ", count * inst);
- - }
- - printf("%s", s);
- -}
- -
- -void printsource(p)
- - Sourcefile *p;
- -{
- - int line = 0, last = 0, i = 0, inst = 0;
- - long count = 0;
- - char buf[BUFSIZ];
- - FILE *fp = efopen(p->name, "r");
- -
- - static int fill = 0;
- - static bool firsttime = TRUE;
- - if (firsttime) {
- - firsttime = FALSE;
- - if (flags & BLOCKS)
- - fill += 12;
- - if (flags & INST)
- - fill += 12;
- - } else
- - printf("\f");
- -
- - while (fgets(buf, sizeof buf, fp) != NULL) {
- - for (; i < p->nblock && line >= p->block[i].line; i++) {
- - if (flags & ALL)
- - printline("\n", p->block[i].count,
- - p->block[i].inst);
- - if (last <= p->block[i].last)
- - last = p->block[i].last;
- - }
- - line++;
- - if (i < p->nblock && line == p->block[i].line && last < line) {
- - count = p->block[i].count;
- - inst = p->block[i].inst;
- - last = p->block[i].last;
- - printline(buf, count, inst);
- - while (++i < p->nblock && line == p->block[i].line)
- - if (flags & ALL)
- - printline("\n", p->block[i].count,
- - p->block[i].inst);
- - } else if (flags & LINES)
- - printline(buf, count, inst);
- - else
- - printf("%*s%s", fill, "", buf);
- - }
- - fclose(fp);
- -}
- -
- -typedef struct Sum {
- - long calls, i, ie, ine, bb, bbe, bbne;
- -} Sum;
- -
- -void printsumline(name, sum, isfunc)
- - char *name;
- - Sum sum;
- - bool isfunc;
- -{
- - printf("%9ldbbe %4ldbb %4ldbbne ", sum.bbe, sum.bb, sum.bbne);
- - printf("%9ldie %4ldi %4ldine ", sum.ie, sum.i, sum.ine);
- - if (isfunc)
- - printf("%7ldcalls ", sum.calls);
- - else
- - printf("%13s", "");
- - printf(" %s\n", name);
- -}
- -
- -static Sum zerosum = { 0, 0, 0, 0, 0, 0, 0 };
- -
- -void printfunctionsummary(p)
- - Sourcefile *p;
- -{
- - Func *func;
- -
- - for (func = &functab[0]; func < &functab[nfunc]; func++)
- - if (func->map->block[func->block].source == p) {
- - Sum sum;
- - Mapblock *block = func->map->block;
- - int i, last;
- - sum = zerosum;
- - if (func < &functab[nfunc] && func->map == (func + 1)->map)
- - last = (func + 1)->block;
- - else
- - last = func->map->n;
- - sum.calls += block[func->block].count;
- - for (i = func->block; i < last; i++) {
- - Mapblock *b = &block[i];
- - sum.bb += 1;
- - sum.bbe += b->count;
- - sum.i += b->inst;
- - sum.ie += b->inst * b->count;
- - if (b->count == 0) {
- - sum.bbne += 1;
- - sum.ine += b->inst;
- - }
- - }
- - printsumline(func->name, sum, TRUE);
- - }
- -}
- -
- -void printfilesummary(p)
- - Sourcefile *p;
- -{
- - Sum sum;
- - Mapfile *map;
- - Mapblock *block;
- -
- - sum = zerosum;
- - for (map = maplist; map != NULL; map = map->next)
- - for (block = &map->block[0]; block < &map->block[map->n]; block++)
- - if (block->source == p) {
- - sum.bb += 1;
- - sum.bbe += block->count;
- - sum.i += block->inst;
- - sum.ie += block->inst * block->count;
- - if (block->count == 0) {
- - sum.bbne += 1;
- - sum.ine += block->inst;
- - }
- - }
- - printsumline(p->name, sum, FALSE);
- -}
- -
- -void analyze(name)
- - char *name;
- -{
- - Sourcefile *p;
- - for (p = sourcelist; p == NULL || !streq(p->name, name); p = p->next)
- - if (p == NULL) {
- - fprintf(stderr, "%s: not in prof.out\n", name);
- - return;
- - }
- -
- - if (flags & (INST|BLOCKS)) {
- - printsource(p);
- - if (flags & (FUNCSUM|FILESUM))
- - printf("\n\n\n\n");
- - }
- - if (flags & FUNCSUM) {
- - printfunctionsummary(p);
- - if (flags & FILESUM)
- - printf("\n");
- - }
- - if (flags & FILESUM) {
- - printfilesummary(p);
- - if ((flags & FUNCSUM) && (flags & (INST|BLOCKS)) == 0)
- - printf("\n\n");
- - }
- -}
- -
- -int main(argc, argv)
- - int argc;
- - char *argv[];
- -{
- - int c;
- - bool compact = FALSE;
- - char *prof = "prof.out";
- - Mapfile *map;
- -
- - extern int optind;
- - extern char *optarg;
- -
- - progname = argv[0];
- - while ((c = getopt(argc, argv, "blaipfcr:?")) != EOF)
- - switch(c) {
- - case 'b': flags |= BLOCKS; break;
- - case 'l': flags |= LINES; break;
- - case 'a': flags |= ALL; break;
- - case 'i': flags |= INST; break;
- - case 'p': flags |= FUNCSUM; break;
- - case 'f': flags |= FILESUM; break;
- - case 'c': compact = TRUE; break;
- - case 'r': prof = optarg; break;
- - case '?': usage();
- - }
- -
- - if (streq(prof, "-"))
- - gather(stdin);
- - else {
- - FILE *fp = efopen(prof, "r");
- - gather(fp);
- - fclose(fp);
- - }
- - if (compact) {
- - if (streq(prof, "-"))
- - writeprof(stdout);
- - else {
- - FILE *fp = efopen(prof, "w");
- - writeprof(fp);
- - fclose(fp);
- - }
- - if (optind == argc && flags == 0)
- - return 0;
- - }
- -
- - if (flags == 0)
- - flags = DEFAULT;
- - if ((flags & (ALL|LINES)) && (flags & (INST|BLOCKS)) == 0)
- - flags |= BLOCKS;
- -
- - for (map = maplist; map != NULL; map = map->next)
- - correlate(map);
- - if (optind == argc) {
- - Sourcefile *p;
- - for (p = sourcelist; p != NULL; p = p->next)
- - analyze(p->name);
- - } else
- - for (; optind < argc; optind++)
- - analyze(argv[optind]);
- - return 0;
- -}
- end of lprint.c
- echo ealloc.c 1>&2
- sed 's/^-//' > ealloc.c <<'end of ealloc.c'
- -/* ealloc.c -- error checking malloc */
- -
- -#include <stdio.h>
- -#include "new.h"
- -
- -extern char *progname;
- -
- -/* VARARGS1 */ /* PRINTFLIKE0 */
- -void panic(fmt, a, b, c, d, e, f, g, h)
- - char *fmt;
- -{
- - fprintf(stderr, "%s: ", progname);
- - fprintf(stderr, fmt, a, b, c, d, e, f, g, h);
- - exit(1);
- -}
- -
- -char *ealloc(n)
- - int n;
- -{
- - char *p = malloc(n);
- - if (p == NULL)
- - panic("malloc(%d) returned 0\n", n);
- - return p;
- -}
- -
- -char *erealloc(p, n)
- - char *p;
- - int n;
- -{
- - p = realloc(p, n);
- - if (p == NULL)
- - panic("realloc(%d) returned 0\n", n);
- - return p;
- -}
- -
- -#include <string.h>
- -
- -char *strdup(s)
- - char *s;
- -{
- - return strcpy(ealloc(strlen(s) + 1), s);
- -}
- end of ealloc.c
- echo efopen.c 1>&2
- sed 's/^-//' > efopen.c <<'end of efopen.c'
- -/* efopen.c -- open stdio file, check for errors */
- -
- -#include <stdio.h>
- -
- -extern char *progname;
- -
- -FILE *efopen(file, mode)
- - char *file, *mode;
- -{
- - FILE *fp = fopen(file, mode);
- - if (fp == NULL) {
- - fprintf(stderr, "%s: can't open file %s, mode %s\n",
- - progname, file, mode);
- - exit(1);
- - }
- - return fp;
- -}
- end of efopen.c
- echo vax.l 1>&2
- sed 's/^-//' > vax.l <<'end of vax.l'
- -/* vax.l -- basic block counting driver for vaxen */
- -
- -%{
- -
- -#include <stdio.h>
- -#include <ctype.h>
- -#include <string.h>
- -#include "bool.h"
- -#include "bb.h"
- -
- -extern void panic();
- -
- -bool newfunc = FALSE; /* started new function? */
- -
- -%}
- -
- -%%
- -
- -\.stab[dn]\n { stabd(); return; }
- -\.stabs\n { stabs(); return; }
- -\.word\n { word(); return; }
- -\.text\n { text = TRUE; passline(); return; }
- -\.data\n { text = FALSE; passline(); return; }
- -\..*\n { passline(); return; }
- -
- -nop\n { safe(); return; }
- -movpsl\n { safe(); return; }
- -adwc\n { safe(); return; }
- -
- -[as]ob.+\n { branch(); return; }
- -case[lwb]\n { branch(); return; }
- -
- -bi[sc]psw\n { safe(); return; }
- -bi.+\n { inst(); return; }
- -b.+\n { safe(); return; }
- -
- -jsb\n { inst(); return; }
- -jbr\n { jbr(); return; }
- -j.+\n { branch(); return; }
- -.+\n { inst(); return; }
- -\n { panic("null opcode"); }
- -
- -%%
- -
- -/* ARGSUSED */
- -bool labelstartsblock(s)
- - char *s;
- -{
- - return TRUE;
- -}
- -
- -increment()
- -{
- - if (instructions >= 0)
- - fprintf(map, "%d %d\n", reached, instructions);
- - instructions = 0;
- - fprintf(out, " incl bb+%d\n", 4 * block++);
- - fprintf(map, "%s %d ", filename, lineno);
- - newblock = FALSE;
- -}
- -
- -safeincrement()
- -{
- - fputs(" movpsl -(sp)\n", out);
- - increment();
- - fputs(" movw (sp)+, (sp)\n bicpsw $0xf\n bispsw (sp)+\n", out);
- -}
- -
- -jbr()
- -{
- - if (text && newfunc) {
- - funcprologue();
- - newfunc = FALSE;
- - increment();
- - instructions++;
- - reached = lineno;
- - newblock = TRUE;
- - passline();
- - } else
- - branch();
- -}
- -
- -funcprologue()
- -{
- - function(label, block);
- - fprintf(out, " tstl bb_init\n jneq bb_%s\n", label);
- - fprintf(out, " calls $0, bb_init_func\nbb_%s:\n", label);
- -}
- -
- -word()
- -{
- - if (text && newblock && label[0] == '_')
- - newfunc = TRUE;
- - passline();
- -}
- -
- -epilogue(mapfile)
- - char *mapfile;
- -{
- - if (instructions >= 0)
- - fprintf(map, "%d %d\n", reached, instructions);
- - if (text)
- - fprintf(out, " .data\n");
- - fprintf(out, " .lcomm bb, %d\n", 4 * block);
- - fprintf(out, "bb_mapfile:\n");
- - fprintf(out, " .asciz \"%s\"\n", mapfile);
- - fprintf(out, "bb_init:\n");
- - fprintf(out, " .long 0\n");
- - fprintf(out, "bb_entry:\n");
- - fprintf(out, " .long 0\n"); /* next */
- - fprintf(out, " .long %d\n", block); /* len */
- - fprintf(out, " .long bb\n"); /* count */
- - fprintf(out, " .long bb_mapfile\n"); /* mapfile */
- - fprintf(out, " .text\n");
- - fprintf(out, "bb_init_func:\n");
- - fprintf(out, " .word 0\n");
- - fprintf(out, " movl __bblist, bb_entry\n");
- - fprintf(out, " movl $bb_entry, __bblist\n");
- - fprintf(out, " incl bb_init\n");
- - fprintf(out, " ret\n");
- -}
- end of vax.l
- echo 68020.l 1>&2
- sed 's/^-//' > 68020.l <<'end of 68020.l'
- -/* 68020.l -- basic block counting driver for motorola 68020s */
- -
- -%{
- -
- -#include <stdio.h>
- -#include <ctype.h>
- -#include <string.h>
- -#include "bool.h"
- -#include "bb.h"
- -
- -extern void panic();
- -
- -%}
- -
- -%%
- -
- -\.stab[dn]\n { stabd(); return; }
- -\.stabs\n { stabs(); return; }
- -\.text\n { text = TRUE; passline(); return; }
- -\.data\n { text = FALSE; passline(); return; }
- -\..*\n { passline(); return; }
- -\|.+\n { passline(); return; }
- -
- -link\n { linkprologue(); return; }
- -
- -movem.+\n { safe(); return; }
- -trap\n { safe(); return; }
- -pea\n { safe(); return; }
- -nop\n { safe(); return; }
- -[ans]bcd\n { safe(); return; }
- -(add|neg|sub)x\n { safe(); return; }
- -un.+\n { safe(); return; }
- -pack\n { safe(); return; }
- -rox[lr]\n { safe(); return; }
- -
- -bchg\n { inst(); return; }
- -btst\n { inst(); return; }
- -bclr\n { inst(); return; }
- -bf.+\n { inst(); return; }
- -bs.+\n { inst(); return; }
- -b.+\n { branch(); return; }
- -
- -jbsr\n { inst(); return; }
- -jsr\n { inst(); return; }
- -j.+\n { branch(); }
- -
- -.+\n { inst(); return; }
- -\n { panic("null opcode"); }
- -
- -%%
- -
- -increment()
- -{
- - if (instructions >= 0)
- - fprintf(map, "%d %d\n", reached, instructions);
- - instructions = 0;
- - fprintf(out, " addql #1, bb+%d\n", 4 * block++);
- - fprintf(map, "%s %d ", filename, lineno);
- - newblock = FALSE;
- -}
- -
- -safeincrement()
- -{
- - fputs(" movw cc, sp@-\n", out);
- - increment();
- - fputs(" movw sp@+, cc\n", out);
- -}
- -
- -linkprologue()
- -{
- - if (text && label[0] == '_') {
- - funcprologue();
- - increment();
- - }
- - instructions++;
- - reached = lineno;
- - passline();
- -}
- -
- -funcprologue()
- -{
- - function(label, block);
- - fprintf(out, " tstl bb_init\n jne Lbb_%s\n", label);
- - fprintf(out, " jbsr bb_init_func\nLbb_%s:\n", label);
- -}
- -
- -bool labelstartsblock(s)
- - char *s;
- -{
- - if (s[0] == 'L' && s[1] == 'L') /* only used by stab */
- - return FALSE;
- - return TRUE;
- -}
- -
- -epilogue(mapfile)
- - char *mapfile;
- -{
- - if (instructions >= 0)
- - fprintf(map, "%d %d\n", reached, instructions);
- - if (text)
- - fprintf(out, " .data\n");
- - fprintf(out, " .even\n");
- - fprintf(out, " .lcomm bb, %d\n", 4 * block);
- - fprintf(out, "bb_init:\n");
- - fprintf(out, " .long 0\n");
- - fprintf(out, "bb_map:\n");
- - fprintf(out, " .asciz \"%s\"\n", mapfile);
- - fprintf(out, " .even\n");
- - fprintf(out, "bb_entry:\n");
- - fprintf(out, " .long 0\n"); /* next */
- - fprintf(out, " .long %d\n", block); /* len */
- - fprintf(out, " .long bb\n"); /* count */
- - fprintf(out, " .long bb_map\n"); /* mapfile */
- - fprintf(out, " .text\n");
- - fprintf(out, "bb_init_func:\n");
- - fprintf(out, " movl __bblist, sp@-\n");
- - fprintf(out, " movl sp@+, bb_entry\n");
- - fprintf(out, " movl #bb_entry, __bblist\n");
- - fprintf(out, " movl #1, bb_init\n");
- - fprintf(out, " rts\n");
- -}
- end of 68020.l
-
- --
- Please send comp.sources.unix-related mail to rsalz@uunet.uu.net.
- Use a domain-based address or give alternate paths, or you may lose out.
-