.\"/*
.\" * Copyright (c) 2017, NVIDIA CORPORATION.  All rights reserved.
.\" *
.\" * Licensed under the Apache License, Version 2.0 (the "License");
.\" * you may not use this file except in compliance with the License.
.\" * You may obtain a copy of the License at
.\" *
.\" *     http://www.apache.org/licenses/LICENSE-2.0
.\" *
.\" * Unless required by applicable law or agreed to in writing, software
.\" * distributed under the License is distributed on an "AS IS" BASIS,
.\" * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
.\" * See the License for the specific language governing permissions and
.\" * limitations under the License.
.\" *
.\" */
.NS 6 Expander
.sh 2 "Overview"
The primary purpose of the expander module is to translate the ILMs produced
by the semantic analyzer into ILIs, the internal language
that is processed by the LLVM-bridge. The LLVM-bridge then
converts the ILI into LLVM Intermediate Representation (IR).
.br
During ILM to ILI translation, the ILIs are grouped into blocks, where the
extent of a block is determined by certain compiler options and the
characteristics of the control flow ILMs.
.lp
For each block, the expander creates a block information header (see later
sections for more detail)
which describes the contents of the block.
In addition, global information is gathered.  This includes:
.ip
a names table reflecting precisely the variables being referenced
(e.g.,
.cw *p ,
.cw st.x ,
.cw a[i] ,
etc.).  These entries are accessed by the 
the ILI which perform loads and stores.
.lp
The expander is separated into language dependent and
language independent modules. The Fortran-specific portions of the
expander are contained in
.i exp_ftn.c .
.sh 2 "Data Structures"
.sh 3 "Global Data Structures Used"
.us "Symbol Table"
described in section 11.
.us "ILMs"
internal representation of executable statements read from
a temporary file into an area used by the semantic analyzer and
the expander.
Refer to section 12 for a general description and appendix IV
for a list of the ILM opcodes and descriptions of their meanings.
.us "Static ILM Information"
Static tables describing the ILM to ILI table driven expansions,
ILM attributes, etc. This information is generated by the
ILMTP
utility.
Refer to section 12 for a general description and appendix IV
for a list of the ILM opcodes and descriptions of their meanings.
.us "ILIs"
internal representation created by the expander which are
shared for an entire source file (across all functions in that source
file). The ILIs are maintained in a single dynamic memory area.
This area is an array of unsigned short ints.
Refer to section 13 for a general description and appendix
V for a list of the ILI opcodes and descriptions of their meanings.
.us "Static ILI Information"
Static tables describing ILI attributes, etc.
This information is generated by the 
ILITP
utility.
Refer to section 13 for a general description and appendix
V for a list of the ILI opcodes and descriptions of their meanings.
.us "ILTs"
internal representation created by the expander which represents
the terminal nodes of an ILI
.q statement .
An ILI statement may
be a function call, a store, register move or a branch.  A sequence of ILTs 
represents a block of ILIs.
.us "BIHs"
block information header table.  Refer to section 13 for a description.
.us "NMEs"
name table entries. Refer to section 13 for a description.
.sh 3 "ILM Area"
This area is a single dynamic memory area (an array of short ints)
used to hold the ILMs
read in for a block. This space is allocated by the
semantic analyzer and freed by the expander.
An additional memory area (an array of structs) is used to store 
auxiliary information
created for an ILM by the Expander.
This area parallels the area used
for reading in ILMs; that is, an index (relative offset from the beginning
of the ILM area) locating an ILM also locates the auxiliary 
structure for that ILM.
After an ILM is expanded, the pointer (actually an
unsigned int offset from the
beginning of the ILI area) to the ILI which is considered the
result of the ILM may be stored in its (the ILMs) auxiliary structure.
This is done for those ILMs which may be 
.q linked
to by other ILMs.
References to an ILM whose result
has been saved is just an indirection through this word.
In addition, for those ILMs which produce an address result
(e.g, a 
.q reference
ILM, a pointer load ILM, etc.),
the index to the
names table entry representing the reference is stored in the
ILM's auxiliary structure.
For certain ILMs (stores and pseudo stores), the ILI block index
(a BIH index) is stored in the auxiliary structure indicating the
ILI block which contains the store or pseudo store ILI for the ILM
(see section 6.3.6, 
.i "Common ILM Expressions" ,
for more details).
Figure 6-1 shows the dependencies of the two areas.
.(b L
.hl
.TS
tab(%);
rw(0.5i)   cw(1.5i)   rw(0.5i)   cw(0.5i)   sw(0.5i)   sw(0.5i)
rw(0.5i)   cw(1.5i)   rw(0.5i)   cw(0.5i)   sw(0.5i)   sw(0.5i)
rw(0.5i) | cw(1.5i) | rw(0.5i) | cw(0.5i)   sw(0.5i)   sw(0.5i) |
rw(0.5i)   cw(1.5i)   rw(0.5i)   cw(0.5i)   sw(0.5i)   sw(0.5i)
rw(0.5i) | cw(1.5i) | rw(0.5i) | cw(0.5i)   sw(0.5i)   sw(0.5i) |
rw(0.5i)   cw(1.5i)   rw(0.5i)   cw(0.5i)   sw(0.5i)   sw(0.5i)
rw(0.5i) | cw(1.5i) | rw(0.5i) | cw(0.5i) | cw(0.5i) | cw(0.5i) |
rw(0.5i)   cw(1.5i)   rw(0.5i)   cw(0.5i)   sw(0.5i)   sw(0.5i)
rw(0.5i) | cw(1.5i) | rw(0.5i) | cw(0.5i)   sw(0.5i)   sw(0.5i) |
rw(0.5i)   cw(1.5i)   rw(0.5i)   cw(0.5i)   sw(0.5i)   sw(0.5i)
rw(0.5i) | cw(1.5i) | rw(0.5i) | cw(0.5i)   sw(0.5i)   sw(0.5i) |
rw(0.5i)   cw(1.5i)   rw(0.5i)   cw(0.5i)   sw(0.5i)   sw(0.5i)
rw(0.5i) | cw(1.5i) | rw(0.5i) | cw(0.5i)   sw(0.5i)   sw(0.5i) |
rw(0.5i)   cw(1.5i)   rw(0.5i)   cw(0.5i)   sw(0.5i)   sw(0.5i)
rw(0.5i) | cw(1.5i) | rw(0.5i) | cw(0.5i)   sw(0.5i)   sw(0.5i) |
rw(0.5i)   cw(1.5i)   rw(0.5i)   cw(0.5i)   sw(0.5i)   sw(0.5i)   .
%ILM Area%%Auxiliary Area
%_%%_
0%%0%
%...%%...
%%%
%_%%_
i%opc%i%ili%nme%blk
%_%%_
%%%
%_%%_
%%%
%_%%_
%%%
%...%%...
%%%
%_%%_
.TE
.TS
tab(%);
L L.
i%index of an ILM
opc%opcode of the ILM
ili%index to the ILI created for the ILM at i
nme%index to the names entry created for the ILM
blk%T{
bih index containing the ili  for the ILM
(see section 6.3.6)
T}
.TE
.ce 1
Figure 6-1.  ILM Areas
.hl
.)b
The following variable, global to the expander module and declared in
the file
.i ilm.h ,
is used to
locate the memory area and to give the size of the area:
.(b
.CS
struct {
    short ilm_base; /* pointer to the memory area */
    short ilm_size; /* size in units of short words */
    short ilmavl;   /* available index (used by semant) */
} ilmb;
.CE
.)b
.lp
A definition for the parallel area occurs in the local expander
data structure (described in the next section).
.lp
While an ILM is being expanded, it may be necessary to temporarily save
pointers to ILI created.
An ILI saved in this fashion is associated with a temporary number.
The area used to remember the ILI is just a static array, local to
the expander module and defined in the local expander data structure.
This array is
indexed by the temporary number,
and is
.i n
words long,
where
.i n
is a number sufficient for
the
temporary locations required by any one ILM macro.
Any references
to a temporary are just indirections through this area.
Note that this number is hard-coded in
.i expand.h
and will have to
be increased if the number of temp locations required by an ILM
exceeds 9.
.sh 3 "Local Expander Data Structure"
The file
.i expand.h
contains
the data structure (the structure
.cw exp )
which is local to the expander module,
and various C macros used to access the values of an ILM and its auxiliary
information.
Details about the structure exp can be obtained by examining the file
.i expand.h .
The ILM macros used by the expander module are:
.np
.cw ILM_OPC(ip) ,
.cw ILM_OPND(ip,j) :
used to extract the opcode and the
.cw j -th
operand of ILM in the ILM area located by
.cw ip .
.cw ip
is an
.i "absolute pointer"
(not an offset) to the ILM.
.np
.cw ILM_RESULT(ix) :
is used to store the result (and index to an ILI) of an
ILM.  The ILM is located by the
.i index
.cw ix
(the offset from the beginning of the ILM area to the ILM in units
of short ints).
.np
.cw NME_RESULT(ix) :
used to store the
.q names
result of an ILM.
.np
.cw ILI_OF(ix) :
used to extract the ILI result of ILM located at index
.cw ix .
.np
.cw NME_OF(ix) :
used to extract the
.q names
result of ILM located at
index
.cw ix .
.np
.cw ILM_BLOCK(ix) :
used to store and extract the block identification
(a BIH index) of the block containing the ILI generated for ILM
.cw ix .
This is used for the ILMs which are stores or pseudo stores.
.sh 2 "Processing"
.sh 3 "Overview"
The Expander module is divided into the following parts:
.nr ii 1.5i
.ip \f(CWexpand\fP
This routine is the main routine of the
.cw expand
module and is the
routine which is called by the Program Controller.
.cw expand
is responsible for reading in an ILM block, processing the terminal
ILMs in that block, and for cleaning up 
after the block has been processed.
.cw expand
processes ILMs by scanning through the ILM blocks
calling
.cw eval_ilm
on the terminal ILMs (an attribute in the static ILM
information).
Refer to Figure 6-2 for a high level description of
.cw expand .
.(z
.hl
.br
.CS

exp_init() ;
while ( not end of ILM file ) {
   rdilms();    /* this routine reads in the BOS ILM,
                   processes the BOS, and then reads
                   in the ILMS in the ILM block */

   for each ILM, located by index ilmx, in the block {
     if ILM is a terminal ILM
        eval_ilm(ilmx);
   }
}
cleanup expand module;
.CE

.ce 1
Figure 6-2.  \fIexpand(\^)\fP
.hl
.)z
.ip \f(CWexp_init\fP
This routine is called by
.cw expand
to initialize the Expander data
items and to allocate space for certain Expander data
structures.
This routine is called immediately before expanding any ILMs for the
source program.
.ip \f(CWeval_ilm\fP
This routine controls the main processing of an ILM.
This routine is called by
.cw expand
when
.cw expand
sees a
.q terminal
ILM. The routine makes recursive calls on the ILMs operands
which are links and have not yet been evaluated (ILI have not been created
for it). If an ILM has already been processed,
.cw check_ilm
is
called to ensure that the ILI originally generated will be 
be used as a common expression (see section 6.3.6, 
.i "Common ILM Expressions" ).
.cw eval_ilm
sets three variables which are static to the expand module
and are used by the various expansion routines:
.cw ilmp
(a pointer,
.i "not an index" ,
to the ILM being evaluated), 
.cw curilm
(the index of the ILM being evaluated),
and
.cw opc
(the opcode of the ILM being evaluated).
Refer to Figure 6-3 for a high level description of the main
expand process.
.ip "expansion routines"
The ILMs are divided into two classes:
.ba +1.5i
.ip \(bu 4n
table driven expansion defined by the ILM macros.
The routine
.cw exp_mac
is responsible for expanding ILMs using the
template or macro information created by the utility ILMTP.
.ip \(bu 4n
special case ILMs.
Several routines are responsible for these ILMs. The ILIs produced
for these ILMs are determined by various conditions as determined
by the routines. Typically, a routine will exist for each of the
ILM types (i.e., reference, branch, load, store, etc.) which are to
be special cased.
.ba -1.5i
.(z
.hl
.br
.CS

/*  evaluate all operands of ilmp  */

for each ILM link operand, opnd, of ilmp
    if opnd has not been processed
        eval_ilm(opnd);
    else
        check_ilm(opnd);

define curilm, ilmp, opc;

/*  evaluate ilmp  */

select processing for ilmp {

case ILM is table driven:
    exp_mac();

/*  the following are special cased ILMS  */

case ILM is type reference:
    exp_ref();
case ILM is type branch:
    exp_bran();
case ILM is type procedure:
    exp_call();
case ILM is type load:
    exp_load();
case ILM is type store:
    exp_store();
case ILM is type arithmetic, constant, or miscellaneous:
    process ILM according to its opcode;
}

.CE
.ce 1
Figure 6-3.  Expand Process
.hl
.)z
.ip "utility routines"
These routines are called by the various expand routines
to perform such functions as reading in a block of ILMs,
creating and completing a basic block of ILI, and
performing certain ILI optimizations, etc.
These routines are found in the file
.cw exputil.c .
.lp
Important expander issues are discussed in the remainder of this
section.
.nr ii 5n
.sh 3 "ILT Blocks"
During expansion, ILT nodes are grouped into a unit called a basic block
or extended basic block.
A basic block of ILT nodes consists of a sequence of ILTs which can only
be entered at the beginning and may be exited only at the end
(it has a single
exit point).
An extended basic block is the same as a basic block except that there
may be more than one exit.
A basic block is formed according to the following rules:
.np
The occurrence of the
.cw LABEL
ILM causes a new block to be created provided 
that the label is referenced (its reference count is greater than zero).
.np
A branch (conditional and unconditional) ends a block.
.np
At opt level 0, at least one basic block is created for one ILM block
(note that an ILM block always begins with a
.cw BOS
ILM).
At opt levels greater than 0, a basic block may span ILM block boundaries.
.np
The operands of an ILI cannot span a block boundary. This can only occur
if the operand of an ILM
is a store or pseudo store ILM (refer to section 6.3.6,
.i "Common ILM Expressions" ).
.(z
.hl
.br
.CS
/*
   previlt - the previous ILT
   curilt  - the current ILT
   curilm  - current ILM being expanded
   optlvl  - opt level selected
*/

-----  curilm is a BOS  -----

if (optlvl==0) {
   wrtilts();		/* save block just created */
   create new block;
   process BOS;
}

-----  curilm is a LABEL  -----

   lbl = label defined by ILM;
   while (previlt is a branch which references lbl) {
      previlt = delilt(previlt);  /* delete this ILT and
				     update previlt */
      rfcnt(lbl)--;
      if (branch deleted was in a jump table) break;
   }
   if (rfcnt(lbl) > 0 ) {
      wrtilts();	/*  save block just created  */
      create new block;
   }
}

-----  curilm is one which creates an ILT  -----

if (curilt is a branch) {
   if (curilt is unconditional && previlt is unconditional){
      if (not in jump table) {
	 delilt(curilt);   /*  the result of delilt is 
			       discarded  */
	 curilt = NULL;
      }
   else {
      wrtilts();
      create new block;
      previlt = curilt;
      curilt = NULL;
   }
}
else {	/*  just add curilt to block  */
   next(previlt) = curilt;
   prev(curilt) = previlt;
   previlt = curilt;
}
.CE
.ce 1
Figure 6-4. ILT Basic Block Creation
.hl
.)z
.lp
Extended basic blocks are created by the expander only at opt level 1.
These blocks are formed
according to the same rules as above except that a branch does not 
terminate an extended basic block (i.e., the block may have more than
one exit point).
.lp
Creating a block
initially involves creating a BIH for it and then adding
ILTs.
Whether an ILT is added to the block or causes a new block to be created
depends on its type and the opt level selected.
An ILT may be one of the following:
.nr ii 1.5i
.ip store
The ILT locates the store ILI created by a store ILM.
.ip branch
The ILT locates the branch ILI created by a branch ILM.
.ip "procedure call"
The ILT locates the function ILI that is called.
The result of the function is either
is type void or is discarded.
This ILT may also be created when an
ILT is deleted (since its expressions
are scanned for function calls),
or when the
.cw ESTMT
ILM is processed.
.ip move
he ILT locates a register move ILI.
.ip "entry/exit"
The ILT locates the entry/exit ILI.
Note that these ILTs are always in their own blocks at opt not equal to 1
or if the option debug was selected.
.nr ii 5n
.lp
After an ILT is created, it is determined if the previous ILT (if one exists)
is a branch. If so, one of four cases occurs:
.np
the previous ILT is an unconditional branch which is not a member of a
switch-jump table. The current ILT is deleted.
.np
the current ILT is an unconditional branch. The previous ILT is deleted
if the target labels are identical.
Function ILTs may be created by this action.
.np
The current ILT is an unconditional branch and the previous ILT is a 
conditional branch.  The creation of the block is delayed until the
next ILM is processed (this is a non-BOS ILM if the opt level is 1).
If the ILM is a
.cw LABEL ,
then the following optimization is performed if
the label is referenced by the conditional branch:
.(b L
.TS
tab(%) allbox;
Cw(2.0i) Cw(2.0i).
T{
.CW
  if (cond) goto y;
  goto x;
y: . . .
.CE
T}%T{
.CW
  if (!cond) goto x;
y: . . .
T}
.TE
.)b
.np
Otherwise, the previous block is complete.
The current ILT becomes the
first ILT of the new block.
.lp
If the previous ILT is not a branch, the current ILT is added to the
current block.
.lp
When a
.cw LABEL
ILM is processed, the following checks are performed:
.np
The above-mentioned optimization (3) occurs if the conditions are satisfied.
In addition, the reference count of the label described
as
.cw x
is decremented. 
If the label is not referenced by the conditional branch and the opt level is
not 1, the ILT for the conditional branch is the last ILT of the current
block.
The ILT for the unconditional branch becomes the first ILT of
the next block.
.np
If (1) does not occur, the previous ILT is checked to determine if
it is some sort of branch to the label.  If so, the ILT is deleted and the
label's reference count is decremented.
Deleting this ILT could cause a function ILT or ILTs to be created
if it is a conditional branch.
.np
If the reference count of the label is greater than zero (this
check is performed regardless of the outcome of (1) or (2)), a new block is
created with the label defining the beginning of the block.
.lp
When a
.cw BOS
ILM is processed and the opt level is zero, a new block
is created whose line number is extracted from the BOS.
Otherwise, the line number is saved away for use by the next block created.
Note that if multiple ILI blocks are created for an ILM block, all but the
first block have their line numbers set to zero.
.sh 4 "Debugger Interface"
<this may change>
.lp
When the debug compiler option is selected, the first ILT of a block which is
neither an entry nor an exit block is a
call to the debugger routine
.cw "dbg$i_line" .
This involves creating an ILI which is a call to the routine and an ILT which
locates this ILI.
Note that this is done for only those blocks which have non-zero line numbers.
.sh 3 "ILM Macro Expansion"
The routine
.cw exp_mac
is responsible for expanding ILMs which
are defined as macros as specified by the ILM template definitions.
This expansion is straightforward and consists of looping through
the template to add the ILI.
All detail can be found in the
code for the routine.
.sh 3 "Reference ILMs"
The routine
.cw exp_ref
expands the reference ILMs (\c
.cw BASE ,
.cw ELEMENT ,
and
.cw MEMBER ).
The ILI generated represent the memory address of
the reference. In addition, a names table entry is created which
represents the reference. The cases are:
.np
.cw "BASE\ sym"
.ba +5n
.lp
The add ILI routine,
.cw addili
(described in section 13), is called
to produce the ILI
.cw "ACON\ sym'"
(where
.cw sym'
is an address constant
whose value is
.cw <sym,0> ).
The final
result of this
.cw ACON
is either the stack offset allocated to
.cw sym
by the code scheduler (if
.cw sym
is automatic or a dummy argument),
or a relative offset allocated by the code
scheduler from the beginning of its psect
(if
.cw sym
is static or external).
.lp
The add names entry routine,
.cw addnme
(described in section 13),
is called to create a names
entry for the
.cw "BASE"
ILM.
.cw addnme
is called with a template which describes
a names entry of type variable (\c
.cw NT_VAR )
whose symbol field is
.cw sym .
This template is described as
.(b
.CS
<NT_VAR, sym, 0, 0>
.CE
.)b
(the last two 0's
represent a names table entry and a constant offset, respectively).
.lp
If
.cw sym
is an argument of type double
(on 32-bit machines), struct, or union, a
.cw LDA
ILI
referencing the
.cw ACON
is also generated which will extract the
argument's address from the argument list.
This is done since double
(on 32-bit machines), struct, and union values passed
to procedures are actually passed in temporaries.
The address
of the temporary is passed and it is as if the formal argument is
a pointer to the double, struct, or union argument.
The names entry created by
.cw addnme
is used in the
.cw LDA .
.ba -5n
.np
.cw "ELEMENT base subs dt"
.ba +5n
.nr PI \n(psu
.nr ps 0
.ip \f(CWbase\fP 6n
is the base ILI of this reference.
.ip \f(CWsubs\fP 6n
is the subscript ILI.
.ip \f(CWdt\fP 6n
is a pointer to the dtype record which represents the data type
of the element and is used to compute the multiplier of
.cw subs .
The multiplier is defined to be the size of each element in units of bytes.
However, for certain machines, it is possible to use a scaling
instruction which will scale a value before adding.
Consequently, two values,
.cw size
(the number of units to scale) and
.cw scl
(the scale factor),
are computed from
.cw dt
using the function
.i scale_of
in the compiler module
.i dtypeutil.c .
The multiplier based on these values is
.cw "size*2\*[scl\*]" .
For a machine which does not have this capability,
.cw size
is the number of bytes in each element and
.cw scl
is 0.
.nr ps \n(PIu
.lp
The handling of
.cw ELEMENT
depends on
.cw subs :
.br
.ne 7v
.ip \(bu 4n
.cw subs
is a constant ILI (let
.cw c
be its value)
.(b
.CS
(1)  ACON c * size
(2)  AADD base (1) scl
.CE
.)b
Note that the constant
.cw c*size
may be folded into base by
.cw addili .
.br
.ne 9v
.ip \(bu 4
subs is
.cw "i + c"
\(em add
.cw c*size
to the base
.(b
.CS
(1)  ACON c * size	The constant may be folded into base.
(2)  AADD base (1) scl
(3)  ICON size
(4)  IMUL i (3)
(5)  DAMV (4)
(6)  AADD (2) (5) scl	i is added to the (new) base.
.CE
.)b
.ne 9v
.ip \(bu 4
subs is
.cw "i - c"
\(em subtract
.cw c*size
from the base
.(b
.CS
(1)  ACON c * size	The constant may be folded into base.
(2)  ASUB base (1) scl
(3)  ICON size
(4)  IMUL i (3)
(5)  DAMV (4)
(6)  AADD (2) (5) scl	i is added to the (new) base.
.CE
.)b
.ne 6v
.ip \(bu 4
otherwise,
.(b
.CS
(1)  ICON size
(2)  IMUL subs (1)
(3)  DAMV (2)
(4)  AADD (3) base scl
.CE
.)b
.lp
.cw addnme
is called with the template
.(b
.CS
<NT_ARR, arr, bnme, cnst>
.CE
.)b
to create
a names entry for the
.cw ARRAY
ILM.
.cw bnme
is the names entry of the base ILI.
.cw arr
and
.cw cnst
combine to indicate if this array reference is one with constant
subscripts.  If
.cw subs
is a constant,
.cw arr
is 0 and
.cw cnst
is the value of the
constant subscript multiplied by size.  Otherwise,
.cw arr
is -1.
.ba -5n
.np
.cw "MEMBER base sym"
.ba +5n
.nr PI \n(psu
.nr ps 0
.ip \f(CWbase\fP 6n
is the base ILI of the reference.
.ip \f(CWsym\fP 6n
is the member symbol table item used to extract its offset
from the beginning of the structure.
.nr ps \n(PIu
.CS
(1)  ACON offset
(2)  AADD base (1) 0
.CE
.lp
The names entry template for the
.cw MEMBER
ILM is
.(b
.CS
<NT_MEM, psmem, bnme, 0> .
.CE
.)b
.cw bnme
is the names entry of the base ILI.
.cw psmem
is the symbol table item which is the value of the pseudo member
field of
.cw sym
(refer to the section,
.i "Symbol Table" ).
.ba -5n
.sh 3 "Loads and Stores"
The ILMs of type load and store perform loads and stores of
.q "variables"
(scalar, array element, structure member) and loads and stores of
structures (the
.cw SMOVE
ILM). The
.q "variable"
ILMs correspond to the C scalar types.
Expanding these types of ILMs to ILIs involves chosing the
ILI which reflects the size of the data type on the
target machine.  
For the ILIs
.cw LD
and
.cw ST
(load and store data register),
an additional operand value is used to denote the size
of the fetch or store. These ILIs are of the form:
.(b
.CS
LD adr sym stc
ST val adr sym stc
.CE
.)b
where
.nr PI \n(psu
.nr ps 0
.ip \f(CWadr\fP 5n
is a link to the address of the load or store
.ip \f(CWsym\fP 5n
is the names table entry of the reference
.ip \f(CWval\fP 5n
is a link to the value being stored
.ip \f(CWsiz\fP 5n
is an immediate constant selecting size.  These are of the form
.cw MSZ_<name>
and are described in the ILI section.
.nr ps \n(PIu
.lp
The remaining ILIs are for loading and storing pointers (\c
.cw PLD
and
.cw PST ),
loading and storing doubles (\c
.cw DLD
and
.cw DST ),
and loading and storing floats (\c
.cw RLD
and
.cw RST )
are of the form:
.(b L
.TS
LfCW LfCW.
LDA/LDDP/LDSP adr sym	PLD/DLD/RLD
STA/STDP/STSP val adr sym1	PST/DST/RST
.TE
.)b
.lp
Each ILM has a link to an expression which represents the address
of the quantity to be loaded or stored.
For the load ILMs, this
is the only link; for the stores, this is the first link.
This link is also used to locate the names table entry of the entity
being fetched or stored (the next word following that link
contains the index to the names table entry).
.lp
For the
.cw PLD
ILM, a new names entry of type indirection is
created.  The template for this entry is
.(b
.CS
<NT_IND, 0, sym, 0>
.CE
.)b
(\c
.cw sym
is the names entry located by link).  The index to this entry
is stored away in the second word of the
.cw PLD
ILM.
.lp
For field operations, the
.cw LD
or
.cw ST
ILIs are used.
The names table entry created for the referenced
.cw MEMBER
ILM
is used in these operations.
The size
of the operation depends on the
.cw LDSIZE
field of the member symbol
table item in the
.cw MEMBER
ILM located by the address ILM link.
This value is one of 1 (byte), 2 (half-word), or 4 (word)
and indicates which memory unit in a load or store operation 
(byte, half-word, or word) is
used to reference the field.
.lp
For the
.cw SLD
or
.cw FLD
ILMs, a
.cw LD
ILI is generated which will fetch from
memory the unit which contains the field.
Following the
.cw LD
ILI, a sequence of ILI is
generated to extract from this unit the actual field,
using either the field
.cw EXTRACT
instruction, if one exists, or
a left shift followed by a right shift.
The end result is that the
field is right justified in a data register.
These shifts are calculated from the
.cw BITOFF ,
.cw FLDSZ ,
and
.cw LDSIZE
fields
of the member symbol table item.  The actual calculation depends on
the bit ordering (
.q big-endian
or
.q little-endian )
of the target machine.  See the code for details.
.lp
For the
.cw FST
ILM, a
.cw ST
ILI is generated to store the value of the
field and any bits from other members of the structure which are
in the memory unit.
Prior to the
.cw ST
ILI, a sequence of ILI is generated to insert into a
data register the value being stored. These ILI consist of shifts
and masking operations, or field
.cw MERGE
instructions
if available,
which are derived from the 
.cw BITOFF ,
.cw FLDSZ ,
and
.cw LDSIZE
fields.  Again, see the code for details.
.lp
Field load and store operations are optimized in cases where the
field takes up a whole load unit (e.g., 8 bits), and when the field
is left justified in the load unit.
.lp
The
.cw SMOVE
ILM for the structure
assignment,
.cw "a = b" ,
consists of three operands:
.(b
\f(CWaddr\fP	link to the ILM defining the address of \f(CWa\fP
\f(CWexpr\fP	link to the ILM defining the address of \f(CWb\fP
\f(CWsym\fP	pointer to the data type of the structure
.)b
.lp
The ILI generated for the
.cw SMOVE
depend on the size and alignment of the
structure type:
.np
size of the structure is less than or equal
to eight units, where units depends on the alignment
and is one of bytes, half-words, words, or double words.
.sp
For this case, the structures
.cw a
and
.cw b
are divided into
.cw size
distinct
units.  A sequence of
.cw LD
and
.cw ST
ILIs are generated to move a unit of
.cw a
to
its position (according to the same offset for the beginning) in
.cw b .
The names entries created for
.cw addr
and
.cw expr
are used in these ILIs.
.np
size of the structure is greater than eight units.
.sp
For this case, an external call ILI is generated to (depending on the
alignment)
one of
.cw c$bcopy
(copy bytes),
.cw c$hcopy
(copy half-words),
.cw c$wcopy
(copy words),
or
.cw c$dcopy
(copy double words).
These are procedure linkage routines whose
arguments are
.cw n ,
.cw a ,
and
.cw b
where
.cw a
and
.cw b
are pointers to 
.cw char ,
.cw short ,
.cw int ,
or
.cw double
and
.cw n
is the number of bytes, half-words, words, or double words
to copy.  Note that 8 is approximately the number of 
cycles for the call overhead <this will change and needs to be
part of the MACHAR utility>.
.lp
Special ILMs called
.cw NCSELD
and
.cw NCSEST
are used to support the
.cw volatile
type modifier of C.  When a load of a volatile location is generated,
it is covered by a
.cw NCSELD
ILM.  This generates a special names entry
that forces the scheduler to always do the load (i.e., it is never
optimized out).
.lp
When a store to a volatile location is generated, the store is covered
by a
.cw NCSEST
ILM.  This generates a special names entry that forces
the scheduler to always do the store.  Note that, since both store ILMs
and the
.cw NCSEST
ILM are terminal, care must be taken to avoid calling
the
.cw check_ilm
routine on the store when it is covered by a
.cw NCESST
ILM.
.sh 4 "Pseudo Stores"
The pseudo store ILM,
.cw PSEDUOST ,
is generated by the semantic analyzer
for postfix operations. For example,
.cw i++
causes a
.cw PSEUDOST
to be
generated which will represent the original value of
.cw i .
Subsequent uses of
.cw i ,
in particular the add, will locate this ILM.
The expander creates a pseudo store ILI which is one of
.cw FREEIR ,
.cw FREEAR ,
.cw FREESP ,
or
.cw FREEDP ,
depending on the type of the register needed to load
.cw i .
Subsequent references to this ILM will cause the expander to create
an ILI to ensure that the reference uses the original value of
.cw i
instead
of the updated value of
.cw i
(refer to section 6.3.6,
.i "Common ILM Expressions" ).
.lp
The
.cw PSEUDOST
ILM is also used to force the expander to evaluate expressions protected
by unary
.cw +
as written without reordering.
.sh 4 "Names Conflicts"
In certain situations, the names entry created by normal processing may not
be sufficient for the detection of memory reference conflicts.
For example, consider the following program segment:
.(b
.CS
/* (1) */   int a[2], k;
/* (2) */   (double *)&a[0] = 0.0;
/* (3) */   k = a[1];
.CE
.)b
The names entry created for
.cw a[0]
indicates that it is an array reference
with a constant offset of 0.
Because of the double context at statement
(2),
.cw a[1]
is also modified.
At statement (3), the names entry for
.cw a[1]
is an array reference with
a constant offset of 4. This entry does not conflict with the names entry
for
.cw a[0] .
For the reference at (2), the expander recognizes that a double reference
occurs on an entity which is not type double.
For this situation,
the expander changes the names reference for
.cw a[0]
to one which
denotes an array reference with variable subscripts.
This names entry will conflict with the one at (3).
.lp
This processing occurs whenever:
.np
the load or store operation is not double and the item involved is type double,
or the load or store operation is double and the item involved is not type
double, and
.np
the names entry denotes an array with constant subscripts or an indirection
with constant subscripts.
.sh 3 "Common ILM Expressions"
A common ILM expression occurs when an ILM has multiple references.
Common situations are prefix expressions and using the results of
assignments and postfix expressions.
For common ILMs, the expander must ensure that the
.q "value"
stored is the
one that is re-used.
.lp
When the store or pseudo store ILM is processed, the index locating the
terminal ILI generated for the ILM is saved away as the
.q "result"
of the ILM.
Also, the block id, a BIH index, of the ILI block containing the ILI is saved.
When the expander finds an ILM which has been evaluated (in
.cw eval_ilm
while
recursively searching a terminal ILM's links),
routine
.cw check_ilm
is called to examine the
.q "result"
of the ILM.
If the block of the result is the same as the current block being created,
then all that has to be done is to create a cse (common subexpression) ILI
of the value being stored (this is always the first operand of the terminal
ILI).
This (cse) ILI replaces the result of the ILM which is being referenced and
is therefore the ILI used by the referencing ILM (note that subsequent
evaluations of this ILM will use the cse ILI).
The expander must guarantee that the scheduler will see the cse'd
ILI before it sees the cse ILI.
For example,
.(b
.CS
i = j = k;
.CE
.)b
results in the following ILM block:
.(b
.CS
   0 BOS            3    17
   3 BASE          43            ;i
   5 BASE          44            ;j
   7 BASE          45            ;k
   9 ILD           7^
  11 IST           5^    9^
  14 IST           3^   11^
.CE
.)b
.lp
The ILM at (11) generates a store ILI which stores the value of
.cw k
(a load
ILI of
.cw k )
in
.cw j .
For ILM (14), the value stored (the second operand) is the value of
ILM (11).
Since this ILM has already been evaluated, the new
.q "result"
of (11)
is a cse ILI of the value being stored (the load ILI of
.cw k ).
A cse ILI of the load ILI of
.cw k
is the ILI which is accessed by the
store ILI for ILM (14).
Note that the scheduler will see the store of
.cw j
before the store of
.cw i .
Therefore, it will see the load of
.cw k
before it sees its corresponding cse.
.lp
If the ILI occurs in a block which is not the current block, then
the expander must add to the block containing the ILI a temporary store
of a cse of the stored value.
The result of the ILM is replaced by a load of the temporary.
For example,
.(b
.CS
*p++ = flag ? 1 : 0;
.CE
.)b
results in the following ILM block (created ILI basic block
boundaries are denoted by
.cw "---" :
.(b
.CS
   0 BOS            6    55
   3 BASE          45            ;p
   5 PLD           3^
   7 PSEUDOST       0    5^
  10 ICON          35
  12 PIADD         5^   10^     1
  16 PST           3^   12^
  19 BASE          44            ;flag
  21 ILD          19^
  23 BRF          21^    46
  ______________________________________

  26 BASE          47            ;.I0000
  28 ICON          35
  30 IST          26^   28^
  33 BR            48
  ______________________________________

  35 LABEL         46
  37 ICON          32
  39 BASE          47            ;.I0000
  41 ICON          32
  43 IST          39^   41^
  ______________________________________

  46 LABEL         48
  48 BASE          47            ;.I0000
  50 ILD          48^
  52 IST           7^   50^
.CE
.)b
.lp
In this case, the ILM at (52) references ILM (7) whose ILI is in a
different ILI block.
Therefore, the expander will add to the block containing the ILI for ILM
(7) a store into a temporary.
The value stored is just a cse of the ILI which does a load of
.cw p .
ILM (52) will use a load of the temporary.
.sh 3 "Functions"
A function ILM exists for each scalar type and void type.
The ILMs are:
.TS
LfCW LfCW.
VFUNC	void
IFUNC	int
UIFUNC	unsigned int
RFUNC	float
DFUNC	double
PFUNC	pointer
.TE
A function ILM has the form:
.(b
.CS
<function ILM>  n  lnk1  lnk*
.CE
.)b
where,
.ip "\f(CWn\ =\fP" 7n
number of actual arguments
.ip "\f(CWlnk1\ =\fP" 7n
address expression which computes the address of the function
being called
.ip "\f(CWlnk*\ =\fP" 7n
zero or more links locate the arguments that are passed to the
function. These arguments are the actual values passed to the
function.
.lp
The
.cw VFUNC
ILM is also used whenever a non-void function is called and
its value is discarded. The remaining ILMs are used in contexts which
access their values.
.lp
Processing a function ILM involves:
.np
possibly creating a dummy argument to keep the stack double word
aligned.
.np
looping through the argument links to generate ILI to push their
values on the stack.  The ILI generated are in the set
.cw IL_ARGIR
(data
register),
.cw IL_ARGAR
(address register),
.cw IL_ARGSP
(single precision
floating register),
.cw IL_ARGDP
(double precision floating register).
.np
generating the ILI to push the
argument count on the stack.
.np
generating the
.q "jsr"
ILI which links to the function address and
argument list address. This can be one of two ILI:
.ba +5n
.ip \(bu 4n
.cw "JSR\ sym\ lnk"
\(em sym is the ST entry for the function (if
.cw lnk1
locates an
.cw "ACON"
ILI)
.ip \(bu 4n
.cw "JSRA\ lnk\ lnk"
\(em
the first
.cw lnk
locates the function address which is computed,
i.e.,
.cw (*p)() 
.ba -5n
.np
If the function ILM is not void, the
.q "define result"
ILI
is generated which will link to the
.q "jsr" .
This is one of:
.ba +5n
.ip \(bu 4n
.cw "DFRAR\ lnk\ 0"
\(em pointer result; 0 indicates
.cw AR(0) .
.ip \(bu 4n
.cw "DFRIR\ lnk\ 0"
\(em integer register result; 0 indicates
.cw IR(0) .
.ip \(bu 4n
.cw "DFRSP\ lnk\ 0"
\(em single precision result; 0 indicates
.cw SP(0) 
.ip \(bu 4n
.cw "DFRDP\ lnk\ 0"
\(em double precision result; 0 indicates
.cw DP(0) .
.ba -5n
.lp
If the function is a
.cw VFUNC
ILM, an ILT is created.
If the function is a
.cw PFUNC
ILM, a names entry of type
.cw NT_UNK
(unknown)
is created for the names result of the ILM.
.sh 3 "ESTMT Processing"
The
.cw ESTMT
ILM is used for an expression whose result is not used (its
value is discarded).  This is particularly true for all but the rightmost
expression in a comma expression.
The ILI expression tree located by the
.cw ESTMT 's
link is
searched for the functions. The result of this search is that
ILTs are created which reference just the function ILIs.
For example,
.(b
.CS
     a = ( f() + g(), b )

     ----  ILM  ----          ----  ILI ----

     ESTMT   -----+          (1) JSR "f"
                  |          (2) DFRIR (1) 0
                  |          (3) JSR "g"
                  |          (4) DFRIR (3) 0
                  +----->    (5) IADD (4) (2)
.CE
.)b
Two ILT nodes are created for this ILM:  one locates the ILI at (1) and
the second locates the ILI at (3).
.sh 3 "Comparison and Relational Processing"
Comparison ILMs serve only as placeholders for the relational ILMs.
The appropriate ILM is generated by the semantic analyzer
which reflects the scalar data type of its operands.
The expander passes up the opcode of the equivalent ILI to the relational
ILM accessing the compare by saving away the opcode.
When the relational ILM is processed, the opcode and the compare's
operands are extracted, and the value denoting the relation is computed.
The "compare for relation" ILI is then generated.
Note that the value indicating the
relation is an immediate value to the ILI.
This value is computed by relying on the following consecutive ordering
of the relational ILMs: EQ, NE, LT, GE, LE, and GT.
The respective values are 1, 2, 3, 4, 5, and 6.
.sh 3 "Branch Processing"
Most branch ILMs are expanded using
.cw exp_mac .
Certain ILMs require special handling by the expander.
For now, there is just one ILM special cased \(em the
.cw SWITCH
ILM.
.lp
The
.cw SWITCH
ILM consists of the switch expression and the switch list (a 
list of the switch labels including the default; refer to Section 12 for
a description of the switch list).
Simple heuristics are used to generate the ILIs for the
.cw SWITCH .
There are
three cases:
.np
The number of cases in the switch is less than or equal to 
four.
A sequence of conditional if's is used to represent the switch:
For example,
.(b
.CS
switch (i) {
case 1: s1;
case 2: s2;
}
s3;
.CE
.)b
The ILIs generated are for a sequence of conditional if's:
.(b
.CS
        if (i==1) goto l1;
        if (i==2) goto l2;
        goto l3:
    l1: s1;
    l2: s2;
    l3: s3;
.CE
.)b
.np
The number of cases in the switch is greater than four and
less than or equal to 16, or
the case values consist of a set of dense values (many values \(em
80 percent \(em
which exist between the minimum and maximum values).
.ba +5n
.sp
For example,
.(b
.CS
switch (i) {
case 1: s1;
case 2: s2;
case 3: s3;
case 5: s5;
case 6: s6;
}
s7;
.CE
.)b
yields ILIs which select an entry from an address table.
The address table is a data initialized,
compiler created array, with a name of the form
.cw .Jxxxx
where
.cw xxxx
is a decimal number.
The address table consists of a series of addresses
where the first entry
is the address of
the default statement (\c
.cw s7
in the above example), the
second entry is the address of
the statement corresponding to the smallest case value
(\c
.cw s1
in the example), the third entry is the address of
the statement corresponding
to the next (increase of 1) case value (\c
.cw s2
in the example),
and so forth.
The index to the jump table is determined by adding to the switch
expression (in the above example,
.cw i )
a value which normalizes
the switch value to 1.
This calulation results in the
minimum case value corresponding to the second entry (the first case
value) in the jump table. In the example, the value added is one.
If this value falls outside of the range
of 1 to n (n is the number of entries in the table including the default
entry), the default statement is branched to.
For the above example, the following ILIs are generated:
.(b
.CS
        (1) IADD i '1'          '1' is a constant ST for the
                                value 1
        (2) JMPM (1) '7' tab    The table has 7 entries.
        ...
tab:    l7                      default
        l1                      case 1
        l2                      case 2
        l3                      case 3
        l7                      case 4 is default
        l5                      case 5
        l6                      case 6
.CE
.)b
An ILT is created for the JMPM ILI.
.ba -5n
.np
The number of cases in the switch is greater than 16 and the case
values are sparse.
In this case, ILIs are generated which will call the C support routine,
.cw c$i_switch ,
to perform the switch. Passed to the routine are the switch
expression and the
label list, which must be created by the expander module.
The label list is a compiler created symbol (an auto integer array)
whose name is
.cw ".Jxxxx"
where
.cw xxxx
is a decimal number.
The label list has the form:
.ba +5n
.(b C
.TS
tab(%);
  c8   l
| c8 | l
  c8   l
| c8 | l
  c8   l
| c8 | l
  c8   l
| c8 | l
  c8   l
| c8 | l
  c8   l
| c8 | l
  c8   l
| c8 | l
  c8   l .
_%
n%number of case value-label pairs
_%
default label%label of default statment
_%
case value\*<1\*>%value-label pair
_%\^
case label\*<1\*>%for first entry
_%
\&...%
_%
case value\*<N\*>%value-label pair
_%\^
case label\*<N\*>%for Nth entry
_%
.TE
.)b
Note that the case values are in sorted (ascending) order.
An ILT node is created which locates the ILI representing the
call to the switch routine.
.ba -5n
.sh 3 "Entry Processing"
When an
.cw ENTRY
ILM is processed, the following actions are performed:
.np
A basic block is created. This will be the first block of the function.
.np
The
.cw ENTRY
ILI is generated. This ILI has two operands:
.cw pro ,
and
.cw func ,
respectively.
.cw pro
is a symbol table item of type
.cw ST_FUNC
which represents the C prologue
routine (
.cw c$i_entry ).
.cw func
is the symbol table item of type
.cw ST_FUNC
which represents the
entry.
Note that the first ILT in this block locates this ILI.
.np
If exceptions are to be disabled and/or enabled, two constants are
created from the values of the global variables
.cw "flg.xon"
and
.cw "flg.xoff" .
The first represents the mask value used to enable exceptions
(by OR'ing). The second represents the mask value used
to disable exceptions (by AND'ing).
The method by which these exceptions are enabled and disabled
is machine dependent and is specified in the MACHAR utility.
.np
If the debug option was selected, an ILT is created to locate the ILI
which calls the debugger routine
.cw "dbg$i_entry"
<this may change>.
.sh 3 "Return Processing"
When the
.cw RET
or
.cw RETV
ILM is processed, a jump ILI is created which
references the label (a compiler created symbol table item) of the
exit block. This label's name is
.cw ".Rxxxx"
where
.cw xxxx
is a decimal
number.
Its symbol table index is stored in
.cw exp.retlbl .
Only one return label is needed per function.
For the
.cw RETV ,
the appropriate move register ILI is generated to
move the function's return value into a register prior to the jump.
.sh 3 "End Processing"
When the
.cw END
ILM is processed, the following actions are performed:
.np
If a return ILM was processed, a label would have been created which
is accessed by a
.cw JMP
ILI. 
That is, a return is turned into a jump to the block defined by the
return label.
Note that the same rules for the label specified in a
.cw LABEL
ILM apply
to the return label (optimizing out, etc.).
.np
If exceptions were modified, machine dependent exception
cleanup ILI are generated and
linked to by an ILT node.
.np
If the debug option was selected, an ILT is created which locates the
ILI which calls the debugger routine
.cw "dbg$i_exit"
<this may change>.
.np
The
.cw EXIT
ILI is generated. This ILI has one operand, a
.cw ST_FUNC
symbol table item
representing the C epilogue routine
.cw "c$i_exit" ).
An ILT node locates this ILI.
.sh 3 "Miscellaneous"
The following ILMs are the remaining
.q "address"
producing ILMs which
require that each produces a names entry result in addition to an ILI
result:
.np
.cw ACON
\(em A names entry of type
.cw NT_VAR
is created. The symbol field is set
to the address constant.
.np
.cw IPTR
\(em This ILM converts an integer value to a pointer value. The names
entry created is type
.cw NT_UNK
(unknown).
.np
.cw LOC
\(em This ILM
.q "passes"
up the ILI and names entry located by its link.
.np
.cw PIADD/PISUB
\(em These ILMs call the
.cw addnme
routine with the template
.(b
.CS
<NT_ADD, ptr, bnme, cnst> .
.CE
.)b
.cw NT_ADD
indicates that addnme is to add
.cw bnme
(the name entry of the address ILI located by the first ILM link)
to the
.q "value"
denoted by
.cw ptr
and
.cw cnst .
.cw ptr
is zero if a constant is
being added (\c
.cw cnst
is the constant value in the
.cw PIADD
or
the negative of the
constant value in the
.cw PISUB ),
and \(mi1 if a non-constant
is being added.
.sh 3 "Program Units"
The expander module is composed of four C files:
.i expdf.c ,
.i expand.c ,
.i exp_clang.c , and
.i exputil.c .
The file
.i expdf.c
contains
the definitions and static initializations of the data structures
required by the expander.
.lp
The file
.i expand.c
contains the following routines:
.nr ii 5n
.lp
.CS
void exp_init()
.CE
.ip
Initialize the expander module: allocates space for the ILM, ILI, ILT, BIH,
and NME areas. Clears the zeroth entry for the ILT and BIH areas (refer
to section 13). The
.q "noblock"
flag in the expander local data area is set on
(no current block exists). The ILM file is rewound.
.lp
.CS
void expand()
.CE
.ip
Main expander routine called by the program controller.
This routine reads in a block of ILMs and scans the block for terminal
ILMs.  When one is found, it calls
.cw eval_ilm
to evaluate the terminal ILM
which in turn evaluates all of its operands.
.lp
.CS
void eval_ilm(ilmx)
int ilmx;
.CE
.ip
This routine controls evaluates the ILM
indexed by
.cw ilmx
and all of its operands.
When the operands have been evaluated,
.i eval_ilm
sets up the following static variables for use by the various subordinate
expand routines:
.(b
\f(CWilmp\fP	pointer to the current ILM
\f(CWopc\fP	opcode of the current ILM
\f(CWcurilm\fP	index of the current ILM
.)b
.cw eval_ilm
selects the appropriate action depending on the ILM 
attributes.
.lp
.CS
void
exp_estmt(ilmx)
int ilmx;
.CE
.ip
Expands the
.cw ESTMT
ILM.
.lp
.CS
void
exp_label(lbl)
int lbl;
.CE
.ip
Expands the
.cw LABEL
ilm.
.lp
.CS
void
exp_load(opc, ilmp, curilm)
int opc;
ILM *ilmp;
int curilm;
.CE
.ip
Expands the load ILMs.
.lp
.CS
void
exp_store(opc, ilmp, curilm)
int opc;
ILM *ilmp;
int curilm;
.CE
.ip
Expands the store ILMs.
.lp
.CS
void
exp_mac(opc, ilmp, curilm)
int opc;
ILM *ilmp;
int curilm;
.CE
.ip
Expands the non-special case ILMs using the templates defined using the
ILITP utility.
.lp
.CS
void
exp_ref(opc, ilmp, curilm)
int opc;
ILM *ilmp;
int curilm;
.CE
.ip
Expands the reference ILMs (except for
.cw ELEMENT )
and creates names
entries.
.lp
The C module file,
.i exp_clang.c , contains:
.lp
.CS
void
exp_ac(opc, ilmp, curilm)
int opc;
ILM *ilmp;
int curilm;
.CE
.ip
Expands the arithmetic and constant ILMs.
.lp
.CS
void
exp_array(opc, ilmp, curilm)
int opc;
ILM *ilmp;
int curilm;
.CE
.ip
Expands the
.cw ELEMENT
ILM and creates names entries.
.lp
.CS
void
exp_bran(opc, ilmp, curilm)
int opc;
ILM *ilmp;
int curilm;
.CE
.ip
Expands the branch ILMs, particulary the switch.
.lp
.CS
void
exp_call(opc, ilmp, curilm)
int opc;
ILM *ilmp;
int curilm;
.CE
.ip
Expands the call ilms.
.lp
.CS
void
exp_misc(opc, ilmp, curilm)
int opc;
ILM *ilmp;
int curilm;
.CE
.ip
Expands the miscellanous ILMs.
.lp
The C module file,
.i exputil.c ,
contains:
.lp
.CS
int mkfunc(name)
char *name;
.CE
.ip
Creates a symbol table entry of type function given the name and returns
its index.
.lp
.CS
cr_block()
.CE
.ip
Creates a BIH. Sets
.cw exp.curbih
to its index and defines its line number.
.lp
.CS
wr_block()
.CE
.ip
Terminates the block defined by
.cw exp.curbih .
Sets the first and last
fields of the BIH. Sets the
.q "noblock" flag in
.cw exp
to 1 (no block currently
exists).
.lp
.CS
void
flsh_block()
.CE
.ip
.lp
.CS
void
chk_block(ilix)
int ilix;
.CE
.ip
Checks to see if the ILI (located by
.cw ilix )
will terminate the current block.
If it will terminate the block, the block is terminated and the
.q "noblock"
flag in
.cw exp
is set to 1. Otherwise, an ILT is created for the ILI
and added to the current block.
.lp
.CS
int
check_ilm(ilmx)
int ilmx;
.CE
.ip
Checks the ILM (located by
.cw ilmx )
which has already been evaluated.
Actions are performed to ensure that the ILI originally generated for the
ILM is treated as a common subexpression or is used if
across block boundaries.  Special care is take not to call this
routine for store ILMs covered by the
.cw NCSEST
ILM.
.lp
.CS
int mk_swlist(n, swhdr)
INT n;
SWEL *swhdr
.CE
.ip
Makes the address/value table for the switch statement.
.lp
.CS
int mk_swtab(n, swhdr)
INT n;
SWEL *swhdr
.CE
.ip
Makes the address table for the switch statement.
