[comp.sources.unix] v20i082: "Cheap dynamic instruction counting"

rsalz@uunet.uu.net (Rich Salz) (10/28/89)

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.