PSL Manual 7 February 1983 Compiler and Loader
section 18.0 page 18.1
CHAPTER 18
CHAPTER 18
CHAPTER 18
LOADER AND COMPILER
LOADER AND COMPILER
LOADER AND COMPILER
18.1. Introduction . . . . . . . . . . . . . . . 18.1
18.2. The Compiler . . . . . . . . . . . . . . . 18.2
18.2.1. Compiling Functions into Memory . . . . . . 18.2
18.2.2. Compiling Functions into FASL Files . . . . . 18.3
18.2.3. Loading FASL Files. . . . . . . . . . . 18.3
18.2.4. Functions to Control the Time When Something is Done 18.5
.
18.2.5. Order of Functions for Compilation . . . . . 18.6
18.2.6. Fluid and Global Declarations . . . . . . . 18.6
18.2.7. Switches Controlling Compiler . . . . . . . 18.8
18.2.8. Differences between Compiled and Interpreted Code 18.10
18.2.9. Compiler Errors. . . . . . . . . . . . 18.11
18.3. The Loader. . . . . . . . . . . . . . . . 18.13
18.3.1. Legal LAP Format and Pseudos . . . . . . . 18.14
18.3.2. Examples of LAP for DEC-20, VAX and Apollo. . . 18.14
18.3.3. Lap Switches. . . . . . . . . . . . . 18.17
18.4. Structure and Customization of the Compiler. . . . . 18.18
18.5. First PASS of Compiler. . . . . . . . . . . . 18.19
18.5.1. Tagging Information . . . . . . . . . . 18.19
18.5.2. Source to Source Transformations . . . . . . 18.20
18.6. Second PASS - Basic Code Generation . . . . . . . 18.20
18.6.1. The Cmacros . . . . . . . . . . . . . 18.20
18.6.2. Classes of Functions . . . . . . . . . . 18.23
18.6.3. Open Functions . . . . . . . . . . . . 18.24
18.7. Third PASS - Optimizations . . . . . . . . . . 18.29
18.8. Some Structural Notes on the Compiler. . . . . . . 18.30
18.1. Introduction
18.1. Introduction
18.1. Introduction
The functions and facilities in the PSL LISP/SYSLISP compiler and
supporting loaders (LAP and FASL) are described in this chapter.
[??? This chapter is out of date and will be rewritten soon. ???]
[??? This chapter is out of date and will be rewritten soon. ???]
[??? This chapter is out of date and will be rewritten soon. ???]
18.2. The Compiler
18.2. The Compiler
18.2. The Compiler
The compiler is a version of the Portable LISP Compiler [Griss 81],
Compiler and Loader 7 February 1983 PSL Manual
page 18.2 section 18.2
1
modified and extended to more efficiently support both LISP and SYSLISP
compilation. See the later sections in this chapter and references [Griss
81] and [Benson 81] for more details.
18.2.1. Compiling Functions into Memory
18.2.1. Compiling Functions into Memory
18.2.1. Compiling Functions into Memory
__________ ______
!*COMP [Initially: NIL] switch
If the compiler is loaded (which is usually the case, otherwise
on
on
execute LOAD COMPILER;), turning on the switch !*COMP (via on
comp; in RLISP) causes all subsequent procedure definitions of
appropriate type to be compiled automatically and a message of
the form
<function-name> COMPILED, <words> WORDS, <words> LEFT
to be printed. The first number is the number of words of binary
program space the compiled function took, and the second number
the number of words left unused in binary program space. See
!*PWRDS in Section 18.2.7.
____ _____ _____ _____
____ _____ _____ _____
____ _____ _____ _____
expr fexpr nexpr macro
expr fexpr nexpr macro
Currently, exprs, fexprs, nexprs and macros may be compiled. This is
controlled by a flag ('COMPILE) on the property list of the procedure type.
If desired, uncompiled functions already resident may be compiled by
using
Compile
Compile _____ __ ____ ___ ____
(Compile NAMES:id-list): any expr
18.2.2. Compiling Functions into FASL Files
18.2.2. Compiling Functions into FASL Files
18.2.2. Compiling Functions into FASL Files
Load FaslIn
Load FaslIn
In order to produce files that may be input using Load or FaslIn, the
FaslOut FaslEnd
FaslOut FaslEnd
FaslOut and FaslEnd pair may be used in RLISP mode:
FaslOut
FaslOut ____ ______ ___ ____
(FaslOut FILE:string): NIL expr
_______________
1
Many of the recent extensions to the PLC were implemented by John
Peterson.
PSL Manual 7 February 1983 Compiler and Loader
section 18.2 page 18.3
FaslEnd
FaslEnd ___ ____
(FaslEnd ): NIL expr
FaslOut
FaslOut
After the command FaslOut has been given, all subsequent
S-expressions and function definitions typed in or input from
files are processed by the Compiler, LAP and FASL as needed, and
____
output to FILE. Functions are compiled and partially assembled,
and output as in a compressed binary form, involving blocks of
code and relocation bits. This activity continues until the
FaslEnd
FaslEnd
function FaslEnd terminates this process.
FaslOut FaslEnd
FaslOut FaslEnd
The FaslOut and FaslEnd pair also use the DFPRINT!* mechanism, turning on
the switch !*DEFN, and redefining DFPRINT!* to trap the parsed input in the
RLISP top-loop. Currently this is not useable from pure LISP level.
[??? Fix, by adding !*DEFN mechanism to basic top-loop. ???]
[??? Fix, by adding !*DEFN mechanism to basic top-loop. ???]
[??? Fix, by adding !*DEFN mechanism to basic top-loop. ???]
18.2.3. Loading FASL Files
18.2.3. Loading FASL Files
18.2.3. Loading FASL Files
Two convenient procedures are available for loading FASL files (.b files
on the VAX); see Section 18.2.2 for information on producing FASL files.
Load
Load ____ ______ __ ___ _____
(Load [FILE:{string, id}]): NIL macro
____
Each FILE is converted into a file name of the form
"/u/local/lib/psl/file.b" on the VAX, "pl:file.b" on the DEC-20.
FaslIn
FaslIn
An attempt is made to execute the function FaslIn on it. Once
____
loaded, the symbol FILE is added to the GLOBAL variable
OPTIONS!*.
FaslIn
FaslIn ________ ______ ___ ____
(FaslIn FILENAME:string): NIL expr
This is an efficient binary read loop, which fetches blocks of
__
code, constants and compactly stored ids. It uses a bit-table to
relocate code and to identify special LISP-oriented constructs.
________
FILENAME must be a complete file name.
ReLoad
ReLoad ____ ______ __ ___ _____
(ReLoad [FILE:{string,id}]): NIL macro
Removes the filename from the list OPTIONS!* and executes the
Load
Load
function Load.
Imports
Imports ___________ ____ ___ ____
(Imports MODULENAMES:list): NIL expr
LOAD
___________ __ LOAD
MODULENAMES is a list of ids representing modules to be LOAD'ed
after the module containing this function has been loaded.
Imports
Imports
Imports works only in compiled code.
Compiler and Loader 7 February 1983 PSL Manual
page 18.4 section 18.2
__________ ______
LOADDIRECTORIES!* [Initially: A list of strings] global
Contains a list of strings to append to the front of file names
Load
Load
given in Load commands. This list may be one of the following,
if your system is an Apollo, Dec-20, or Vax:
("" "/utah/psl/lap/")
("" "pl:")
("" "/usr/local/src/cmd/psl/dist/lap/")
__________ ______
LOADEXTENSIONS!* [Initially: An a-list] global
Contains an a-list of (str . fn) in which the str is an extension
to append to the end of the filename and fn is a function to
apply. The a-list contains
((".b" . FaslIn)(".lap" . LapIn)(".sl" . LapIN))
[??? Describe FASL format in more detail ???]
[??? Describe FASL format in more detail ???]
[??? Describe FASL format in more detail ???]
18.2.4. Functions to Control the Time When Something is Done
18.2.4. Functions to Control the Time When Something is Done
18.2.4. Functions to Control the Time When Something is Done
Which expressions are evaluated during compilation ONLY, which output to
the file for LOAD TIME evaluation, and which do both (such as macro
definitions) can be controlled by the properties 'EVAL and 'IGNORE on
certain function names, or the following functions.
CommentOutCode
CommentOutCode _ ____ ___ _____
(CommentOutCode U:form): NIL macro
_
Comment out a single expression; use <<U>> to comment out a block
of code.
CompileTime
CompileTime _ ____ ___ ____
(CompileTime U:form): NIL expr
_
Evaluate the expression U at compile time only, such as defining
auxiliary smacros and macros that should not go into the file.
Certain functions have the FLAG 'IGNORE on their property lists
to achieve the same effect. E.g. FLAG('(LAPOUT LAPEND),'IGNORE)
has been done.
BothTimes
BothTimes _ ____ _ ____ ____
(BothTimes U:form): U:form expr
Evaluate at compile and load time. This is equivalent in effect
Flag
Flag
to executing Flag('(f1 f2),'EVAL) for certain functions.
PSL Manual 7 February 1983 Compiler and Loader
section 18.2 page 18.5
LoadTime
LoadTime _ ____ _ ____ ____
(LoadTime U:form): U:form expr
Evaluate at load time only. Should not even compile code, just
pass direct to file.
[??? EVAL and IGNORE are for compatibility, and enable the above sort
[??? EVAL and IGNORE are for compatibility, and enable the above sort
[??? EVAL and IGNORE are for compatibility, and enable the above sort
of functions to be easily written. The user should AVOID EVAL and
of functions to be easily written. The user should AVOID EVAL and
of functions to be easily written. The user should AVOID EVAL and
IGNORE flags, if Possible ???]
IGNORE flags, if Possible ???]
IGNORE flags, if Possible ???]
18.2.5. Order of Functions for Compilation
18.2.5. Order of Functions for Compilation
18.2.5. Order of Functions for Compilation
____
____
____
expr
expr
Non-expr procedures must be defined before their use in a compiled
function, since the compiler treats the various function types differently.
_____ _____
_____ _____
_____ _____
Macro fexpr
Macro fexpr
Macros are expanded and then compiled; the argument list fexprs quoted; the
_____
_____
_____
nexpr
nexpr
arguments of nexprs are collected into a single list. Sometimes it is
convenient to define a Dummy version of the function of appropriate type,
to be redefined later. This acts as an "External or Forward" declaration
of the function.
[??? Add such a declaration. ???]
[??? Add such a declaration. ???]
[??? Add such a declaration. ???]
18.2.6. Fluid and Global Declarations
18.2.6. Fluid and Global Declarations
18.2.6. Fluid and Global Declarations
The FLUID and GLOBAL declarations must be used to indicate variables that
are to be used as non-LOCALs in compiled code. Currently, the compiler
defaults variables bound in a particular procedure to LOCAL. The effect of
this is that the variable only exists as an "anonymous" stack location; its
name is compiled away and called routines cannot see it (i.e. they would
have to use the name). Undeclared non-LOCAL variables are automatically
declared FLUID by the compiler with a warning. In many cases, this means
that a previous procedure that bound this variable should have known about
this as a FLUID. Declare it with FLUID, below, and recompile, since the
caller cannot be automatically fixed.
[??? Should we provide an !*AllFluid switch to make the default Fluid,
[??? Should we provide an !*AllFluid switch to make the default Fluid,
[??? Should we provide an !*AllFluid switch to make the default Fluid,
or should we make Interpreter have a LOCAL variable as default, or both
or should we make Interpreter have a LOCAL variable as default, or both
or should we make Interpreter have a LOCAL variable as default, or both
???]
???]
???]
Fluid
Fluid _____ __ ____ ___ ____
(Fluid NAMES:id-list): any expr
Declares each variable FLUID (if not previously declared); this
Prog
Prog
means that it can be used as a Prog LOCAL, or as a parameter. On
entry to the procedure, its current value is saved on the Binding
Stack (BSTACK), and all access is always to the VALUE cell
Throw Error
Throw Error
(SYMVAL) of the variable; on exit (or Throw or Error), the old
values are restored.
Compiler and Loader 7 February 1983 PSL Manual
page 18.6 section 18.2
Global
Global _____ __ ____ ___ ____
(Global NAMES:id-list): any expr
Declares each variable GLOBAL (if not previously declared); this
means that it cannot be used as a LOCAL, or as a parameter.
Access is always to the VALUE cell (SYMVAL) of the variable.
[??? Should we eliminate GLOBALs ???]
[??? Should we eliminate GLOBALs ???]
[??? Should we eliminate GLOBALs ???]
18.2.7. Switches Controlling Compiler
18.2.7. Switches Controlling Compiler
18.2.7. Switches Controlling Compiler
The compilation process is controlled by a number of switches, as well as
the above declarations and the !*COMP switch, of course.
__________ ______
!*R2I [Initially: T] switch
T
T
If T, causes recursion removal if possible, converting recursive
calls on a function into a jump to its start. If this is not
possible, it uses a faster call to its own "internal" entry,
rather than going via the Symbol Table function cell. The effect
in both cases is that tracing this function does not show the
internal or eliminated recursive calls, nor the backtrace
information.
__________ ______
!*NOLINKE [Initially: NIL] switch
T NIL
T NIL
If T, inhibits use of !*LINKE cmacro. If NIL, "exit" calls on
functions that would then immediately return. For example, the
calls on FOO(x) and FEE(X) in
PROCEDURE DUM(X,Y);
IF X=Y THEN FOO(X) ELSE FEE(X+Y);
can be converted into direct JUMP's to FEE or FOO's entry point.
This is known as a "tail-recursive" call being converted to a
jump. If this happens, there is no indication of the call of DUM
on the backtrace stack if FEE or FOO cause an error.
__________ ______
!*ORD [Initially: NIL] switch
T
T
If T, forces the compiler to compile arguments in Left-Right
Order, even though more optimal code can be generated.
[??? !*ORD currently has a bug, and may not be fixed for some
[??? !*ORD currently has a bug, and may not be fixed for some
[??? !*ORD currently has a bug, and may not be fixed for some
time. Thus do NOT depend on evaluation order in argument
time. Thus do NOT depend on evaluation order in argument
time. Thus do NOT depend on evaluation order in argument
lists ???]
lists ???]
lists ???]
PSL Manual 7 February 1983 Compiler and Loader
section 18.2 page 18.7
__________ ______
!*MODULE [Initially: NIL] switch
Indicates block compilation (a future extension of this
compiler). When implemented, even more function and variable
names are "compiled away".
The following switches control the printing of information during the
compilation process:
__________ ______
!*PWRDS [Initially: NIL] switch
T
T
If T, causes the compiled size to be printed in the form
*** NAME: base NNN, length MMM
The base is in octal, the length is in current Radix.
[??? more mnemonic name ???]
[??? more mnemonic name ???]
[??? more mnemonic name ???]
__________ ______
!*PLAP [Initially: NIL] switch
T
T
If T, causes the printing of the portable cmacros produced by the
the compiler.
Most of this information is printed by the resident LAP, and controlled
by its switches, described below.
18.2.8. Differences between Compiled and Interpreted Code
18.2.8. Differences between Compiled and Interpreted Code
18.2.8. Differences between Compiled and Interpreted Code
The following just re-iterates some of the points made above and in other
Sections of the manual regarding the "obscure" differences that compilation
introduces.
[??? This needs some careful work, and perhaps some effort to reduce
[??? This needs some careful work, and perhaps some effort to reduce
[??? This needs some careful work, and perhaps some effort to reduce
the list of differences ???]
the list of differences ???]
the list of differences ???]
In the process of compilation, many functions are open-coded, and hence
cannot be redefined or traced in the compiled code. Such functions are
noted to be OPEN-CODED in the manual. If called from compiled code, the
call on an open-compiled function is replaced by a series of online
instructions. Most of these functions have some sort of indicator on their
property lists: 'OPEN, 'ANYREG, 'CMACRO, 'COMPFN, etc. For example: SETQ,
CAR, CDR, COND, WPLUS2, MAP functions, PROG, PROGN, etc. Also note that
_____
_____
_____
macro
macro
some functions are defined as macros, which convert to some other form
(such as PROG), which itself might compile open.
Some optimizations are performed that cause inaccessible or redundant
code to be removed, e.g. 0*foo(x) could cause foo(x) not to be called.
Compiler and Loader 7 February 1983 PSL Manual
page 18.8 section 18.2
_____ ______
_____ ______
_____ ______
Fluid global
Fluid global
Unless variables are declared (or detected) to be Fluid or global, they
_____
_____
_____
local
local
are compiled as local variables. This causes their names to disappear, and
so are not visible on the Binding Stack. Further more, these variables are
NOT available to functions called in the dynamic scope of the function
containing their binding.
_____ _____ _____
_____ _____ _____
_____ _____ _____
macro fexpr nexpr
macro fexpr nexpr
Since compiled calls on macros, fexprs and nexprs are different from the
____
____
____
expr
expr
default exprs, these functions must be declared (or defined) before
_____ _____
_____ _____
_____ _____
fexpr nexpr
fexpr nexpr
compiling the code that uses them. While fexprs and nexprs may
_____
_____
_____
macro
macro
subsequently be redefined (as new functions of same type), macros are
executed by the compiler to get the replacement form, which is then
compiled. The interpreter of course picks up the most recent definition of
ANY function, and so functions can switch type as well as body.
[??? If we expand macros at PUTD time, then this difference will go
[??? If we expand macros at PUTD time, then this difference will go
[??? If we expand macros at PUTD time, then this difference will go
away. ???]
away. ???]
away. ???]
As noted above, the !*R2I, !*NOLINKE and !*MODULE switches cause certain
functions to call other functions (or themselves usually) by a faster route
(JUMP or internal call). This means that the recursion or call may not be
visible during tracing or backtrace.
18.2.9. Compiler Errors
18.2.9. Compiler Errors
18.2.9. Compiler Errors
A number of compiler errors are listed below with possible explanations
of the error.
*** Function form converted to APPLY
Car
Car
This message indicates that the Car of a form is either
a. Non-atomic,
b. a local variable, or
c. a global or fluid variable.
The compiler converts (F X1 X2 ...), where F is one of the above, to (APPLY
F (LIST X1 X2 ...)).
*** NAME already SYSLISP non-local
This indicates that NAME is either a WVAR or WARRAY in SYSLISP mode, but is
being used as a local variable in LISP mode. No special action is taken.
*** WVAR NAME used as local
This indicates that NAME is a WVAR, but is being used as a bound variable
in SYSLISP mode. The variable is treated as an an anonymous local variable
within the scope of its binding.
PSL Manual 7 February 1983 Compiler and Loader
section 18.2 page 18.9
*** NAME already SYSLISP non-local
This indicates that a variable was previously declared as a SYSLISP WVAR or
WARRAY and is now being used as a LISP fluid or global. No special action
is taken.
*** NAME already LISP non-local
This indicates that a variable was previously declared as a LISP fluid or
global and is now being used as a SYSLISP WVAR or WARRAY. No special
action is taken.
*** Undefined symbol NAME in Syslisp, treated as WVAR
A variable was encountered in SYSLISP mode which is not local nor a WVAR or
WARRAY. The compiler declares it a WVAR. This is an error, all WVARs
should be explicitly declared.
*** NAME declared fluid
A variable was encountered in LISP mode which is not local nor a previously
declared fluid or global. The compiler declares it fluid. This is
sometimes an error, if the variable was used strictly locally in an earlier
function definition, but was intended to be bound non-locally. All fluids
should be declared before being used.
18.3. The Loader
18.3. The Loader
18.3. The Loader
[??? update ???]
[??? update ???]
[??? update ???]
Currently, PSL on the DEC-20 provides a simple LISP assembler, LAP. This
is modeled after the original LISP 1.6 LAP, although completely
reimplemented to take advantage of PSL constructs, and to support the
additional requirements of SYSLISP. In the process of implementing the VAX
LAP and developing the LAP-to-ASM translator required to bootstrap PSL onto
the next machine (Apollo MC68000), a much more table-driven form of LAP was
designed to make all LAP's, LAP-to-ASM's and FASL's (fast loaders,
sometimes called FAP) easier to maintain. This is now in use on the VAX
and being used to implement Apollo PSL.
[??? FASL now works ???]
[??? FASL now works ???]
[??? FASL now works ???]
Until that is complete, we will briefly describe the available functions,
and give a sample of current and future LAP; this Section will be
completely rewritten in the next revision. LAP is currently a full two
pass assembler; on the VAX and Apollo it also includes a pass to optimize
long and short jumps.
Compiler and Loader 7 February 1983 PSL Manual
page 18.10 section 18.3
LAP
LAP ____ ____ ____ _______ ____
(LAP CODE:list): code-pointer expr
____
CODE is a list of legal LAP forms, including:
a. Machine specific Mnemonics (using opcode-names from the
assembler on the DEC-20, VAX or Apollo).
b. Compiler cmacros (which expand in a machine specific way).
These can be thought of as "generic" or LISP-oriented
instructions. See the next Section on the Compiler details, and
list of legal cmacros.
c. LAP pseudo instructions, to declare entry points, indicate data
and constants, etc.
The first pass of LAP converts mnemonics into LISP integers, doing as
much of the assembly as possible, allocating labels and constants. The
second (and third?) pass fills in labels and completes the assembly,
depositing code into the next available locations in BPS, or creating FASL
or LAP files.
[??? What is BPS (binary program space) ???]
[??? What is BPS (binary program space) ???]
[??? What is BPS (binary program space) ???]
18.3.1. Legal LAP Format and Pseudos
18.3.1. Legal LAP Format and Pseudos
18.3.1. Legal LAP Format and Pseudos
[??? Describe LAP format in detail ???]
[??? Describe LAP format in detail ???]
[??? Describe LAP format in detail ???]
18.3.2. Examples of LAP for DEC-20, VAX and Apollo
18.3.2. Examples of LAP for DEC-20, VAX and Apollo
18.3.2. Examples of LAP for DEC-20, VAX and Apollo
The following is a piece of VAX specific LAP, using the current "new"
format. Apart from the VAX mnemonics, notice the extra tags around the
register names, and the symbols to indicate addressing modes (essentially
PREFIX syntax rather then INFIX @ etc.). This is from PV:APPLY-LAP.RED.
Note they are almost ENTIRELY written in cmacros, to aid in re-coding for
the next machine.
PSL Manual 7 February 1983 Compiler and Loader
section 18.3 page 18.11
lap '((!*entry FastApply expr 0)
%. Apply with arguments loaded
% Called with arguments in the registers and functional form in t1
(!*FIELD (reg t2) (reg t1)
(WConst TagStartingBit) (WConst TagBitLength))
(!*FIELD (reg t1) (reg t1)
(WConst InfStartingBit) (WConst InfBitLength))
(!*JUMPNOTEQ (Label NotAnID) (reg t2) (WConst ID))
(!*WTIMES2 (reg t1) (WConst AddressingUnitsPerFunctionCell))
(!*JUMP (MEMORY (reg t1) (WArray SymFnc)))
NotAnID
(!*JUMPNOTEQ (Label NotACodePointer) (reg t2) (WConst CODE))
(!*JUMP (MEMORY (reg t1) (WConst 0)))
NotACodePointer
(!*JUMPNOTEQ (Label IllegalFunctionalForm) (reg t2) (WConst
(!*MOVE (MEMORY (reg t1) (WConst 0)) (reg t2))
% CAR with pair already unta
(!*JUMPNOTEQ (Label IllegalFunctionalForm) (reg t2) (QUOTE L
(!*MOVE (reg t1) (reg t2)) % put lambda form in t2
(!*PUSH (QUOTE NIL)) % align stack
(!*JCALL FastLambdaApply)
IllegalFunctionalForm
(!*MOVE (QUOTE "Illegal functional form in Apply") (reg 1))
(!*MOVE (reg t1) (reg 2))
(!*CALL List2)
(!*JCALL StdError)
);
lap '((!*entry UndefinedFunction expr 0)
%. Error Handler for non code
% Called by JSB
%
(subl3 (immediate (plus2 (WArray SymFnc) 6))
(autoincrement (reg st))
(reg t1))
(divl2 6 (reg t1))
(!*MKITEM (reg t1) (WConst ID))
(!*MOVE (reg t1) (reg 2))
(!*MOVE (QUOTE "Undefined function %r called from compiled c
(reg 1))
(!*CALL BldMsg)
(!*JCALL StdError)
);
The following is a piece of Apollo specific LAP, using the current NEW
format. Apart from the MC68000 mnemonics, notice the extra tags around the
register names, and the symbols to indicate addressing modes (essentially
PREFIX syntax rather then INFIX @ etc.). This is from P68:M68K-USEFUL-
LAP.RED.
Compiler and Loader 7 February 1983 PSL Manual
page 18.12 section 18.3
% Signed multiply of 32 bits numbers in A1 and A2,
% returns 64 bits in A1 and A2, low in A1 high in A2
% Clobbers D1,D2,D3,D4,D5,D6,D7, no saving
% [Can insert MOVEM!.L D1-D7,-(SP)
% and MOVEM!.L (SP)+,D1-D7]
LAP '((!*entry Mult32 expr 2) % Arguments in A1 and A2
(move!.l (reg a1) (reg d1))
(move!.l (reg a1) (reg d6))
(move!.l (reg a2) (reg d2))
(move!.l (reg a2) (reg d7)) % Need copies
% Now do Unsigned Multiply
(move!.l (reg d1) (reg d3))
(move!.l (reg d1) (reg d4))
(swap (reg d4))
(move!.l (reg d2) (reg d5))
(swap (reg d5)) % Swapped for partial products
(mulu!.w (reg d2) (reg d1)) % partial products (pp1)
(mulu!.w (reg d4) (reg d2)) % pp2
(mulu!.w (reg d5) (reg d3)) % pp3
(mulu!.w (reg d5) (reg d4)) % pp4
(swap (reg d1)) % sum1=pp#2low+pp#1hi
(add (reg d2) (reg d1))
(clr!.l (reg d5))
(addx!.l (reg d5) (reg d4)) % propagate carry
(add (reg d3) (reg d1)) % sum2=sum1+pp#3low
(addx!.l (reg d5) (reg d4)) % carry inot pp#4
(swap (reg d1)) % low order product
(clr (reg d2))
(swap (reg d2))
(clr (reg d3))
(swap (reg d3))
(add!.l (reg d3) (reg d2)) % Sum3=pp2low+pp3Hi
(add!.l (reg d4) (reg d2)) % Sum4=Sum3+pp4
% Now do adjustment
(tst!.l (reg d7)) % Negative
(bpl!.s chkd6) % nope
(sub!.l (reg d6) (reg d2)) % Flip
chkd6
(tst!.l (reg d6)) % Negative
(bpl!.s done) % nope
(sub!.l (reg d7) (reg d2)) % Flip
done
(movea!.l (reg d1) (reg a1)) % low part
(movea!.l (reg d2) (reg a2)) % high part
(rts));
PSL Manual 7 February 1983 Compiler and Loader
section 18.3 page 18.13
18.3.3. Lap Switches
18.3.3. Lap Switches
18.3.3. Lap Switches
The following switches control the printing of information from LAP and
other optional behavior of LAP:
__________ ______
!*PLAP [Initially: NIL] switch
Causes LAP forms to printed before expansion. Used mainly to see
output of compiler before assembly.
__________ ______
!*PGWD [Initially: NIL] switch
Causes LAP to print the actual DEC-20 mnemonics and corresponding
assembled instruction in octal, displaying OPCODE, REGISTER,
INDIRECT, INDEX and ADDRESS fields.
__________ ______
!*PWRDS [Initially: T] switch
Prints a LAP message of the form
*** NAME: base NNN, length MMM
The base is in octal, the length is in current Radix.
__________ ______
!*SAVECOM [Initially: T] switch
If T, the LAP is deposited in BPS, and the returned Code-Pointer
used to (re)define the procedure associated with the (!*entry
name type n).
__________ ______
!*SAVEDEF [Initially: NIL] switch
If T, and if !*SAVECOM is T, saves any preexisting procedure
definition under '!*SAVEDEF on the property list of the procedure
name, "just in case".
LAP also uses the following indicators on property lists:
'MC Cmacros and some mnemonics have associated PASS1 expansions in
terms of simpler instructions or operations. The form (mc a1 ...
an) has its associated function applied to (a1 ... an).
For more details, see "P20:LAP.RED".
Compiler and Loader 7 February 1983 PSL Manual
page 18.14 section 18.4
18.4. Structure and Customization of the Compiler
18.4. Structure and Customization of the Compiler
18.4. Structure and Customization of the Compiler
The following is a brief summary of the compiler structure and model.
The purpose of this Section is to aid the user to add new compilation
forms, and to understand the task of bootstrapping a new version of PSL.
The original paper on the Portable LISP Compiler [Griss 81] has complete
details on the original version of the compiler, and should be read in
conjunction with this Section. It might be useful to also examine the
paper on recent work on the compiler [Griss 82].
[??? This needs a LOT of work ???]
[??? This needs a LOT of work ???]
[??? This needs a LOT of work ???]
The compiler is basically three-pass:
______
______
______
macros
macros
a. The first pass expands ordinary macros, and compiler specific
cmacros. It also uses some special purpose 'PA1REFORM and
'PA1FN functions on the property lists of certain functions to
produce a simpler and more explicit LISP for the next pass.
Variables and constants, x, are explicitly tagged as (FLUID x),
(GLOBAL x), (QUOTE x), (WCONST x), etc.
b. The second pass recursively compiles the code, using 'COMPFN's
to handle special cases, and the recursive function !&COMPILE
for the general case. In general, code is compiled to cause
function arguments to be loaded into R1...Rn in order, a CALL to
the function to be made, and the returned value to appear in R1.
Temporaries and function arguments to be reused later are saved
on the stack. The compiler allocates a single FRAME for the
maximum stack space that might be needed, and then trims it down
in the third pass. PSL requires registers R1 ... R15, though
not all need be "REAL registers"; the extra are simulated as
memory locations. Special cases avoid a lot of LOAD/STORES to
move arguments around. The compiled code is emitted as a
sequence of abstract LISP machine cmacros. The current set of
cmacros is described below.
c. The third pass scans the list of cmacros for patterns, removing
LOADs and STOREs, redundant JUMP's and LABEL's, compressings the
stack frame, and possibly mapping temporaries stored on the
stack into any of the REAL registers that would otherwise be
unused. This optimized cmacro list is then passed to LAP.
18.5. First PASS of Compiler
18.5. First PASS of Compiler
18.5. First PASS of Compiler
PSL Manual 7 February 1983 Compiler and Loader
section 18.5 page 18.15
18.5.1. Tagging Information
18.5.1. Tagging Information
18.5.1. Tagging Information
This affects many parts of the compiler. The basic idea is that all
information is to be tagged. These tags fit in three categories: variable
tags, location (register and frame) tags, and constant tags. Tags used for
variables must be flagged 'VAR; tags for constants must be flagged 'CONST.
Currently, the register tag is REG and the frame tag is FRAME. Frame
locations are always positive integers.
These tags are used everywhere; thus, register 1 is always described by
(REG 1) in both emitted cmacros and internally in the register list REGS.
Pass 1 tags all variable references with a source to source transformation
of the variables (suitably obscure names must be used for these tags to
prevent conflicts with named functions).
The purpose behind this tagging is to make the compiler easier to work
with in adding new features; new notions of registers, constants, and
variables can all be accommodated through new tags. Also, the components
of the cmacros are more clearly identified for pass 3.
18.5.2. Source to Source Transformations
18.5.2. Source to Source Transformations
18.5.2. Source to Source Transformations
A PA1REFORMFN has been provided to augment PA1FN's. The only difference
between these functions is that the PA1REFORM function is passed code which
has already been through PASS1. This was previously done by calling pass 1
within a PA1FN.
18.6. Second PASS - Basic Code Generation
18.6. Second PASS - Basic Code Generation
18.6. Second PASS - Basic Code Generation
18.6.1. The Cmacros
18.6.1. The Cmacros
18.6.1. The Cmacros
The compiler second pass compiles the input LISP into a series of
abstract machine instructions, called cmacros. These are instructions for
a LISP-oriented Register machine.
___ _______ ______ _______
The current DEC-20 cmacros
Definitions of arguments
reg: (REG n) n = 1,2,... MAXNARGS
var: frame | (GLOBAL name) | (FLUID name)
frame: (FRAME n) n = 0,1,2, ..
const: (QUOTE value) | (WCONST value)
label: (LABEL symbol)
regn: reg | NIL | frame
regf: reg | frame
loc: reg | var | const
Compiler and Loader 7 February 1983 PSL Manual
page 18.16 section 18.6
anyreg: (CAR anyreg) | (CDR anyreg) | loc
Basic Cmacros for LISP and SYSLISP
(!*ALLOC nframe)
(!*DEALLOC nframe)
(!*ENTRY fname ftype nargs)
(!*EXIT nframe)
(!*FREERSTR (NONLOCALVARS f1 f2 ...))
(!*JUMP label)
(!*JUMPxx label loc loc')
where xx = ATOM, EQ, NOTEQ, NOTTYPE, PAIRP, TYPE
(!*JUMPON lower upper (label-1 ... Label-n))
(!*LINK fname ftype nargs)
(!*LINKE nframe fn type nargs)
(!*LINKF nargs reg) where reg contains the function name,
nargs an integer
(!*LINKEF nframe nargs reg) %/ ?
(!*LBL label)
(!*LAMBIND (REGISTERS reg1 reg2 ...) (NONLOCALVARS f1 f2 ...))
where f1, f2, ... = (FLUID name )
No frame location will be allocated (depends on switch)
(!*LOAD reg anyreg)
(!*PROGBIND (NONLOCALVARS f1 f2 ...))
(!*PUSH reg)
(!*RPLACA regf loc)
(!*RPLACD regf loc)
(!*STORE regn var) | (!*STORE regn reg)
SYSLISP oriented Cmacros
(!*ADDMEM loc)
(!*ADJSP ?)
(!*DECMEM loc)
(!*INCMEM loc)
(!*INTINF loc)
(!*JUMPWGEQ label loc loc')
(!*JUMPWGREATERP label loc loc')
(!*JUMPWITHIN label loc loc')
(!*JUMPWLEQ label loc loc')
(!*JUMPWLESSP label loc loc')
(!*MKITEM loc loc')
(!*MPYMEM loc loc')
(!*NEGMEM loc)
(!*SUBMEM loc loc')
(!*WAND loc loc')
(!*WDIFFERENCE loc loc')
(!*WMINUS loc)
(!*WNOT loc)
(!*WOR loc loc')
(!*WPLUS2 loc loc')
(!*WSHIFT loc loc')
(!*WTIMES2 loc loc')
PSL Manual 7 February 1983 Compiler and Loader
section 18.6 page 18.17
(!*WXOR loc loc')
_____ _______
68000 Cmacros
Basic LISP and SYSLISP Cmacros
(!*ALLOC nframe)
(!*CALL fname)
(!*DEALLOC nframe)
(!*ENTRY fname ftype nargs)
(!*EXIT nframe)
(!*JCALL fname)
(!*JUMP label)
(!*JUMPEQ label loc loc')
(!*JUMPINTYPE label type)
(!*JUMPNOTEQ label loc loc')
(!*JUMPNOTINTYPE label loc type)
(!*JUMPNOTTYPE label loc type)
(!*JUMPTYPE label loc type)
(!*LAMBIND label loc loc')
(!*LBL label)
(!*LINK fname ftype nargs)
(!*LINKE fname ftype nargs nframe)
(!*MOVE loc loc')
(!*PROGBIND label loc loc')
(!*PUSH loc)
SYSLISP specific Cmacros
(!*APOLLOCALL label loc loc')
(!*ASHIFT loc loc')
(!*FIELD loc loc')
(!*FOREIGNLINK loc loc')
(!*INF loc loc')
(!*JUMPON loc loc')
(!*JUMPWGEQ loc loc')
(!*JUMPWGREATERP loc loc')
(!*JUMPWITHIN loc loc')
(!*JUMPWLEQ loc loc')
(!*JUMPWLESSP loc loc')
(!*LOC loc loc')
(!*MKITEM loc loc')
(!*PUTFIELD loc loc')
(!*PUTINF loc loc')
(!*PUTTAG loc loc')
(!*SIGNEDFIELD loc loc')
(!*TAG loc loc')
(!*WAND loc loc')
(!*WDIFFERENCE loc loc')
(!*WMINUS loc loc')
(!*WNOT loc loc')
(!*WOR loc loc')
Compiler and Loader 7 February 1983 PSL Manual
page 18.18 section 18.6
(!*WPLUS2 loc loc')
(!*WSHIFT loc loc')
(!*WTIMES2 loc loc')
(!*WXOR loc loc')
18.6.2. Classes of Functions
18.6.2. Classes of Functions
18.6.2. Classes of Functions
The compiler groups functions into four basic classes:
a. ANYREG functions. No side effects and can be done in a single
register. Passed directly to CMACROs. Viewed as a form of
"extended addressing" mode.
b. Specially compiled or "OPEN" functions. These are functions
have a special compiling function stored under a 'COMPFN
indicator. While many of these functions are specially coded,
many are written with the aid of supporting patterns; these are
called 'OPENFN or 'OPENTST patterns. Some OPEN functions alter
registers which are in use, allocate new frames or obtain unused
registers. These open functions also include open compilation
of tests.
c. Built-in or 'stable' functions. These functions are called in
the standard fashion by the compiler, but they have properties
which are useful to the compiler and are assumed to always hold.
Currently, a function may be flagged as NOSIDEEFFECT and have
the property DESTROYS, which contains a list of registers
destroyed by the function.
d. All other functions are assumed to be totally random, destroying
every register and causing side effects.
[??? Mark non-random functions of various levels elsewhere ???]
[??? Mark non-random functions of various levels elsewhere ???]
[??? Mark non-random functions of various levels elsewhere ???]
The most important of these categories is the OPEN function. It is hoped
that improved OPEN functions will eliminate the need for temporary
registers to be allocated by the assembler. Most OPEN functions emit
cmacros especially tailored for each function.
18.6.3. Open Functions
18.6.3. Open Functions
18.6.3. Open Functions
[??? Explain how to CODE them ???]
[??? Explain how to CODE them ???]
[??? Explain how to CODE them ???]
There are 3 basic kinds of open function:
a. Test: the destination is a LABEL.
PSL Manual 7 February 1983 Compiler and Loader
section 18.6 page 18.19
b. Value: the result is to be placed in a particular register.
c. Effect: the result is a side effect, and no destination is
needed.
Note that an EFFECT open function does not have a destination. It is not
really a separate class of function, just a separate usage. Example:
(PROGN (SETQ X 0) ... )
- the SETQ is for effect only - could be implemented with a "clear"
instruction.
(FOO (SETQ X 0) ... )
- here the 0 is also placed in a register (the destination register).
The use of OPENTST is also derived from context: in
(COND ((EQ A B) ...))
- EQ is interpreted as a test.
(RETURN (EQ A B))
, though, must have a value. It should be noted that a pseudo
source-source transformation occurs if an OPENTST is called for value:
(RETURN (EQ A B)) ->
(RETURN (COND ((EQ A B) T) (T NIL)))
An OPENTST function always returns T/NIL if called for value. No separate
handling for non test cases is needed (as opposed to the effect/value cases
for normal OPEN funs in which two separate expansions can be supplied)
Also, there are 3 basic issues encountered in generating the code:
a. Bringing arguments into registers as needed.
b. Emitting the actual code.
c. Updating the final register contents.
Initially, the arguments to an open function are removed of all but
ANYREG functions. Thus, these arguments fall into four classes:
a. Registers
b. Memory locations (FLUID, GLOBAL, FRAME, !*MEMORY)
c. Constants
d. ANYREG functions (viewed as extended addressing modes)
Compiler and Loader 7 February 1983 PSL Manual
page 18.20 section 18.6
Also, along with the arguments coming in is the destination (register or
label).
The first step is to replace some arguments by registers by emitting
LOAD's. This step can be controlled by a function, called the adjust
function, which emits LOAD's and replaces the corresponding arguments by
registers. Next, cmacros are emitted. These cmacros are selected through
a pattern which defines the format of the particular OPEN function call.
Note that the pattern is matching the locations of the arguments to the
open function. For example, assume that FOO is OPEN, and the call
(FOO 'A (CDR B) C D)
is encountered. Assume also that B is frame 1, C is frame 2, and D was
found in reg 1.
The argument list being matched is thus
('A (CDR (FRAME 1)) (FRAME 2) (REG 1))
For most purposes, this would be interpreted as (const anyreg mem reg). Of
course, a pattern can use the value of a constant (you might recognize
(!*WPLUS2 1 X) as an increment). Also, the actual register may be
important for register args, especially if one of the args is also the
destination. You would probably emit different code for
(REG 1) := (!*WPLUS2 (REG 2) (REG 3))
than
(REG 1) := (!*WPLUS2 (REG 1) (REG 2))
To avoid a profusion of properties which would be associated with an OPEN
function, two properties of the function name are used to hold all
information associated with OPEN compiling. These properties are OPENFN
and OPENTST.
The OPENFN and OPENTST properties have the following format:
(PATTERN MACRONAME PARAMETERS)
or function name.
The PATTERN field contains either the pattern itself or a pattern name.
__
A pattern name is an id having the PATTERN property. In the following
material, DEST refers to the destination label in an OPENTST and to the
destination register in an OPENFN. If the function is being evaluated for
effect only, DEST is a temporary register which need not be used.
A pattern has the following format:
PSL Manual 7 February 1983 Compiler and Loader
section 18.6 page 18.21
(ADJUST_FN
REG_FN
(P1 M11 M12 M13 ..)
(P2 M21 M22 M23 ..)
...)
The Pi are patterns and Mij are cmacros or pseudo cmacros. ADJUST_FN is a
register adjustment function used to place things in registers as required,
and to factor out basic properties of the function from the pattern. For
example, you almost never could do anything with ANYREG stuff except load
it somewhere (emitting (!*WPLUS2 X (CDR (CAR Y))) directly probably won't
work - you must bring (CDR (CAR Y)) into a reg before further progress can
be made). The most common adjust function is NOANYREG, which replaces
ANYREG stuff with registers. This eliminates the problem of having to test
for ANYREG stuff in the patterns.
Some pattern elements currently supported are:
ANY matches anything
DEST matches the destination register or label
NOTDEST matches any register except the destination
REG matches any register
REGN Any register or 'NIL or a frame location
VAR A LOCAL, GLOBAL, or FLUID variable
MEM A memory address, currently constants + vars (NOT REGS)
ANYREGFN matches an ANYREG function
'literal matches the literal
(p1 p2 ... pn)
matches a field whose components match p1 ... pn
NOVAL matches only if STATUS > 1; must be the first component of a
pattern, consumes no part of the subject.
The cmacros associated with the patterns fall into two classes: actual
cmacros to be emitted and pseudo cmacros which are interpreted by the
compiler. In either case, the components of the cmacros are handled in the
same fashion. The cmacros contain:
Ai replaced by the ith argument to the OPEN function (after
adjustment)
Ti replaced by a temporary register
Li replaced by a temporary label
Pi replaced by corresponding parameter from OPENFN
DEST replaced by the destination register or label (depending on
OPENFN or OPENTST).
FN replaced by the name of the OPEN function
MAC synonym for P1, by convention a cmacro name
'literal
(x1 x2 ... )
xi as above, forms a list
Compiler and Loader 7 February 1983 PSL Manual
page 18.22 section 18.6
The pseudo cmacros currently supported are:
!*DESTROY
!*DESTROY __ __ ____ ______
(!*DESTROY R1, R2, ...): list cmacro
__ __
Remove any register values from R1 ... RN.
!*DO
!*DO ________ ____ ____ ____ ______
(!*DO FUNCTION ARG1 ARG2 ...): list cmacro
________
Call the FUNCTION.
!*SET
!*SET ___ ___ ____ ______
(!*SET REG VAL): list cmacro
___ ___
Set the value in REG to VAL.
The cmacros which are known to the compiler are
!*LOAD
!*LOAD ____ ______
(!*LOAD ): list cmacro
!*STORE
!*STORE ____ ______
(!*STORE ): list cmacro
!*JUMP
!*JUMP ____ ______
(!*JUMP ): list cmacro
!*LBL
!*LBL ____ ______
(!*LBL ): list cmacro
These cmacros have special emit functions which are called as they are
emitted; otherwise the cmacro is directly attached to CODELIST.
18.7. Third PASS - Optimizations
18.7. Third PASS - Optimizations
18.7. Third PASS - Optimizations
The third pass of the compiler is responsible for doing optimizations,
getting rid of extra labels and jumps, removing redundant code, adjusting
the stack frame to squeeze out "holes" or even reallocating temporaries to
excess registers if no "random" functions are called by this function.
This pass also does "peephole" optimizations (controlled by patterns that
examine the Output CMACRO list for cmacros that can be merged). These
tables can be adjusted by the user. This pass also gathers information on
register usage that may be accumulated to aid block compilation or
recompilation of a set of functions that are NOT redefined, and so can use
information about each other (i.e. become "stable").
The 'OPTFN property is used to associate an optimization function with a
particular CMACRO name. This function looks at the CMACRO arguments and
PSL Manual 7 February 1983 Compiler and Loader
section 18.7 page 18.23
some subsequent CMACROs in the code-list, to see if a transformation is
possible. The OPTFN takes a single argument, the code-list in reverse
order starting at the associated CMACRO. The OPTFN can also examine
certain parameters. Currently !*LBL, !*MOVE and !*JUMP have 'OPTFNS. For
example, !&STOPT, associated with !*MOVE, checks if previous CMACRO was
!*ALLOC, and that this !*MOVE moves a register to the slot just allocated.
If so, it converts the !*ALLOC and !*MOVE into a single !*PUSH. Likewise,
!&LBLOPT removes duplicate labels defined at one place, aliasing one with
the other, and so permitting certain JUMP optimizations to take place.
Tags in the cmacros are processed in a final pass through the code. At
this time the compiler can do substitutions using functions attached to
these tags. Currently, (!*FRAMESIZE) is converted to the frame size and
holes are squeezed out (using the FRAME tag) by !&REFORMMACROS.
Transformation functions are attached to tags (or any function) through the
TRANFN property currently.
18.8. Some Structural Notes on the Compiler
18.8. Some Structural Notes on the Compiler
18.8. Some Structural Notes on the Compiler
[??? This Section is very ROUGH, just to give some additional
[??? This Section is very ROUGH, just to give some additional
[??? This Section is very ROUGH, just to give some additional
information in interim ???]
information in interim ???]
information in interim ???]
External variables and properties used by the compiler:
_________ ___ ________
Variables and Switches
__________ ______
!*ERFG [Initially: ] switch
__________ ______
!*INSTALLDESTROY [Initially: NIL] switch
If true, causes the compiler to install the DESTROYS property on
any function compiled which leaves one or more registers
unchanged
__________ ______
!*INT [Initially: T] switch
__________ ______
!*NOFRAMEFLUID [Initially: T] switch
If true, inhibits allocation of frame locations for FLUIDS
__________ ______
!*SHOWDEST [Initially: NIL] switch
If true, compiler prints out which registers a function destroys
unless all are destroyed
Compiler and Loader 7 February 1983 PSL Manual
page 18.24 section 18.8
__________ ______
!*SYSLISP [Initially: NIL] switch
Switch compilation mode from default of LISP to SYSLISP. This
affects constant tagging, and in RLISP also causes LISP functions
to be replaced by SYSLISP equivalents. Also, non-locals default
to WVAR's rather than FLUIDs. See Chapter 20.
__________ ______
!*UNSAFEBINDER [Initially: NIL] switch
for Don's BAKER problem...GC may be called in Binder, so regs
cannot be preserved, and Binder called as regular function.
__________ ______
!*USEREGFLUID [Initially: NIL] switch
If true, LAMBIND and PROGBIND cmacros may contain registers as
well as frame locations (through FIXFRM).
_______
Globals:
__________ ______
LASTACTUALREG [Initially: 5] global
The number of the last real register; FIXFRM does not map stack
locations into registers > LASTACTUALREG. Also, temporary
registers are actual registers if possible.
__________ ______
MAXNARGS [Initially: 15] global
Number of registers
__________ ___ _____
Properties and Flags:
CONST A tag property, indicates tags for constants (WCONST and QUOTE)
EXTVAR A tag property, indicates a variable type whose name is
externally known (!$FLUID, !$GLOBAL, !$WVAR)
MEMMOD A cmacro property, indicates in place memory operations. The
first argument to the cmacro is assumed to be the memory location
(var or !*MEMORY)
NOSIDEEFFECT
A function property, used both in dealing with !*ORD and to
determine if the result should be placed in register status
REG A tag property, indicates a register (REG)
TERMINAL A tag property, indicates terminals (leaves) whose arguments are
not tagged items (!$FLUID !$GLOBAL !$WVAR REG LABEL QUOTE WCONST
FRAME !*FRAMESIZE IREG)
TRANSFER A property of cmacros and functions, indicates cmacros &
functions which cause unconditional transfers (!*JUMP !*EXIT
!*LINKE !*LINKEF ERROR)
PSL Manual 7 February 1983 Compiler and Loader
section 18.8 page 18.25
VAR A tag property, indicates a variable type (!$LOCAL !$FLUID
!$GLOBAL !$WVAR)
__________
Properties:
ANYREG A function property, non-NIL indicates an ANYREG function
CFNTYPE Used in compiler to relate to Recursion-to-iteration conversion.
DESTROYS A function property, contains a (tagged) list of registers
destroyed by the function
DOFN A function property, contains the name of a compile time
evaluation function for numeric arguments.
EMITFN A cmacro or pseudo cmacro property, contains the name of a
special function for emitting (or executing) the cmacro, such as
!&ATTJMP for !*JUMP.
EXITING A cmacro property, used in FIXLINKS. Contains the name of an
associated exiting cmacro (!*LINK : !*LINKE, !*LINKF : !*LINKEF)
FLIPTST A function property, contains the name of the opposite of a test
function. All open compiled test functions must have one. (EQ :
NOTEQ, ATOM : PAIRP)
GROUPOPS A function property, used in constant folding. Attached to the
three functions of a group, always a list of the three functions
in the order +, -, MINUS. (!*WPLUS2, !*WDIFFERENCE, !*WMINUS :
(!*WPLUS2 !*WDIFFERENCE !*WMINUS))
MATCHFN A property attached to an atom in a pattern. Contains the name
of a boolean function for use in pattern matching.
NEGJMP A cmacro property, contains the inverted test jump cmacro name.
(!*JUMPEQ : !*JUMPNOTEQ, !*JUMPNOTEQ : !*JUMPEQ ...)
ONE A function property, contains the (numeric) value of an identity
associated with the function (!*WPLUS2 : 0, !*WTIMES2 : 1, ...)
PATTERN A property associated with atoms appearing in OPENFN or OPENTST
properties, contains a pattern for open coding of functions.
SUBSTFN A property of atoms found in cmacros which are inside patterns.
Contains a function name; the function value is substituted into
the cmacro as emitted.
ZERO Like ONE, designates a value which acts as a 0 in a ring over *.
(!*WTIMES2 : 0 , !*LOGAND : 0)