Basic block profiling for 3b1 (cc or gcc)

Steve Wampler sbw at tapest.UUCP
Fri Nov 17 00:22:40 AEST 1989


What follows is a version of the recent 'lcomp' posting, modified
for unix-pc using cc and/or gcc.  See the README file for details.
Briefly, 'lcomp' does code profiling down to the basic block level
rather than the function call level.

Since I don't know unix-pc assembly, there are doubtless errors
and omissions in the file '3b1.l'.  If you improve it, would you
send the corrections to me so that I can keep the code stable?
When it is stable, I'll send the changes to the author of the
original version.  Thanks!

---- snip "lcomp.shar" ----
#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  3b1.l 68020.l INTERNALS Makefile README bb.c bb.h bbexit.c
#   bbfile.c bool.h ealloc.c efopen.c lcomp lcomp.1 lprint.c new.h
#   pi.c pi.out rename.c vax.l
# Wrapped by sbw at tapest on Wed Nov 15 16:09:59 1989
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f '3b1.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'3b1.l'\"
else
echo shar: Extracting \"'3b1.l'\" \(3815 characters\)
sed "s/^X//" >'3b1.l' <<'END_OF_FILE'
X/* 3b1.l -- basic block counting driver for ATT UNIX-PC's */
X
X%{
X
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include "bool.h"
X#include "bb.h"
X
Xextern void panic();
X
X%}
X
X%%
X
Xdef\n			{ do_def(); return; }
Xfile\n		        { setfilename(); return; }
Xln\n		        { setlineno(); return; }
Xtext\n			{ text = TRUE;  passline(); return; }
Xdata\n			{ text = FALSE; passline(); return; }
X\..*\n			{ passline(); return; }
X\|.+\n			{ passline(); return; }
X
Xlink\n			{ linkprologue(); return; }
Xlink.w\n		{ linkprologue(); return; /* for gcc */ }
X
Xmovm.+\n		{ safe(); return; }
Xtrap\n			{ safe(); return; }
Xpea\n			{ safe(); return; }
Xnop\n			{ safe(); return; }
X[ans]bcd\n		{ safe(); return; }
X(add|neg|sub)x\n	{ safe(); return; }
Xun.+\n			{ safe(); return; }
Xpack\n			{ safe(); return; }
Xrox[lr]\n		{ safe(); return; }
X
Xbchg\n			{ inst(); return; }
Xbtst\n			{ inst(); return; }
Xbclr\n			{ inst(); return; }
Xbf.+\n			{ inst(); return; }
Xbs.+\n			{ inst(); return; }
Xb.+\n			{ branch(); return; }
X
Xjbsr\n			{ inst(); return; }
Xjsr\n			{ inst(); return; }
Xj.+\n			{ branch(); }
X
X.+\n			{ inst(); return; }
X\n			{ panic("null opcode"); }
X
X%%
Xstatic int baseno = 1;
Xstatic int func_start = 0;
Xstatic char *func_label;
X
Xincrement()
X{
X	if (instructions >= 0)
X		fprintf(map, "%d %d\n", reached, instructions);
X	instructions = 0;
X	fprintf(out, "	add.l	&1, bb+%d\n", 4 * block++);
X	fprintf(map, "%s %d ", filename, lineno);
X	newblock = FALSE;
X}
X
Xsafeincrement()
X{
X	fputs("	mov.w	%cc,-(%sp)\n", out);
X	increment();
X	fputs("	mov.w	(%sp)+,%cc\n", out);
X}
X
Xlinkprologue()
X{
X 	char *strdup();
X
X        if (text) {
X		func_start = 1;
X		func_label = strdup(label);
X		}
X	passline();
X}
X
Xfuncprologue()
X{
X        static int newlab = 0;
X
X	function(func_label, block);
X        fprintf(out, "	tst.l	bb_init\n");
X        fprintf(out, "	bne	Lbb_%s\n",label);
X	fprintf(out, "	jsr	bb_init_func\nLbb_%s:\n", label);
X}
X
Xbool labelstartsblock(s)
X	char *s;
X{
X	if (s[0] == 'L' && s[1] == 'C' && s[2] == '%')	/* only used by gcc */
X		return FALSE;
X	return TRUE;
X}
X
Xepilogue(mapfile)
X	char *mapfile;
X{
X	if (instructions >= 0)
X		fprintf(map, "%d %d\n", reached, instructions);
X	if (text)
X		fprintf(out, "	data\n");
X	fprintf(out, "	even\n");
X	fprintf(out, "	lcomm	bb, %d\n", 4 * block);
X	fprintf(out, "bb_init:\n");
X	fprintf(out, "	long	0\n");
X	fprintf(out, "bb_map:\n");
X	fprintf(out, "	asciz	\"%s\"\n", mapfile);
X	fprintf(out, "	even\n");
X	fprintf(out, "bb_entry:\n");
X	fprintf(out, "	long	0\n");			/* next */
X	fprintf(out, "	long	%d\n", block);		/* len */
X	fprintf(out, "	long	bb\n");			/* count */
X	fprintf(out, "	long	bb_map\n");		/* mapfile */
X	fprintf(out, "	text\n");
X	fprintf(out, "bb_init_func:\n");
X	fprintf(out, "	mov.l	_bblist, -(%%sp)\n");
X	fprintf(out, "	mov.l	(%%sp)+, bb_entry\n");
X	fprintf(out, "	mov.l	&bb_entry, _bblist\n");
X	fprintf(out, "	mov.l	&1, bb_init\n");
X	fprintf(out, "	rts\n");
X}
X
Xdo_def()
X{
X        char *s;
X
X	passline();
X        if (strncmp(strtok(tail,"\t"),"~bf;",4) == 0) {
X	   inside_func = TRUE;
X           while (strncmp(strtok(NULL,"\t"),"line",4) != 0)
X              /* empty */ ;
X           if ((s = strtok(NULL,";\t")) != NULL)
X              lineno = baseno = atoi(s);
X           else
X              panic("bad def: %s\n",tail);
X           if (text && func_start) {
X	      funcprologue();
X	      increment();
X	      instructions++;
X	      reached = lineno;
X	      func_start = 0;
X              }
X           }
X	else if (strncmp(strtok(tail,"\t"),"~ef;",4) == 0)
X	   inside_func = FALSE;
X}
X
Xsetlineno()
X{
X	passline();
X        lineno = baseno + atoi(tail) - 1;
X}
X
Xsetfilename()
X{
X	char *s, *t;
X	int len;
X	passline();
X	if ((s = strchr(tail, '"')) == NULL || (t = strchr(s + 1, '"')) == NULL)
X		panic("bad directive: file\t%s", tail);
X	len = t - s - 1;
X	memcpy(filename, s + 1, len);
X	filename[len] = '\0';
X}
END_OF_FILE
if test 3815 -ne `wc -c <'3b1.l'`; then
    echo shar: \"'3b1.l'\" unpacked with wrong size!
fi
# end of '3b1.l'
fi
if test -f '68020.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'68020.l'\"
else
echo shar: Extracting \"'68020.l'\" \(2643 characters\)
sed "s/^X//" >'68020.l' <<'END_OF_FILE'
X/* 68020.l -- basic block counting driver for motorola 68020s */
X
X%{
X
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include "bool.h"
X#include "bb.h"
X
Xextern void panic();
X
X%}
X
X%%
X
X\.stab[dn]\n		{ stabd(); return; }
X\.stabs\n		{ stabs(); return; }
X\.text\n		{ text = TRUE;  passline(); return; }
X\.data\n		{ text = FALSE; passline(); return; }
X\..*\n			{ passline(); return; }
X\|.+\n			{ passline(); return; }
X
Xlink\n			{ linkprologue(); return; }
X
Xmovem.+\n		{ safe(); return; }
Xtrap\n			{ safe(); return; }
Xpea\n			{ safe(); return; }
Xnop\n			{ safe(); return; }
X[ans]bcd\n		{ safe(); return; }
X(add|neg|sub)x\n	{ safe(); return; }
Xun.+\n			{ safe(); return; }
Xpack\n			{ safe(); return; }
Xrox[lr]\n		{ safe(); return; }
X
Xbchg\n			{ inst(); return; }
Xbtst\n			{ inst(); return; }
Xbclr\n			{ inst(); return; }
Xbf.+\n			{ inst(); return; }
Xbs.+\n			{ inst(); return; }
Xb.+\n			{ branch(); return; }
X
Xjbsr\n			{ inst(); return; }
Xjsr\n			{ inst(); return; }
Xj.+\n			{ branch(); }
X
X.+\n			{ inst(); return; }
X\n			{ panic("null opcode"); }
X
X%%
X
Xincrement()
X{
X	if (instructions >= 0)
X		fprintf(map, "%d %d\n", reached, instructions);
X	instructions = 0;
X	fprintf(out, "	addql	#1, bb+%d\n", 4 * block++);
X	fprintf(map, "%s %d ", filename, lineno);
X	newblock = FALSE;
X}
X
Xsafeincrement()
X{
X	fputs("	movw	cc, sp at -\n", out);
X	increment();
X	fputs("	movw	sp at +, cc\n", out);
X}
X
Xlinkprologue()
X{
X	if (text && label[0] == '_') {
X		funcprologue();
X		increment();
X	}
X	instructions++;
X	reached = lineno;
X	passline();
X}
X
Xfuncprologue()
X{
X	function(label, block);
X	fprintf(out, "	tstl	bb_init\n	jne	Lbb_%s\n", label);
X	fprintf(out, "	jbsr	bb_init_func\nLbb_%s:\n", label);
X}
X
Xbool labelstartsblock(s)
X	char *s;
X{
X	if (s[0] == 'L' && s[1] == 'L')		/* only used by stab */
X		return FALSE;
X	return TRUE;
X}
X
Xepilogue(mapfile)
X	char *mapfile;
X{
X	if (instructions >= 0)
X		fprintf(map, "%d %d\n", reached, instructions);
X	if (text)
X		fprintf(out, "	.data\n");
X	fprintf(out, "	.even\n");
X	fprintf(out, "	.lcomm	bb, %d\n", 4 * block);
X	fprintf(out, "bb_init:\n");
X	fprintf(out, "	.long	0\n");
X	fprintf(out, "bb_map:\n");
X	fprintf(out, "	.asciz	\"%s\"\n", mapfile);
X	fprintf(out, "	.even\n");
X	fprintf(out, "bb_entry:\n");
X	fprintf(out, "	.long	0\n");			/* next */
X	fprintf(out, "	.long	%d\n", block);		/* len */
X	fprintf(out, "	.long	bb\n");			/* count */
X	fprintf(out, "	.long	bb_map\n");		/* mapfile */
X	fprintf(out, "	.text\n");
X	fprintf(out, "bb_init_func:\n");
X	fprintf(out, "	movl	__bblist, sp at -\n");
X	fprintf(out, "	movl	sp at +, bb_entry\n");
X	fprintf(out, "	movl	#bb_entry, __bblist\n");
X	fprintf(out, "	movl	#1, bb_init\n");
X	fprintf(out, "	rts\n");
X}
END_OF_FILE
if test 2643 -ne `wc -c <'68020.l'`; then
    echo shar: \"'68020.l'\" unpacked with wrong size!
fi
# end of '68020.l'
fi
if test -f 'INTERNALS' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'INTERNALS'\"
else
echo shar: Extracting \"'INTERNALS'\" \(5311 characters\)
sed "s/^X//" >'INTERNALS' <<'END_OF_FILE'
XINTERNALS for lcomp
X(or how to write a driver for a new instruction set)
X
XThe driver for lcomp (actually, bb) is a lex program which matches the
Xinstruction field of a compiler's assembly output.  General machine
Xcode for most architectures would be very hard to write basic block
Xcounting code for, as many things that one wants to be able to find are
Xhard to identify (for example, can one tell the difference
Xbetween a normal label and the start of a functions).  Therefore, the
Xdriver for most machines will have to take advantage of the idiosyncratic
Xnature of compiler output.
X
XThe included drivers both are based on the output from the Portable C
XCompiler (PCC).  68020.l was written for the Sun 3;  it has been tested
Xwith SunOS 3.3 throught 3.5.  vax.l is for Digital Vaxen;  it has been
Xtested on BSD 4.3 and Ultrix 2.0.  I have not tried using either with
X(and assume they will break on) the output of the GNU C compiler, but I
Xam sure it would not take long to port from a PCC version to a GNU
Xversion.  It would be very difficult to port this code to work with a
Xcompiler that directly generates object code with no provision for
Xcreating assembler source.  Sorry.
X
XMy approach for writing a new driver is to start with one of the
Xexisting drivers included in this package and modify it appropriately.
XA good way to become familiar with one of these drivers is to examine
Xsome compiler output for a vax or a sun and compare it with the output
Xof bb for that machine.  Reasonable knowledge of the machine you are
Xworking on and it's function call/return protocol is useful if not
Xnecessary for porting the driver.
X
XThe driver reads one file (a .s file generated by the compiler) and
Xgenerates two (a .s file with block counting code and a .sL file which
Xmaps basic blocks to line numbers).  The generated code, when executed,
Xappends to a file called prof.out which contains a counter for each
Xbasic block.  (The -r option to lcomp and lprint picks a name other
Xthan prof.out.  Using an absolute path name can be extremely useful for
Xprofiling a program that is run from a public bin directory, so that
Xusers don't get a prof.out file every time they run the program, and
Xthe developer of the program can get useful profiling data.)
X
XThe prof.out file is a series of entries of the form
X	<.sL file> <n>
X	<count for block 0>
X	<count for block 1>
X	.
X	.
X	.
X	<count for block n-1>
XOne such entry is written for each file compiled with lcomp.
X
XA .sL file has two parts.  The first part is a set of n (obtained from
Xprof.out) lines, one per basic block, each with four whitespace
Xseparated records, containing the sourcefile name (these should all be
Xthe same in any one .sL if one does not make too creative use of the C
Xpreprocessor), first line of the basic block, last line of the block,
Xand number of instructions in the block.  This section is followed by a
Xline of the form "<m> functions", followed by m lines, one for each
Xfunction in the compilation unit (source file).  Each function line is
Xthe name of the function and its first basic block.
X
XThe .l file must match instructions and generate code to do the
Xinstruction counting (and link a file's count table with the routine that
Xprints counts), and write a .sL file.  Start with the vax or 68020 code
Xand modify it appropriately.  The following functions are predefined
X(in bb.c) to handle common cases:
X
X	passline()	-- pass a line through unchanged
X	inst()		-- a normal instruction that does not use
X			   the condition codes and does alter them
X	safe()		-- an instruction that uses the condition codes
X			   or does not change them
X	branch()	-- a jump or branch (conditional or unconditional)
X			   unconditional subroutine call does not go here
X	stabd()		-- handle unix .stabd or .stabn lines
X	stabs()		-- handle unix .stabs lines
X	function(s, n)	-- declare that function named s starts at block n
X	functionmap()	-- write the function map for the end of the .sL file
X
Xstabd() and stabs() read the .stab directives put out by the compiler for
Xdebugger information.  They should work with both dbx and sdb style compiler
Xoutput.
X
XThe following functions must be provided by the driver:
X
X	labelstartsblock(label)	-- return a non-zero value if the named label
X				   could be the target of a branch.  if there
X				   is a systematic way of telling that a label
X				   only exists for a debugger, this function
X				   should return false (zero) in that case.
X				   this feature is used in the sun version
X	increment()	-- increment a basic block counter.  output
X			   at the beginning of a basic block.
X	safeincrement()	-- same as increment(), but does not change condition
X			   codes.  this is normally possible on most machines,
X			   but can require tricky code.
X	epilogue()	-- takes one argument, the name of a map file,
X			   which must be linked with count information into
X			   the counting table.  see bbexit.c.  the structures
X			   are normally defined here.
X
X
XThere's more to it than what I have described here, but the best way to
Xfigure it out is to try to write a driver for some machine.  I'll be
Xglad to answer questions on how to write a driver.  I will also be
Xwilling to keep an archive of drivers that other people have written
Xfor other machines, if there is interest.
X
Xpaul haahr
Xprinceton!haahr		haahr at princeton.edu
END_OF_FILE
if test 5311 -ne `wc -c <'INTERNALS'`; then
    echo shar: \"'INTERNALS'\" unpacked with wrong size!
fi
# end of 'INTERNALS'
fi
if test -f 'Makefile' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'Makefile'\"
else
echo shar: Extracting \"'Makefile'\" \(3050 characters\)
sed "s/^X//" >'Makefile' <<'END_OF_FILE'
XCFLAGS	= -O
XLIBS	= -ll
XTARGET	= 3b1
XCFLAGS  = -DNEED_IN		# Define this for 3b1, so gcc works...
X#GENDEP	= /lib/cpp -M		# on ultrix, use /lib/cpp -Em
XGENDEP	= /lib/cpp -Em		# on ultrix, use /lib/cpp -Em
X
XSRC	= README makefile INTERNALS lcomp.1 lcomp \
X	  bbexit.c bbfile.c \
X	  bb.h new.h bool.h \
X	  bb.c lprint.c ealloc.c efopen.c rename.c \
X	  vax.l 68020.l 3b1.l
X
XLPRINT	= lprint.o ealloc.o efopen.o
XBB	= bb.o ealloc.o efopen.o $(TARGET).o rename.o
X
XHOME	= /usr/local
XBIN	= $(HOME)/bin
XLIB	= $(HOME)/lib/bb
XMAN	= /usr/man/manl
X
X# normal targets
X
Xall	: bb bbexit.o bbfile.o lprint
X
Xbb	: $(BB)
X	$(CC) $(CFLAGS) -o bb $(BB) $(LIBS)
X
Xlprint	: $(LPRINT)
X	$(CC) $(CFLAGS) -o lprint $(LPRINT)
X
X
X# c code checking
X
X#	using V8 cyntax
XCYNTAX	= cyntax
XCYN	= O
XCYNLIB	=
X
X#	using sun system V lint
X#CYNTAX	= /usr/5bin/lint
X#CYN	= ln
X#CYNLIB	= -ll
X
X
XCLPRINT	= lprint.$(CYN) ealloc.$(CYN) efopen.$(CYN)
XCBB	= bb.$(CYN) ealloc.$(CYN) efopen.$(CYN) $(TARGET).$(CYN)
X
X.SUFFIXES:	.$(CYN)
X
X.c.$(CYN):
X	-$(CYNTAX) $(CFLAGS) -c $*.c
X
Xcyntax	: Cbb Clprint bbexit.$(CYN) bbfile.$(CYN)
X
XCbb	: $(CBB)
X	-$(CYNTAX) $(CFLAGS) $(CBB) $(CYNLIB)
X
XClprint	: $(CLPRINT)
X	-$(CYNTAX) $(CFLAGS) $(CLPRINT)
X
X$(TARGET).$(CYN) : $(TARGET).l
X	lex $(LFLAGS) -t $(TARGET).l > $(TARGET).c
X	-$(CYNTAX) $(CFLAGS) -c $(TARGET).c
X	rm -f $(TARGET).c
X
X
X# installation procedure
X
Xinstall		: bin lib
Xbin		: $(BIN)/lprint $(BIN)/lcomp 
Xlib		: $(LIB)/bb $(LIB)/bbexit.o $(LIB)/bbfile.o
X
X$(BIN)/lcomp	: lcomp
X		sed 's+^LIB=.*$$+LIB='$(LIB)+ lcomp > $(BIN)/lcomp
X
X$(BIN)/lprint	: lprint
X		cp lprint $(BIN)
X		strip $(BIN)/lprint
X
X$(LIB)/bb	: bb
X		cp bb $(LIB)
X	 	strip $(LIB)/bb
X
X$(LIB)/bbexit.o	: bbexit.o
X		cp bbexit.o $(LIB)
X
X$(LIB)/bbfile.o	: bbfile.o
X		cp bbfile.o $(LIB)
X
Xbundle	: $(SRC)
X	@bundle $(SRC)
X
Xwc	:
X	@wc $(SRC)
X
Xdelta	: $(SRC)
X	@echo "message for $?"
X	@cat > .cimsg
X	@ci -q -l -m"`cat .cimsg`" $?
X	@rm -f .cimsg
X	@touch delta
X
Xclean	:
X	rm -f a.out prof.out bb lprint lex.yy.c makefile.dep *.sL *.[Oos] *%
X
Xdepend	:
X	sed '/^# --- cut here ---$$/q' makefile > makefile.dep
X	for i in *.[cly]; do $(GENDEP) $$i; done >> makefile.dep
X	mv makefile.dep makefile
X
X# --- cut here ---
X3b1.o: 3b1.l
X3b1.o: /usr/include/stdio.h
X3b1.o: /usr/include/ctype.h
X3b1.o: /usr/include/string.h
X3b1.o: ./bool.h
X3b1.o: ./bb.h
X68020.o: 68020.l
X68020.o: /usr/include/stdio.h
X68020.o: /usr/include/ctype.h
X68020.o: /usr/include/string.h
X68020.o: ./bool.h
X68020.o: ./bb.h
Xbb.o: bb.c
Xbb.o: /usr/include/stdio.h
Xbb.o: /usr/include/ctype.h
Xbb.o: /usr/include/string.h
Xbb.o: ./new.h
Xbb.o: ./bool.h
Xbb.o: ./bb.h
Xbbexit.o: bbexit.c
Xbbexit.o: /usr/include/stdio.h
Xealloc.o: ealloc.c
Xealloc.o: /usr/include/stdio.h
Xealloc.o: ./new.h
Xealloc.o: /usr/include/string.h
Xefopen.o: efopen.c
Xefopen.o: /usr/include/stdio.h
Xlprint.o: lprint.c
Xlprint.o: /usr/include/stdio.h
Xlprint.o: /usr/include/string.h
Xlprint.o: ./bool.h
Xlprint.o: ./new.h
Xmax.o: max.c
Xpanic.o: panic.c
Xpanic.o: /usr/include/stdio.h
Xvax.o: vax.l
Xvax.o: /usr/include/stdio.h
Xvax.o: /usr/include/ctype.h
Xvax.o: /usr/include/string.h
Xvax.o: ./bool.h
Xvax.o: ./bb.h
END_OF_FILE
if test 3050 -ne `wc -c <'Makefile'`; then
    echo shar: \"'Makefile'\" unpacked with wrong size!
fi
# end of 'Makefile'
fi
if test -f 'README' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'README'\"
else
echo shar: Extracting \"'README'\" \(4114 characters\)
sed "s/^X//" >'README' <<'END_OF_FILE'
XREADME for lcomp and lprint
Xcheap dynamic instruction counting
X
X/* Note from sbw (11/14/89) - this particular version is modified
X *   to run on ATT UNIX-PC's as well as Sun-3 and Vaxen.  The
X *   current Makefile is configured for an ATT UNIX-PC.  The
X *   differences are the use of the TARGET file '3b1.l', some
X *   changes to 'bb.c' (and 'bb.h') to enable the use of this
X *   with gcc on a 3b1 (gcc puts string constants in the text area),
X *   and the addition of the code for 'rename()', which is missing
X *   on the 3B1.  The code for 'rename()' was pulled from the
X *   recently posted POSIX library.
X *
X *   Oh, I modified the script file 'lcomp' to take an optional
X *   argument '-gcc' to use 'gcc' in place of 'cc'.
X *
X *   I don't know 68010 (and, in particular, the 3b1's) assembly.
X *   The file '3b1.l' may contain some errors or omissions.
X *   Part of the reason I'm posting this so that someone more
X *   knowledgable than I can fix it.  I don't notice any problems,
X *   but what do I know?  My thanks to those who told me how to
X *   read/write the condition codes!
X *
X *   I've included a test program 'pi.c' and the resulting output
X *   from 'lprint pi.c' in case people would like to compare their
X *   changes with my version.  The file 'pi.out' shows the profiling
X *   of 'pi.c'.  Compile pi.c with 'lcomp pi.c -lm'.
X */
X
XThis package is based on Peter Weinberger's "Cheap Dynamic Instruction
XCounting" from the AT&T Bell Labs Tech Journal Unix(tm) issue of a
Xfew years ago (Vol 63, No 8, Oct 1984, pp 1815-1826).  These programs
Xwere written for a class taught by David Hanson at Princeton University
Xin Spring 1988.  (Computer Science 596, Systems Programming Workshop)
X
XThis code runs on Sun-3s (68020s) and Vaxen (4.3 bsd and ultrix).  Since it
Xworks with the assembly language output of compilers, it needs to make
Xsome assumptions.  The files 68020.l and vax.l are lex programs that match
Xthe instructions in an assembly program.  For new machines, if the assembler
Xis a unix-like assembler and the compiler doesn't do too many strange things,
Xit should be possible to easily change one of the included .l files to work
Xif you look at the code a bit and know the relevant assembly language.  If
Xpeople are interested, I will maintain a library of machine.l files.
X
XTo get this working on a vax or a sun, edit the makefile to set TARGET
Xto 68020 or vax, and  change BIN, LIB, and MAN and do a make install.
XBIN, LIB, and MAN may not be the current directory.  If you do not want
Xto install the programs, edit lcomp to change the LIB directory to the
Xcurrent directory.
X
XSee the enclosed manual page (and Weinberger's paper) for how to use
Xand interpret the results of these programs.
X
XThe interesting thing about this package is the use of lex to drive the
Xinstruction recognizer.  I like this approach, and would defend it,
Xbecause i did my port to the sun 68020 compiler in less than an hour by
Xchanging the patterns matched and the inserted assembly code (all in
Xthe lex source).  Only two small changes had to be made to the machine
Xindependent code (bb.c) to support the sun, but this was just because
Xof a few vax-centrist assumptions I had made when writing the original code.
XSee the file INTERNALS for a description of how to write the driver for
Xa new machine.
X
Xlcomp functions as either cc or f77.  I have not found a case where it
Xbreaks.  Note that you must use -F when linking fortran .o files if
Xthere are no .f files listed as arguments.
X
Xlprint is modelled on the Ninth Edition manual page for Weinberger's code,
Xbut I wrote it from memory and confused the meaning of all of his
Xoptions.  Since my lprint and his have different functionality and I
Xthought my names made more sense for my program, I kept my version of
Xthe option names.
X
XFor a different approach to writing a package like this, see Sun's tcov,
Xwhich add profiling code to C source rather than compiler output.
X
X
XThis code is wholly within the public domain.  It is not copy(right|left)ed
Xby anyone or any organization.  Do with it what you wish.
X
XPaul Haahr
Xprinceton!haahr (haahr at princeton.edu)
END_OF_FILE
if test 4114 -ne `wc -c <'README'`; then
    echo shar: \"'README'\" unpacked with wrong size!
fi
# end of 'README'
fi
if test -f 'bb.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bb.c'\"
else
echo shar: Extracting \"'bb.c'\" \(4246 characters\)
sed "s/^X//" >'bb.c' <<'END_OF_FILE'
X/* bb.c -- insert basic block counting code */
X
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include "new.h"
X#include "bool.h"
X#include "bb.h"
X
Xextern FILE *efopen();
Xextern char *memcpy();
X
Xchar *progname = "bb";
X
Xstatic void usage()
X{
X	fprintf(stderr, "usage: %s file.s ...\n", progname);
X	exit(1);
X}
X
X
X/* globals shared with $TARGET.l */
X
XFILE *out = NULL;		/* generated .s file */
XFILE *map = NULL;		/* generated .sL file */
X
Xint lineno = 0;			/* original source line number */
Xchar filename[WORDSIZE];	/* original source filename */
X
Xchar *yystring;			/* input to lex */
Xchar *tail;			/* tail of line (everything after opcode) */
Xchar line[BUFSIZ];		/* input line */
Xchar label[WORDSIZE];		/* most recent label */
X
Xbool text = TRUE;		/* in text segment? */
X#ifdef NEED_IN
Xint inside_func = FALSE;	/* MUST be set in TARGET.l file! */
X#endif
Xbool newblock = TRUE;		/* started new basic block? */
Xint block = 0;			/* current basic block number */
Xint instructions = NOPRINT;	/* counter of instructions */
Xint reached = 0;		/* last line reached in basic block */
X
X
X/* associate functions with basic blocks*/
X
X#define	MAXFUNC	1000
Xint nfunc;
Xstruct {
X	char *name;
X	int bb;
X} func[MAXFUNC];
X
Xfunction(s, bb)
X	char *s;
X	int bb;
X{
X	if (nfunc >= MAXFUNC)
X		panic("too many functions (>%d), on %s\n", MAXFUNC, s);
X	func[nfunc].name = strdup(s);
X	func[nfunc].bb = bb;
X	nfunc++;
X}
X
Xfunctionmap()
X{
X	int i;
X	fprintf(map, "%d functions\n", nfunc);
X	for (i = 0; i < nfunc; i++) {
X		fprintf(map, "%s %d\n", func[i].name, func[i].bb);
X		free(func[i].name);
X		func[i].name = NULL;
X	}
X	nfunc = 0;
X}
X
X
X/* parse file, pass to yylex from $TARGET.l */
Xvoid bb(infile)
X	char *infile;
X{
X	char outfile[BUFSIZ], mapfile[BUFSIZ];
X	static char pid[10] = "";
X	FILE *in;
X
X	in = efopen(infile, "r");
X
X	strcpy(mapfile, infile);
X	strcat(mapfile, "L");
X	map = efopen(mapfile, "w");
X
X	if (pid[0] == '\0')
X		sprintf(pid, ".%d", getpid());
X	strcpy(outfile, infile);
X	strcat(outfile, pid);
X	out = efopen(outfile, "w");
X
X	lineno = 0;
X	filename[0] = '\0';
X
X	while (fgets(line, sizeof line, in) != NULL) {
X		char *s = line, opcode[WORDSIZE];
X		int i;
Xstartofline:
X		for (; isspace(*s); s++)
X			;
X		if (*s == '\0') {
X			fputs(line, out);
X			continue;
X		}
X		for (i = 0; isgraph(s[i]); i++)
X			if (s[i] == ':') {
X				if (text) {
X					memcpy(label, s, i);
X					label[i] = '\0';
X					if (labelstartsblock(label))
X						newblock = TRUE;
X				}
X				s += i + 1;
X				goto startofline;
X			}
X		tail = s + i;
X		memcpy(opcode, s, i);
X		opcode[i] = '\n';
X		opcode[i + 1] = '\0';
X		yystring = opcode;
X		yylex();
X	}
X
X	epilogue(mapfile);
X	functionmap();
X
X	fclose(in);
X	fclose(out);
X	fclose(map);
X	map = out = NULL;
X
X	if (unlink(infile) == -1)
X		panic("couldn't unlink %s -- output in %s\n", infile, outfile);
X	if (rename(outfile, infile) == -1)
X		panic("couldn't rename %s to %s\n", outfile, infile);
X}
X
Xint main(argc, argv)
X	int argc;
X	char *argv[];
X{
X	progname = argv[0];
X	if (argc == 1)
X		usage();
X	for (--argc, ++argv; argc != 0; --argc, ++argv)
X		bb(*argv);
X	return 0;
X}
X
X/* functions for use in $TARGET.l -- common to most machines */
X
Xvoid passline()
X{
X	fputs(line, out);
X}
X
Xvoid inst()
X{
X	if (text && inside_func) {
X		if (newblock)
X			increment();
X		reached = lineno;
X		instructions++;
X	}
X	passline();
X}
X
Xvoid safe()
X{
X	if (text && inside_func) {
X		if (newblock)
X			safeincrement();
X		reached = lineno;
X		instructions++;
X	}
X	passline();
X}
X
Xvoid branch()
X{
X	if (text && inside_func) {
X		if (newblock)
X			safeincrement();
X		reached = lineno;
X		instructions++;
X		newblock = TRUE;
X	}
X	passline();
X}
X
X#define	STAB_LINE	0104	/* N_SLINE from <stab.h> */
X#define	STAB_FILE	0144	/* N_SO from <stab.h> */
X
Xvoid stabd()
X{
X	char *s;
X	passline();
X	if (atoi(tail) != STAB_LINE)
X		return;
X	if ((s = strchr(line, ',')) == NULL || (s = strchr(s + 1, ',')) == NULL)
X		panic("bad directive: .stabn%s", tail);
X	lineno = atoi(s + 1);
X}
X
Xvoid stabs()
X{
X	char *s, *t;
X	int len;
X	passline();
X	if ((s = strchr(tail, ',')) == NULL)
X		panic("bad directive: .stabs%s", tail);
X	if (atoi(s + 1) != STAB_FILE)
X		return;
X	if ((s = strchr(tail, '"')) == NULL || (t = strchr(s + 1, '"')) == NULL)
X		panic("bad directive: .stabs%s", tail);
X	len = t - s - 1;
X	memcpy(filename, s + 1, len);
X	filename[len] = '\0';
X}
END_OF_FILE
if test 4246 -ne `wc -c <'bb.c'`; then
    echo shar: \"'bb.c'\" unpacked with wrong size!
fi
# end of 'bb.c'
fi
if test -f 'bb.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bb.h'\"
else
echo shar: Extracting \"'bb.h'\" \(1529 characters\)
sed "s/^X//" >'bb.h' <<'END_OF_FILE'
X/* bb.h -- basic block counting definitions */
X
X#define WORDSIZE	256
X#define	NOPRINT		-1000
X
X#define streq(s, t)	(strcmp((s), (t)) == 0)
X#define	atoi(s)		strtol((s), (char *) NULL, 0)
X
X
Xextern	FILE *out;		/* generated .s file */
Xextern	FILE *map;		/* generated .sL file */
X
Xextern	int lineno;		/* original source line number */
Xextern	char filename[];	/* original source filename */
X
Xextern	char *yystring;		/* input to lex */
Xextern	char *tail;		/* tail of line (everything after opcode) */
Xextern	char line[];		/* input line */
Xextern	char label[];		/* most recent label */
X
Xextern	bool text;		/* in text segment? */
X#ifdef NEED_IN			/* Some targets need to know this... */
Xextern  int inside_func;	/* inside a function definition? */
X#else
X# define inside_func TRUE
X#endif
Xextern	bool newblock;		/* started new basic block? */
Xextern	int block;		/* current basic block number */
Xextern	int instructions;	/* counter of instructions */
Xextern	int reached;		/* last line reached in basic block */
X
X
Xextern	void inst();		/* normal instruction */
Xextern	void safe();		/* instruction that uses condition codes */
Xextern	void branch();		/* any flow of control */
Xextern	void stabd(), stabs();	/* debugger symbol table */
Xextern	void passline();	/* no-op */
X
X
Xextern	bool labelstartsblock();	/* supplied in $TARGET.l */
X
X
X#ifdef	YYLERR		/* lex */
X
X#undef	output
X#undef	input
X#undef	unput
X
X#define	input()		(*yystring == '\0' ? 0 : *yystring++)
X#define	unput(c)	(*--yystring = (c))
X#define	output(c)	(c)	/* force evaluation */
X
X#endif
END_OF_FILE
if test 1529 -ne `wc -c <'bb.h'`; then
    echo shar: \"'bb.h'\" unpacked with wrong size!
fi
# end of 'bb.h'
fi
if test -f 'bbexit.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bbexit.c'\"
else
echo shar: Extracting \"'bbexit.c'\" \(667 characters\)
sed "s/^X//" >'bbexit.c' <<'END_OF_FILE'
X/* bbexit.c -- exit routine for basic block counting */
X
X#include <stdio.h>
X
Xtypedef struct Entry Entry;
Xstruct Entry {
X	Entry	*next;
X	int	len, *counts;
X	char	*mapfile;
X};
X
XEntry *_bblist = NULL;
Xextern char *_bbfile;
X
Xextern char *malloc();
X
X_bbdump()
X{
X	Entry *e;
X	FILE *fp = fopen(_bbfile, "a");
X	if (fp == NULL) {
X		fprintf(stderr, "couldn't open %s\n", _bbfile);
X		return;
X	}
X	for (e = _bblist; e != NULL; e = e->next) {
X		int i;
X		fprintf(fp, "%s %d\n", e->mapfile, e->len);
X		for (i = 0; i < e->len; i++) {
X			fprintf(fp, "%d\n", e->counts[i]);
X			e->counts[i] = 0;
X		}
X	}
X	fclose(fp);
X}
X
Xexit(status)
X	int status;
X{
X	_bbdump();
X	_cleanup();
X	_exit(status);
X}
END_OF_FILE
if test 667 -ne `wc -c <'bbexit.c'`; then
    echo shar: \"'bbexit.c'\" unpacked with wrong size!
fi
# end of 'bbexit.c'
fi
if test -f 'bbfile.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bbfile.c'\"
else
echo shar: Extracting \"'bbfile.c'\" \(28 characters\)
sed "s/^X//" >'bbfile.c' <<'END_OF_FILE'
Xchar *_bbfile = "prof.out";
END_OF_FILE
if test 28 -ne `wc -c <'bbfile.c'`; then
    echo shar: \"'bbfile.c'\" unpacked with wrong size!
fi
# end of 'bbfile.c'
fi
if test -f 'bool.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'bool.h'\"
else
echo shar: Extracting \"'bool.h'\" \(124 characters\)
sed "s/^X//" >'bool.h' <<'END_OF_FILE'
X/* bool.h -- boolean type */
X
Xtypedef int bool;
X#define	FALSE	0
X#define	TRUE	1
X
X#define	strbool(t)	((t) ? "TRUE" : "FALSE")
END_OF_FILE
if test 124 -ne `wc -c <'bool.h'`; then
    echo shar: \"'bool.h'\" unpacked with wrong size!
fi
# end of 'bool.h'
fi
if test -f 'ealloc.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'ealloc.c'\"
else
echo shar: Extracting \"'ealloc.c'\" \(627 characters\)
sed "s/^X//" >'ealloc.c' <<'END_OF_FILE'
X/* ealloc.c -- error checking malloc */
X
X#include <stdio.h>
X#include "new.h"
X
Xextern char *progname;
X
X/* VARARGS1 */  /* PRINTFLIKE0 */
Xvoid panic(fmt, a, b, c, d, e, f, g, h)
X	char *fmt;
X{
X	fprintf(stderr, "%s: ", progname);
X	fprintf(stderr, fmt, a, b, c, d, e, f, g, h);
X	exit(1);
X}
X
Xchar *ealloc(n)
X	int n;
X{
X	char *p = malloc(n);
X	if (p == NULL)
X		panic("malloc(%d) returned 0\n", n);
X	return p;
X}
X
Xchar *erealloc(p, n)
X	char *p;
X	int n;
X{
X	p = realloc(p, n);
X	if (p == NULL)
X		panic("realloc(%d) returned 0\n", n);
X	return p;
X}
X
X#include <string.h>
X
Xchar *strdup(s)
X	char *s;
X{
X	return strcpy(ealloc(strlen(s) + 1), s);
X}
END_OF_FILE
if test 627 -ne `wc -c <'ealloc.c'`; then
    echo shar: \"'ealloc.c'\" unpacked with wrong size!
fi
# end of 'ealloc.c'
fi
if test -f 'efopen.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'efopen.c'\"
else
echo shar: Extracting \"'efopen.c'\" \(303 characters\)
sed "s/^X//" >'efopen.c' <<'END_OF_FILE'
X/* efopen.c -- open stdio file, check for errors */
X
X#include <stdio.h>
X
Xextern char *progname;
X
XFILE *efopen(file, mode)
X	char *file, *mode;
X{
X	FILE *fp = fopen(file, mode);
X	if (fp == NULL) {
X		fprintf(stderr, "%s: can't open file %s, mode %s\n",
X			progname, file, mode);
X		exit(1);
X	}
X	return fp;
X}
END_OF_FILE
if test 303 -ne `wc -c <'efopen.c'`; then
    echo shar: \"'efopen.c'\" unpacked with wrong size!
fi
# end of 'efopen.c'
fi
if test -f 'lcomp' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lcomp'\"
else
echo shar: Extracting \"'lcomp'\" \(1433 characters\)
sed "s/^X//" >'lcomp' <<'END_OF_FILE'
X#! /bin/sh
X
XLIB=.
XPATH=$LIB:$PATH
Xexport PATH
XCC=cc
XALTCC=gcc
X
XCFILES=
XFFILES=
XSFILES=
XOFILES=
XRMFILES=
X
XLIBS=
XFLIBS=
XPROF=prof.out
XLINK=true
XEXEC=a.out
XFFLAGS='-u _MAIN_'
XFORTRAN='-lF77 -lI77 -lU77 -lm'
X
Xwhile [ $# != 0 ]
Xdo
X	case "$1" in
X	*.c)	CFILES="$CFILES $1" ;;
X	*.[fF])	FFILES="$FFILES $1" ; FLIBS="$FORTRAN" ;;
X	*.[sS])	SFILES="$SFILES $1" ;;
X	*.o)	OFILES="$OFILES $1" ;;
X	-r)	shift ; PROF=$1 ;;
X	-C)	CC=CC ;;
X	-gcc)	CC="$ALTCC" ;;
X	-F)	FLIBS="$FORTRAN" ;;
X	-O)	;;
X	-c)	LINK=false ;;
X	-o)	shift ; EXEC=$1 ;;
X	-l*|*.a)LIBS="$LIBS $1" ;;
X	-*)	FLAGS="$FLAGS $1" ;;
X	esac
X	shift
Xdone
X
Xfor i in $CFILES
Xdo
X	file=`echo $i | sed 's/\.c$//'`
X	$CC -g -S $FLAGS $file.c	|| exit $?
X	bb $file.s			|| exit $?
X	SFILES="$SFILES $file.s"
X	RMFILES="$RMFILES $file.s"
Xdone
X
Xfor i in $FFILES
Xdo
X	file=`echo $i | sed 's/\.[fF]$//'`
X	f77 -g -S $FLAGS $i		|| exit $?
X	bb $file.s			|| exit $?
X	SFILES="$SFILES $file.s"
X	RMFILES="$RMFILES $file.s"
Xdone
X
Xfor i in $SFILES
Xdo
X	file=`echo $i | sed 's/\.[sS]$//'`
X	$CC -c $FLAGS $i		|| exit $?
X	OFILES="$OFILES $file.o"
Xdone
X
Xif $LINK
Xthen
X	if [ "$PROF" = prof.out ]
X	then
X		OFILES="$OFILES $LIB/bbfile.o"
X	else
X		echo "char *_bbfile = \"$PROF\";" > $$bbfile.c
X		$CC -c $$bbfile.c
X		OFILES="$OFILES $$bbfile.o"
X		RMFILES="$RMFILES $$bbfile.c $$bbfile.o"
X	fi
X
X	if [ "$FLIBS" != "" ]
X	then
X		FLAGS="$FLAGS $FFLAGS"
X	fi
X	$CC -o $EXEC $FLAGS $OFILES $LIB/bbexit.o $LIBS $FLIBS || exit $?
Xfi
Xrm -f $RMFILES
END_OF_FILE
if test 1433 -ne `wc -c <'lcomp'`; then
    echo shar: \"'lcomp'\" unpacked with wrong size!
fi
chmod +x 'lcomp'
# end of 'lcomp'
fi
if test -f 'lcomp.1' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lcomp.1'\"
else
echo shar: Extracting \"'lcomp.1'\" \(4060 characters\)
sed "s/^X//" >'lcomp.1' <<'END_OF_FILE'
X.TH LCOMP 1 "15 April 1988"
X.SH NAME
Xlcomp, lprint \- statement and instruction counting
X.SH SYNOPSIS
X.B lcomp
X[
X.B \-r
X.I prof.out
Xfile
X]
X[
X.B \-FC
X]
X[
X.B \-gcc
X]
X.I cc
Xor
X.I f77
Xarguments ...
X.PP
X.B lprint
X[
X.B \-blaipfc
X]
X[
X.B \-r
X.I prof.out
Xfile
X] [ srcfile ] ...
X.SH DESCRIPTION
X.LP
X.I Lcomp
Xcompiles a C or \s-2FORTRAN\s0 program into an executable that produces
Xinstruction counts.  \fILcomp\fP behaves similarly to
X.I cc
Xand \fIf77\fP,
Xand accepts the same arguments and options as those programs, except that:
X.TP
X.B \-C
XAll named .c files are C++ programs and should be compiled with
X.I CC
Xinstead of
X.I cc .
X.TP
X.B \-F
XLink with \s-2FORTRAN\s0 libraries.  Implied if a named .f file is included,
Xbut necessary if only object files are listed.
X.TP
X.B \-gcc
XUse the GNU C compiler in place of the stock 'cc' compiler.
X.TP
X.BI \-r " file"
XGenerate code that puts the output in the named file, rather than
X\fIprof.out\fP.
X.LP
XFor each .c or .f file named, a .sL file is created, which maps
Xbasic blocks to line numbers.  The source is compiled into a .o
Xfile which is instrumented for counting basic blocks.
X.LP
XIn the executable file, the function \fI_bbdump\fP(), which is called
Xautomatically be \fIexit\fP(), writes the
X.I prof.out
Xfile.  \fI_bbdump\fP() clears it's data structures, so it is safe to
Xcall from a signal handler (as long as it is safe to I/O from a signal
Xhandler on your machine).  This is useful for gethering statistics on
Xa program that is not supposed to exit.
X.LP
X.I Lprint
Xanalyzes the results of executing a program compiled with
X.I lcomp .
XThe default behavior is to print an execution count in the left margin
Xof each named file for the first basic block on that line.
XIf no files are listed on the command line,
Xall that were executed are printed.
X.SH OPTIONS
X.TP
X.B \-b
XPrint counts for basic blocks (default, unless one of
X.B \-ipf
Xis selected).
X.TP
X.B \-l
XPrint counts for all lines, not just the first line of each basic block.
X.TP
X.B \-a
XPrint all basic blocks, not just the first one from a line.
X.TP
X.B \-i
XPrint instruction counts.  If a basic block is not executed, the
Xnumber of instructions in that block is printed in parentheses.
X.TP
X.B \-f
XSummarize by file.  For instructions and basic blocks, the number executed,
Xthe total number in the file, and the number not executed are printed.
X.TP
X.B \-p
XSummarize by function.  As \fB-f\fP, but the number of times each
Xfunction is called is also printed.
X.TP
X.B \-c
XCompresses the
X.I prof.out
Xfile.  The file grows every time the profile program is executed.
X.TP
X.BI \-r " file"
XRead counting data from the named file, instead of \fIprof.out\fP.
X.SH "EXAMPLES"
X.ta 2.0i
X.nf
X$ lcomp file.c	# compile with counting code
X$ a.out	# generate instruction counts
X$ lprint file.c	# print statement counts for file.c
X.PP
X$ lcomp -o prog *.f	# compile all fortran programs in directory
X$ prog ...	# generate instruction counts
X$ lprint -fp	# print summary information for all files
X.PP
X$ make "CC=lcomp"	# tell make to use count generating compiler
X.fi
X.SH "SEE ALSO"
Xcc(1), f77(1), prof(1), gprof(1), exit(2)
X.br
Xtcov(1) in SunOS
X.PP
XPeter J. Weinberger, ``Cheap Dynamic Instruction Counting,''
Xin \fIAT&T Bell Laboratories Technical Journal\fP,
XVolume 63, No. 8, October 1984.
X.SH FILES
X.PD 0
X.TP 1.5i
X.I file .sL
Xmapping from basic blocks to lines and functions
X.TP
X.I prof.out
Xdefault output file for counts
X.TP
X$LIB/bb
Xassembly language post-processor to insert statement counts
X.TP
X$LIB/bbexit.o
Xexit routine for statement counting
X.TP
X$LIB/bbfile.o
Xcontains name of file to dump to, normally
X.I prof.out
X.PD
X.SH BUGS
X.LP
XThe analyzed program must call
X.I exit (2),
Xeither explictly or implictly by returning from
X\fImain\fP() for the coverage information to be written to the
X.I prof.out
Xfile.
X.LP
XThe order that \fIlprint\fP prints files in if no names are
Xmentioned on the command line is determinate but not too useful.
X.LP
XProfiling the kernel is possible, but some code must be written
Xto grab the data out of kernel memory,
Xrather than using \fI_bbdump\fP().
END_OF_FILE
if test 4060 -ne `wc -c <'lcomp.1'`; then
    echo shar: \"'lcomp.1'\" unpacked with wrong size!
fi
# end of 'lcomp.1'
fi
if test -f 'lprint.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'lprint.c'\"
else
echo shar: Extracting \"'lprint.c'\" \(9072 characters\)
sed "s/^X//" >'lprint.c' <<'END_OF_FILE'
X/* lprint.c -- print out statement counts */
X
X#include <stdio.h>
X#include <string.h>
X#include "bool.h"
X#include "new.h"
X
X#define	streq(s, t)	(strcmp((s), (t)) == 0)
X
Xextern FILE *efopen();
X
Xchar *progname = "lprint";
X
Xvoid usage()
X{
X	fprintf(stderr, "usage: %s [-blaipf] [-c] [-r file] [file ...]\n", progname);
X	fprintf(stderr, "	-b	print basic block counts (default)\n");
X	fprintf(stderr, "	-l	print counts for all lines\n");
X	fprintf(stderr, "	-a	print all basic blocks\n");
X	fprintf(stderr, "	-i	print instruction counts\n");
X	fprintf(stderr, "	-p	print function summaries\n");
X	fprintf(stderr,	"	-f	print file summaries\n");
X	fprintf(stderr, "	-c	compress prof.out file\n");
X	fprintf(stderr, "	-r	select alternate prof.out file\n");
X	exit(1);
X}
X
Xint flags = 0;
X
X#define	BLOCKS	0x01
X#define	LINES	0x02
X#define	ALL	0x04
X#define	INST	0x08
X#define	FILESUM	0x10
X#define	FUNCSUM	0x20
X
X#define	DEFAULT	BLOCKS
X
Xtypedef struct Mapfile Mapfile;
Xtypedef struct Mapblock Mapblock;
Xtypedef struct Sourcefile Sourcefile;
Xtypedef struct Block Block;
Xtypedef struct Func Func;
X
Xstruct Mapfile {
X	char	*name;
X	int	n, nfunc;
X	struct Mapblock {
X		long	count;
X		int	inst;
X		Sourcefile *source;
X	} *block;
X	Mapfile	*next;
X};
X
XMapfile *maplist = NULL;
X
Xstruct Block {
X	int	line, last, inst;
X	long	count;
X};
X
Xstruct Sourcefile {
X	char	*name;
X	int	nblock, maxblock;
X	Block	*block;
X	Sourcefile *next;
X};
XSourcefile *sourcelist = NULL;
X
Xstruct Func {
X	char	*name;
X	Mapfile	*map;
X	int	block;
X};
X
XFunc *functab = NULL;
Xint nfunc = 0, maxfunc = 0;
X
Xvoid gather(fp)
X	FILE *fp;
X{
X	int i, n;
X	char name[BUFSIZ];
X	while (fscanf(fp, "%s %d\n", name, &n) != EOF) {
X		Mapfile *p;
X		for (p = maplist; p != NULL; p = p->next)
X			if (streq(name, p->name)) {
X				if (n != p->n)
X					panic("prof.out: bad counts for %s: %d and %d\n",
X					      name, p->n, n);
X				goto found;
X			}
X		p = new(Mapfile, 1);
X		p->next = maplist;
X		maplist = p;
X		p->name = strdup(name);
X		p->n = n;
X		p->block = new(struct Mapblock, n);
X		for (i = 0; i < n; i++)
X			p->block[i].count = 0;
X	found:
X		for (i = 0; i < n; i++) {
X			long count;
X			if (fscanf(fp, "%ld", &count) == EOF)
X				panic("prof.out: early EOF\n");
X			p->block[i].count += count;
X		}
X	}
X}
X
Xvoid writeprof(fp)
X	FILE *fp;
X{
X	Mapfile *p;
X	for (p = maplist; p != NULL; p = p->next) {
X		int i;
X		fprintf(fp, "%s %d\n", p->name, p->n);
X		for (i = 0; i < p->n; i++)
X			fprintf(fp, "%ld\n", p->block[i].count);
X	}
X}
X
XSourcefile *install(name, line, last, inst, count, n)
X	char	*name;
X	int	line, last, inst, n;
X	long	count;
X{
X	int i;
X	static Sourcefile *p = NULL;
X	if (p != NULL && streq(name, p->name))
X		goto found;
X	for (p = sourcelist; p != NULL; p = p->next)
X		if (streq(name, p->name))
X			goto found;
X
X	p = new(Sourcefile, 1);
X	p->name	    = strdup(name);
X	p->block    = new(Block, n);
X	p->maxblock = n;
X	p->nblock   = 0;
X	p->next     = sourcelist;
X	sourcelist  = p;
X
Xfound:
X	if (p->nblock >= p->maxblock) {
X		p->maxblock *= 4;
X		p->block = renew(Block, p->block, p->maxblock);
X	}
X
X	/* insertion sort, but (in practice) very rarely executed */
X	for (i = p->nblock++; i > 0 && line < p->block[i - 1].line; i--)
X		p->block[i] = p->block[i - 1];
X
X	p->block[i].line  = line;
X	p->block[i].last  = last;
X	p->block[i].inst  = inst;
X	p->block[i].count = count;
X	return p;
X}
X
Xvoid correlate(map)
X	Mapfile *map;
X{
X	int i;
X	FILE *fp = efopen(map->name, "r");
X	for (i = 0; i < map->n; i++) {
X		char filename[BUFSIZ];
X		int line, lastline;
X		if (fscanf(fp, "%s %d %d %d\n", filename,
X			   &line, &lastline, &map->block[i].inst) != 4)
X			panic("%s, line %d: bad map entry\n", map->name, i + 1);
X		map->block[i].source = install(filename, line, lastline,
X				map->block[i].inst, map->block[i].count, map->n);
X	}
X	if (fscanf(fp, "%d functions\n", &map->nfunc) != 1)
X		panic("%s, line %d: bad function line\n", map->name, map->n);
X	while (nfunc + map->nfunc >= maxfunc) {
X		if (maxfunc == 0)
X			maxfunc = 200;
X		else
X			maxfunc *= 8;
X		functab = renew(Func, functab, maxfunc);
X	}
X	for (i = 0; i < map->nfunc; i++, nfunc++) {
X		char name[BUFSIZ];
X		int block;
X		if (fscanf(fp, "%s %d\n", name, &block) != 2)
X			panic("%s, line %d: bad function entry\n",
X			      map->name, map->n + 1 + 1);
X		functab[nfunc].name  = strdup(name);
X		functab[nfunc].map   = map;
X		functab[nfunc].block = block;
X	}
X	fclose(fp);
X}
X
Xvoid printline(s, count, inst)
X	char	*s;
X	long	count;
X	int	inst;
X{
X	if (flags & BLOCKS)
X		printf("%10ld  ", count);
X	if (flags & INST) {
X		if (count == 0) {
X			char buf[20];
X			sprintf(buf, "(%d)", inst);
X			printf("%11s ", buf);
X		} else
X			printf("%10ld  ", count * inst);
X	}
X	printf("%s", s);
X}
X
Xvoid printsource(p)
X	Sourcefile *p;
X{
X	int	line = 0, last = 0, i = 0, inst = 0;
X	long	count = 0;
X	char	buf[BUFSIZ];
X	FILE	*fp = efopen(p->name, "r");
X
X	static int fill = 0;
X	static bool firsttime = TRUE;
X	if (firsttime) {
X		firsttime = FALSE;
X		if (flags & BLOCKS)
X			fill += 12;
X		if (flags & INST)
X			fill += 12;
X	} else
X		printf("\f");
X
X	while (fgets(buf, sizeof buf, fp) != NULL) {
X		for (; i < p->nblock && line >= p->block[i].line; i++) {
X			if (flags & ALL)
X				printline("\n", p->block[i].count,
X						p->block[i].inst);
X			if (last <= p->block[i].last)
X				last = p->block[i].last;
X		}
X		line++;
X		if (i < p->nblock && line == p->block[i].line && last < line) {
X			count = p->block[i].count;
X			inst  = p->block[i].inst;
X			last  = p->block[i].last;
X			printline(buf, count, inst);
X			while (++i < p->nblock && line == p->block[i].line)
X				if (flags & ALL)
X					printline("\n", p->block[i].count,
X							p->block[i].inst);
X		} else if (flags & LINES)
X			printline(buf, count, inst);
X		else
X			printf("%*s%s", fill, "", buf);
X	}
X	fclose(fp);
X}
X
Xtypedef struct Sum {
X	long	calls, i, ie, ine, bb, bbe, bbne;
X} Sum;
X
Xvoid printsumline(name, sum, isfunc)
X	char	*name;
X	Sum	sum;
X	bool	isfunc;
X{
X	printf("%9ldbbe %4ldbb %4ldbbne ", sum.bbe, sum.bb, sum.bbne);
X	printf("%9ldie %4ldi %4ldine ", sum.ie, sum.i, sum.ine);
X	if (isfunc)
X		printf("%7ldcalls ", sum.calls);
X	else
X		printf("%13s", "");
X	printf(" %s\n", name);
X}
X
Xstatic Sum zerosum = { 0, 0, 0, 0, 0, 0, 0 };
X
Xvoid printfunctionsummary(p)
X	Sourcefile *p;
X{
X	Func *func;
X
X	for (func = &functab[0]; func < &functab[nfunc]; func++)
X		if (func->map->block[func->block].source == p) {
X			Sum sum;
X			Mapblock *block = func->map->block;
X			int i, last;
X			sum = zerosum;
X			if (func < &functab[nfunc] && func->map == (func + 1)->map)
X				last = (func + 1)->block;
X			else
X				last = func->map->n;
X			sum.calls += block[func->block].count;
X			for (i = func->block; i < last; i++) {
X				Mapblock *b = &block[i];
X				sum.bb	+= 1;
X				sum.bbe	+= b->count;
X				sum.i	+= b->inst;
X				sum.ie	+= b->inst * b->count;
X				if (b->count == 0) {
X					sum.bbne += 1;
X					sum.ine  += b->inst;
X				}
X			}
X			printsumline(func->name, sum, TRUE);
X		}
X}
X
Xvoid printfilesummary(p)
X	Sourcefile *p;
X{
X	Sum sum;
X	Mapfile *map;
X	Mapblock *block;
X
X	sum = zerosum;
X	for (map = maplist; map != NULL; map = map->next)
X		for (block = &map->block[0]; block < &map->block[map->n]; block++)
X			if (block->source == p) {
X				sum.bb	+= 1;
X				sum.bbe	+= block->count;
X				sum.i	+= block->inst;
X				sum.ie	+= block->inst * block->count;
X				if (block->count == 0) {
X					sum.bbne += 1;
X					sum.ine  += block->inst;
X				}
X			}
X	printsumline(p->name, sum, FALSE);
X}
X
Xvoid analyze(name)
X	char *name;
X{
X	Sourcefile *p;
X	for (p = sourcelist; p == NULL || !streq(p->name, name); p = p->next)
X		if (p == NULL) {
X			fprintf(stderr, "%s: not in prof.out\n", name);
X			return;
X		}
X
X	if (flags & (INST|BLOCKS)) {
X		printsource(p);
X		if (flags & (FUNCSUM|FILESUM))
X			printf("\n\n\n\n");
X	}
X	if (flags & FUNCSUM) {
X		printfunctionsummary(p);
X		if (flags & FILESUM)
X			printf("\n");
X	}
X	if (flags & FILESUM) {
X		printfilesummary(p);
X		if ((flags & FUNCSUM) && (flags & (INST|BLOCKS)) == 0)
X			printf("\n\n");
X	}
X}
X
Xint main(argc, argv)
X	int argc;
X	char *argv[];
X{
X	int c;
X	bool compact = FALSE;
X	char *prof = "prof.out";
X	Mapfile *map;
X
X	extern int optind;
X	extern char *optarg;
X
X	progname = argv[0];
X	while ((c = getopt(argc, argv, "blaipfcr:?")) != EOF)
X		switch(c) {
X		case 'b':	flags |= BLOCKS;	break;
X		case 'l':	flags |= LINES;		break;
X		case 'a':	flags |= ALL;		break;
X		case 'i':	flags |= INST;		break;
X		case 'p':	flags |= FUNCSUM;	break;
X		case 'f':	flags |= FILESUM;	break;
X		case 'c':	compact = TRUE;		break;
X		case 'r':	prof = optarg;		break;
X		case '?':	usage();
X		}
X
X	if (streq(prof, "-"))
X		gather(stdin);
X	else {
X		FILE *fp = efopen(prof, "r");
X		gather(fp);
X		fclose(fp);
X	}
X	if (compact) {
X		if (streq(prof, "-"))
X			writeprof(stdout);
X		else {
X			FILE *fp = efopen(prof, "w");
X			writeprof(fp);
X			fclose(fp);
X		}
X		if (optind == argc && flags == 0)
X			return 0;
X	}
X
X	if (flags == 0)
X		flags = DEFAULT;
X	if ((flags & (ALL|LINES)) && (flags & (INST|BLOCKS)) == 0)
X		flags |= BLOCKS;
X
X	for (map = maplist; map != NULL; map = map->next)
X		correlate(map);
X	if (optind == argc) {
X		Sourcefile *p;
X		for (p = sourcelist; p != NULL; p = p->next)
X			analyze(p->name);
X	} else
X		for (; optind < argc; optind++)
X			analyze(argv[optind]);
X	return 0;
X}
END_OF_FILE
if test 9072 -ne `wc -c <'lprint.c'`; then
    echo shar: \"'lprint.c'\" unpacked with wrong size!
fi
# end of 'lprint.c'
fi
if test -f 'new.h' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'new.h'\"
else
echo shar: Extracting \"'new.h'\" \(402 characters\)
sed "s/^X//" >'new.h' <<'END_OF_FILE'
X/* new.h -- dynamic memory allocation */
X
Xextern char *malloc(), *ealloc(), *realloc(), *erealloc(), *strdup();
Xextern int free();
Xextern void panic();
X
X#ifndef NULL
X#define NULL 0
X#endif
X
X#define	new(t, n)	((t *) ealloc((n) * sizeof (t)))
X#define renew(t, p, n)	(((p) == NULL) \
X				? new(t, n) \
X				: ((t *) erealloc((char *) (p), (n) * sizeof (t))))
X#define	delete(p)	(((p) == NULL) ? 0 : free(p))
END_OF_FILE
if test 402 -ne `wc -c <'new.h'`; then
    echo shar: \"'new.h'\" unpacked with wrong size!
fi
# end of 'new.h'
fi
if test -f 'pi.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pi.c'\"
else
echo shar: Extracting \"'pi.c'\" \(5693 characters\)
sed "s/^X//" >'pi.c' <<'END_OF_FILE'
X/* pi n - compute PI to n decimal digits accuracy/
X *    currently, n must be less than or equal to 10000
X *    (this program is highly optimized, both algorithmically
X *    and at the source code level.)
X *
X *    the approach is to compute pi as the sum of three
X *    arctangent terms, where taylor series expansions
X *    are used to compute each arctangent to the desired
X *    accuracy.  arrays are used as 'big numbers', and
X *    long-hand arithmetic is simulated on the arrays.
X *    (the mathematics has been manipulated to avoid
X *    such complex operations such as division of one
X *    big number by another.
X *
X *    (time to compute pi to 10000 places: <9 cpu hours on PDP-11/44)
X */
X
X#include <math.h>
X
X#define MAXNUM  10000   /* largest allowable accuracy */
X#define NDS     4       /* # of digits/machine word */
X#define MSIZE   (MAXNUM/NDS + 2)   /* storage needed */
X#define WDSZ    10000   /* 10 ^ NDS (no exponentiation in C) */
X
Xint places, nwd;        /* # of places, words needed */
Xlong t[MSIZE],s[MSIZE],b[MSIZE],r[MSIZE];  /* big numbers */
X
Xmain(ac,av)
Xint ac;                 /* number of command line arguments */
Xchar *av[];             /* array of command line arguments */
X   {
X    int tcnt;           /* # of arctangent terms */
X    int y[3];           /* constants in arctangent */
X    int c[3];           /*    terms */
X    int positive;       /* switches sign of arctangent term */
X    long y2;            /* y squared */
X    int l, k;           /* loop control */
X
X    places = (ac < 2) ? 50 : atoi(av[1]);
X    if (places > MAXNUM) {
X       printf("Cannot compute to that accuracy");
X       exit(1);
X       }
X
X    nwd    = places/NDS + 2.5;
X
X    y[0] = 8; y[1] = 57; y[2] = 239;
X    c[0] = 24;c[1] =  8; c[2] = 4;
X
X    unit(r,0);          /* initialize the result number */
X
X/*        compute the arctangent terms and combine */
X
X    for (l = 0;l <= 2; l++) {
X           tcnt = terms(c[l],y[l]);
X           printf("Number of terms = %d\n",tcnt);
X
X           y2 = (long)y[l]*(long)y[l];    /* y squared */
X
X           unit(t,c[l]);                  /* first term in taylor */
X           divms(t,(long)y[l],t);         /*  series expansion */
X           move(t,b);
X
X           positive = 1;                  /* remaining terms */
X           for (k = 2; k <= tcnt; k++) {
X              divms(t,y2,t);
X              divms(t,(long)((k<<1)-1),s);
X              positive = !positive;
X              if (positive) addmm(b,s,b);
X              else          submm(b,s,b);
X              }
X           addmm(r,b,r);                  /* add arctangent to result */
X           }
X
X   adjust(r);                   /* adjust carries and borrows */
X   inform(r);                   /* display the result */
X   }
X
X
Xint terms(c,d)          /* determine # of arctangent terms needed to  */
Xint c,d;                /*  obtain places worth or accuracy */
X   {
X   return  (int)((places+log10((double)c))/log10((double)d) + 1.5);
X   }
X
Xunit(a,b)               /* assign scalar b to big number a */
Xlong a[];
Xint b;
X   {
X   long *p, *e;
X   a[0] = b;
X   for (p = a, e = &a[nwd-1]; p < e;)
X      *++p = 0;
X   }
X
Xmove(a,b)               /* copy big number a into big number b */
Xlong a[], b[];
X   {
X   long *pa, *pb, *e;
X   for (pa = a,pb = b, e = &a[nwd]; pa < e;)
X      *pb++ = *pa++;
X   }
X
X
Xdivms(a,b,c)            /* divide big number a by scalar b */
Xlong a[], c[];
Xlong b;
X   {
X   long t, t1;
X   register long *pa, *pc, *e;
X   t = 0;
X   for (pa = a, pc = c, e = &a[nwd]; pa < e;) {
X      *pc = (t1 = *pa++ + t*WDSZ) / b;     /* this code is essentially */
X      if ((t = t1 % b) < 0) {              /*   the code in mod1(), but */
X         t += b;                           /*   was moved here to avoid */
X         (*pc)--;                          /*   a procedure call within */
X         }                                 /*   the innermost loop */
X      pc++;
X      }
X   }
X
X
Xaddmm(a,b,c)            /* add big numbers a and b */
Xlong a[], b[], c[];
X   {
X   long *pa, *pb, *pc, *e;
X   for (pa = a,pb = b,pc = c, e = &c[nwd]; pc < e;)
X       *pc++ = *pa++ + *pb++;
X   }
X
Xsubmm(a,b,c)            /* subtract big number b from big number a */
Xlong a[], b[], c[];
X   {
X   long *pa, *pb, *pc, *e;
X   for (pa = a,pb = b,pc = c, e = &c[nwd]; pc < e;)
X       *pc++ = *pa++ - *pb++;
X   }
X
Xadjust(a)               /* insure each digit in big number a is a */
Xlong a[];               /*  digit < WDSZ, by performing carries */
X   {                    /*  as needed. */
X   long *pa, *pb, *e;
X   long m;
X   long mod1();
X   for (pa = &a[nwd-1], pb = pa - 1, e = a; pa > e; pa--) {
X      *pa = mod1(*pa,(long)WDSZ,&m);
X      *pb-- += m;
X      }
X   }
X
X
Xinform(a)               /* display the result (given in big number a) */
Xlong a[];
X   {
X   printf("\n\n\n\tPI Calcuation\n\n\n");
X   printf("\t\t# of words/number\t= %d\n",nwd);
X   printf("\t\t# of digits/word\t= %d\n",NDS);
X   printf("\t\t# of accurate places\t= %d\n",places);
X   printf("\t\t# Arithmetic base is %d\n",WDSZ);
X   printf("\n\n\tPI is:\n\n");
X   outnum(a);
X   }
X
Xoutnum(a)               /* print out the big number a */
Xlong a[];
X   {
X   int i;
X   char s[15];
X   sprintf(s,"%%%dd.",NDS);
X   printf(s,(int)a[0]);
X   sprintf(s,"%%%d.%dd ",NDS,NDS);
X   for (i = 1; i < nwd; i++) {
X      printf(s,(int)a[i]);
X      if (i % 10 == 9) printf("\n");
X      }
X   printf("\n");
X   }
X
X
Xlong mod1(m,n,l)        /* compute modulus and remainder */
Xlong m, *l;             /*  (note that this is a true */
Xlong n;                 /*  mathematical modulus, not */
X   {                    /*  the standard computer remainder) */
X   long m1;
X   *l = m/n;
X   m1 = m % n;
X   if (m1 < 0) {
X      m1 += n;
X      (*l)--;
X      }
X   return m1;
X   }
END_OF_FILE
if test 5693 -ne `wc -c <'pi.c'`; then
    echo shar: \"'pi.c'\" unpacked with wrong size!
fi
# end of 'pi.c'
fi
if test -f 'pi.out' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'pi.out'\"
else
echo shar: Extracting \"'pi.out'\" \(7997 characters\)
sed "s/^X//" >'pi.out' <<'END_OF_FILE'
X            /* pi n - compute PI to n decimal digits accuracy/
X             *    currently, n must be less than or equal to 10000
X             *    (this program is highly optimized, both algorithmically
X             *    and at the source code level.)
X             *
X             *    the approach is to compute pi as the sum of three
X             *    arctangent terms, where taylor series expansions
X             *    are used to compute each arctangent to the desired
X             *    accuracy.  arrays are used as 'big numbers', and
X             *    long-hand arithmetic is simulated on the arrays.
X             *    (the mathematics has been manipulated to avoid
X             *    such complex operations such as division of one
X             *    big number by another.
X             *
X             *    (time to compute pi to 10000 places: <9 cpu hours on PDP-11/44)
X             */
X            
X            #include <math.h>
X            
X            #define MAXNUM  10000   /* largest allowable accuracy */
X            #define NDS     4       /* # of digits/machine word */
X            #define MSIZE   (MAXNUM/NDS + 2)   /* storage needed */
X            #define WDSZ    10000   /* 10 ^ NDS (no exponentiation in C) */
X            
X            int places, nwd;        /* # of places, words needed */
X            long t[MSIZE],s[MSIZE],b[MSIZE],r[MSIZE];  /* big numbers */
X            
X            main(ac,av)
X            int ac;                 /* number of command line arguments */
X            char *av[];             /* array of command line arguments */
X         1     {
X                int tcnt;           /* # of arctangent terms */
X                int y[3];           /* constants in arctangent */
X                int c[3];           /*    terms */
X                int positive;       /* switches sign of arctangent term */
X                long y2;            /* y squared */
X                int l, k;           /* loop control */
X            
X                places = (ac < 2) ? 50 : atoi(av[1]);
X                if (places > MAXNUM) {
X         0         printf("Cannot compute to that accuracy");
X                   exit(1);
X                   }
X            
X         1      nwd    = places/NDS + 2.5;
X            
X                y[0] = 8; y[1] = 57; y[2] = 239;
X                c[0] = 24;c[1] =  8; c[2] = 4;
X            
X                unit(r,0);          /* initialize the result number */
X            
X            /*        compute the arctangent terms and combine */
X            
X         4      for (l = 0;l <= 2; l++) {
X         3             tcnt = terms(c[l],y[l]);
X                       printf("Number of terms = %d\n",tcnt);
X            
X                       y2 = (long)y[l]*(long)y[l];    /* y squared */
X            
X                       unit(t,c[l]);                  /* first term in taylor */
X                       divms(t,(long)y[l],t);         /*  series expansion */
X                       move(t,b);
X            
X                       positive = 1;                  /* remaining terms */
X                       for (k = 2; k <= tcnt; k++) {
X       211                divms(t,y2,t);
X                          divms(t,(long)((k<<1)-1),s);
X                          positive = !positive;
X                          if (positive) addmm(b,s,b);
X       106                else          submm(b,s,b);
X       211                }
X         3             addmm(r,b,r);                  /* add arctangent to result */
X         3             }
X            
X         1     adjust(r);                   /* adjust carries and borrows */
X               inform(r);                   /* display the result */
X               }
X            
X            
X            int terms(c,d)          /* determine # of arctangent terms needed to  */
X            int c,d;                /*  obtain places worth or accuracy */
X         3     {
X               return  (int)((places+log10((double)c))/log10((double)d) + 1.5);
X               }
X            
X            unit(a,b)               /* assign scalar b to big number a */
X            long a[];
X            int b;
X         4     {
X               long *p, *e;
X               a[0] = b;
X               for (p = a, e = &a[nwd-1]; p < e;)
X       104        *++p = 0;
X               }
X            
X            move(a,b)               /* copy big number a into big number b */
X            long a[], b[];
X         3     {
X               long *pa, *pb, *e;
X               for (pa = a,pb = b, e = &a[nwd]; pa < e;)
X        81        *pb++ = *pa++;
X               }
X            
X            
X            divms(a,b,c)            /* divide big number a by scalar b */
X            long a[], c[];
X            long b;
X       425     {
X               long t, t1;
X               register long *pa, *pc, *e;
X               t = 0;
X               for (pa = a, pc = c, e = &a[nwd]; pa < e;) {
X     11475        *pc = (t1 = *pa++ + t*WDSZ) / b;     /* this code is essentially */
X                  if ((t = t1 % b) < 0) {              /*   the code in mod1(), but */
X         0           t += b;                           /*   was moved here to avoid */
X                     (*pc)--;                          /*   a procedure call within */
X                     }                                 /*   the innermost loop */
X     11475        pc++;
X                  }
X               }
X            
X            
X            addmm(a,b,c)            /* add big numbers a and b */
X            long a[], b[], c[];
X       108     {
X               long *pa, *pb, *pc, *e;
X               for (pa = a,pb = b,pc = c, e = &c[nwd]; pc < e;)
X      2916         *pc++ = *pa++ + *pb++;
X               }
X            
X            submm(a,b,c)            /* subtract big number b from big number a */
X            long a[], b[], c[];
X       106     {
X               long *pa, *pb, *pc, *e;
X               for (pa = a,pb = b,pc = c, e = &c[nwd]; pc < e;)
X      2862         *pc++ = *pa++ - *pb++;
X               }
X            
X            adjust(a)               /* insure each digit in big number a is a */
X            long a[];               /*  digit < WDSZ, by performing carries */
X         1     {                    /*  as needed. */
X               long *pa, *pb, *e;
X               long m;
X               long mod1();
X               for (pa = &a[nwd-1], pb = pa - 1, e = a; pa > e; pa--) {
X        26        *pa = mod1(*pa,(long)WDSZ,&m);
X                  *pb-- += m;
X        26        }
X               }
X            
X            
X            inform(a)               /* display the result (given in big number a) */
X            long a[];
X         1     {
X               printf("\n\n\n\tPI Calcuation\n\n\n");
X               printf("\t\t# of words/number\t= %d\n",nwd);
X               printf("\t\t# of digits/word\t= %d\n",NDS);
X               printf("\t\t# of accurate places\t= %d\n",places);
X               printf("\t\t# Arithmetic base is %d\n",WDSZ);
X               printf("\n\n\tPI is:\n\n");
X               outnum(a);
X               }
X            
X            outnum(a)               /* print out the big number a */
X            long a[];
X         1     {
X               int i;
X               char s[15];
X               sprintf(s,"%%%dd.",NDS);
X               printf(s,(int)a[0]);
X               sprintf(s,"%%%d.%dd ",NDS,NDS);
X               for (i = 1; i < nwd; i++) {
X        26        printf(s,(int)a[i]);
X                  if (i % 10 == 9) printf("\n");
X        26        }
X         1     printf("\n");
X               }
X            
X            
X            long mod1(m,n,l)        /* compute modulus and remainder */
X            long m, *l;             /*  (note that this is a true */
X            long n;                 /*  mathematical modulus, not */
X        26     {                    /*  the standard computer remainder) */
X               long m1;
X               *l = m/n;
X               m1 = m % n;
X               if (m1 < 0) {
X         9        m1 += n;
X                  (*l)--;
X                  }
X        26     return m1;
X               }
END_OF_FILE
if test 7997 -ne `wc -c <'pi.out'`; then
    echo shar: \"'pi.out'\" unpacked with wrong size!
fi
# end of 'pi.out'
fi
if test -f 'rename.c' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'rename.c'\"
else
echo shar: Extracting \"'rename.c'\" \(377 characters\)
sed "s/^X//" >'rename.c' <<'END_OF_FILE'
X/* rename.c -- file renaming routine for systems without rename(2)
X *
X * Written by reading the System V Interface Definition, not the code.
X *
X * Totally public domain.
X *
X */
X/* LINTLIBRARY */
X
Xint rename(from,to)
Xregister char *from, *to;
X{
X    (void) unlink(to);
X    if (link(from, to) < 0)
X	return(-1);
X
X    (void) unlink(from);
X    return(0);
X}
X
X/* rename.c ends here */
END_OF_FILE
if test 377 -ne `wc -c <'rename.c'`; then
    echo shar: \"'rename.c'\" unpacked with wrong size!
fi
# end of 'rename.c'
fi
if test -f 'vax.l' -a "${1}" != "-c" ; then 
  echo shar: Will not clobber existing file \"'vax.l'\"
else
echo shar: Extracting \"'vax.l'\" \(2471 characters\)
sed "s/^X//" >'vax.l' <<'END_OF_FILE'
X/* vax.l -- basic block counting driver for vaxen */
X
X%{
X
X#include <stdio.h>
X#include <ctype.h>
X#include <string.h>
X#include "bool.h"
X#include "bb.h"
X
Xextern void panic();
X
Xbool newfunc = FALSE;		/* started new function? */
X
X%}
X
X%%
X
X\.stab[dn]\n	{ stabd(); return; }
X\.stabs\n	{ stabs(); return; }
X\.word\n	{ word(); return; }
X\.text\n	{ text = TRUE;  passline(); return; }
X\.data\n	{ text = FALSE; passline(); return; }
X\..*\n		{ passline(); return; }
X
Xnop\n		{ safe(); return; }
Xmovpsl\n	{ safe(); return; }
Xadwc\n		{ safe(); return; }
X
X[as]ob.+\n	{ branch(); return; }
Xcase[lwb]\n	{ branch(); return; }
X
Xbi[sc]psw\n	{ safe(); return; }
Xbi.+\n		{ inst(); return; }
Xb.+\n		{ safe(); return; }
X
Xjsb\n		{ inst(); return; }
Xjbr\n		{ jbr(); return; }
Xj.+\n		{ branch(); return; }
X.+\n		{ inst(); return; }
X\n		{ panic("null opcode"); }
X
X%%
X
X/* ARGSUSED */
Xbool labelstartsblock(s)
X	char *s;
X{
X	return TRUE;
X}
X
Xincrement()
X{
X	if (instructions >= 0)
X		fprintf(map, "%d %d\n", reached, instructions);
X	instructions = 0;
X	fprintf(out, "	incl	bb+%d\n", 4 * block++);
X	fprintf(map, "%s %d ", filename, lineno);
X	newblock = FALSE;
X}
X
Xsafeincrement()
X{
X	fputs("	movpsl	-(sp)\n", out);
X	increment();
X	fputs("	movw	(sp)+, (sp)\n	bicpsw	$0xf\n	bispsw	(sp)+\n", out);
X}
X
Xjbr()
X{
X	if (text && newfunc) {
X		funcprologue();
X		newfunc = FALSE;
X		increment();
X		instructions++;
X		reached = lineno;
X		newblock = TRUE;
X		passline();
X	} else
X		branch();
X}
X
Xfuncprologue()
X{
X	function(label, block);
X	fprintf(out, "	tstl	bb_init\n	jneq	bb_%s\n", label);
X	fprintf(out, "	calls	$0, bb_init_func\nbb_%s:\n", label);
X}
X
Xword()
X{
X	if (text && newblock && label[0] == '_') {
X		newfunc = TRUE;
X		}
X	passline();
X}
X
Xepilogue(mapfile)
X	char *mapfile;
X{
X	if (instructions >= 0)
X		fprintf(map, "%d %d\n", reached, instructions);
X	if (text)
X		fprintf(out, "	.data\n");
X	fprintf(out, "	.lcomm bb, %d\n", 4 * block);
X	fprintf(out, "bb_mapfile:\n");
X	fprintf(out, "	.asciz	\"%s\"\n", mapfile);
X	fprintf(out, "bb_init:\n");
X	fprintf(out, "	.long	0\n");
X	fprintf(out, "bb_entry:\n");
X	fprintf(out, "	.long	0\n");			/* next */
X	fprintf(out, "	.long	%d\n", block);		/* len */
X	fprintf(out, "	.long	bb\n");			/* count */
X	fprintf(out, "	.long	bb_mapfile\n");		/* mapfile */
X	fprintf(out, "	.text\n");
X	fprintf(out, "bb_init_func:\n");
X	fprintf(out, "	.word	0\n");
X	fprintf(out, "	movl	__bblist, bb_entry\n");
X	fprintf(out, "	movl	$bb_entry, __bblist\n");
X	fprintf(out, "	incl	bb_init\n");
X	fprintf(out, "	ret\n");
X}
END_OF_FILE
if test 2471 -ne `wc -c <'vax.l'`; then
    echo shar: \"'vax.l'\" unpacked with wrong size!
fi
# end of 'vax.l'
fi
echo shar: End of shell archive.
exit 0
---- end snip "lcomp.sar" ----
-- 
Steve Wampler	{...!arizona!naucse!tapest!sbw}
	        {...!ditka!tapest!sbw}



More information about the Unix-pc.sources mailing list