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