

            














                               AAA RRReee---UUUsssaaabbbllleee CCCooodddeee GGGeeennneeerrraaatttooorrr
                              fffooorrr PPPrrriiimmmeee 555000---SSSeeerrriiieeesss CCCooommmpppuuuttteeerrrsss

                                      UUUssseeerrr'''sss GGGuuuiiidddeee












                                      T. Allen Akin












                       School of Information and Computer Science
                             Georgia Institute of Technology
                                 Atlanta, Georgia  30332


                                       March, 1983











            




            


                                        ___FFF___ooo___rrr___eee___www___ooo___rrr___ddd




                 Although  the School of Information and Computer Science has
            operated Prime 400 and 550 computers for over four years, as  yet
            there  has been no successful local attempt to produce a compiler
            for them.  The main reasons for this failure are the irregularity
            of the architecture and existing system software, the  complexity
            of   Prime's  standard  object  code  format,  and  the  lack  of
            documentation on matters of importance to compiler writers.

                 This paper discusses the design, implementation,  and  usage
            of  a re-usable code generator.  This program can serve as a com-
            mon "back-end" for a number of  language  translators,  producing
            64V-mode  assembly  language  code  suitable for execution on the
            P400 and higher  numbered  processors  in  Prime's  "50"  series.
            Furthermore,  it  could be tailored to match specific front-ends,
            when needs for special optimizations arise.

                 A preliminary version of the code generator is available for
            general use.



































            




            


                                  ___HHH___ooo___www___ ___ttt___ooo___ ___UUU___sss___eee___ ___TTT___hhh___iii___sss___ ___GGG___uuu___iii___ddd___eee




                 The first chapter  of  this  GGGuuuiiidddeee  is  the  _O_v_e_r_v_i_e_w.   The
            _O_v_e_r_v_i_e_w is a brief summary of the design and construction of the
            code  generator.  This chapter may be of general interest, but it
            is not necessary to read it in order to learn  to  use  the  code
            generator.

                 The  _C_o_d_e  _G_e_n_e_r_a_t_o_r _U_s_a_g_e chapter describes the location of
            the code generator and its associated run-time support libraries,
            as well as the Software Tools  Subsystem  commands  necessary  to
            access  them.   Recommended  procedure  is to study this section,
            then generate command language programs to do the low-level  file
            access operations.

                 _I_n_p_u_t  _D_a_t_a  _S_t_r_e_a_m  _F_o_r_m_a_t_s  gives a bird's-eye view of the
            formats of the three code generator input streams.  This  chapter
            merits  some  study,  although it is supplemented by the _E_x_t_e_n_d_e_d
            _E_x_a_m_p_l_e_s.

                 The three operator definitions chapters (_O_p_e_r_a_t_o_r_s _U_s_e_f_u_l _i_n
            _t_h_e  _S_t_a_t_i_c  _D_a_t_a  _S_t_r_e_a_m,  _O_p_e_r_a_t_o_r_s  _U_s_e_f_u_l  _i_n  _t_h_e  _P_r_o_c_e_d_u_r_e
            _D_e_f_i_n_i_t_i_o_n  _S_t_r_e_a_m,  _O_p_e_r_a_t_o_r_s  _U_s_e_f_u_l  _i_n _P_r_o_c_e_d_u_r_e _D_e_f_i_n_i_t_i_o_n_s)
            provide a detailed reference for the intermediate form  operators
            interpreted  by  the code generator.  One or two readings through
            this chapter are desirable; thereafter,  it  can  be  used  as  a
            reference  with  the  _O_p_e_r_a_t_o_r/_F_u_n_c_t_i_o_n  _I_n_d_e_x  and  the Table of
            Contents used as entry points.

                 The _E_x_t_e_n_d_e_d _E_x_a_m_p_l_e_s are comprised of  several  short  (but
            complete)  programs  written  in  the language C.  These examples
            include the original C code, annotated versions of the three code
            generator input streams, and an annotated  listing  of  the  code
            generator's  assembly  language  output.   The  chapter should be
            useful in learning how the various  intermediate  form  operators
            work together, and may be used as a reference when building a new
            front end.

                 'Drift'  is  a  very  small  expression-based language whose
            structure closely mimics the  code  generator's  internal  world-
            model.   _T_h_e  _'_D_r_i_f_t_'  _C_o_m_p_i_l_e_r  is  a complete, working compiler
            using the code generator as a back-end.  It serves as an  example
            of one way to construct a front-end for the VCG.

                 For  ease  of reference, all the intermediate form operators
            have  been  organized  by  subject  in  the   _I_n_t_e_r_m_e_d_i_a_t_e   _F_o_r_m
            _O_p_e_r_a_t_o_r/_F_u_n_c_t_i_o_n _I_n_d_e_x.  Typically, one would look up some func-
            tion  (e.g.,  "subscripting")  in the _I_n_d_e_x, find the name of the
            appropriate intermediate form  operator  (e.g.,  INDEX_OP),  then
            look  up  that operator in the table of contents to find its com-
            plete description.




                                          - 1 -                              




            


                                        ___OOO___vvv___eee___rrr___vvv___iii___eee___www




                                       PPPhhhiiilllooosssoooppphhhyyy


            DDDeeesssiiigggnnn CCCooonnnsssiiidddeeerrraaatttiiiooonnnsss

                 The design of the code generator (hereinafter referred to as
            VCG, for "V-mode Code Generator")  was  driven  by  a  number  of
            considerations:

            ...    For   experimental  language  translators,  code  generation
                 should be fast and straightforward.  This is necessary  both
                 for fast turnaround and ease of debugging in the development
                 stage,  and  for  fast  turnaround  in  typical  educational
                 applications.

            ...    The VCG should insulate front-ends from details  of  storage
                 allocation and data format selection, as well as instruction
                 generation.  This encourages inter-language compatibility at
                 the  object code level, as well as providing a framework for
                 easily retargetable front-ends.

            ...    The intermediate form (IMF) that is  processed  by  the  VCG
                 should  be  simple  to  generate  and display (for debugging
                 purposes).   Furthermore,  it  should  not  unduly  restrict
                 extension for additional functionality or optimization.

            ...    The  output  object  code  should conform to Prime's current
                 standards, and should include at  least  minimal  provisions
                 for separate compilation and run-time debugging.



            IIImmmpppllleeemmmeeennntttaaatttiiiooonnn AAApppppprrroooaaaccchhheeesss

                 After some time, consideration of the goals above led to the
            following approaches to the implementation of the VCG:

            ...    The  basic  IMF  handled  by  both the front end and the VCG
                 should be a tree structure.  A tree is easily generated from
                 the information available on the  semantic  stack  during  a
                 bottom-up  parse,  and  can be generated directly without an
                 explicit  stack  during  a  top-down  parse.   A  number  of
                 operations  like constant folding, reordering of operands of
                 commutative operators, and global  context  propagation  are
                 readily  performed on a tree structure.  Furthermore, use of
                 a tree can eliminate the need for generation and tracking of
                 temporary variables in the front end.

            ...    The IMF operators should be close to the constructs used  in
                 an  algorithmic language of the level of, say, Pascal.  This
                 permits  straightforward  translation  of  most  algorithmic


                                          - 2 -                              




            


                 languages,  and  provides  enough additional context to sim-
                 plify many optimization tasks.  For example, the IMF  resem-
                 bles  the  program's  flow  graph closely enough that simple
                 global register allocation can be  performed  without  graph
                 reduction.

            ...    One of the basic functions of the VCG is the mapping of data
                 descriptions supplied by the front end into physical storage
                 layouts.   The  goal  of  complete  machine  data  structure
                 independence in the front end cannot  be  met  without  com-
                 promising  the  code  generator's utility for languages that
                 allow storage layout specification (C and  Ada  are  notable
                 examples).   Therefore,  the IMF should contain descriptions
                 of data structures in terms of a small set of primitive data
                 modes that can easily be parameterized  in  front-end  code.
                 Simple  variables,  structures,  and  arrays  defined in the
                 front end must be converted to single or multiple  instances
                 of  the  following  basic machine data modes:  16-bit signed
                 integer, 16-bit unsigned integer, 32-bit signed integer, 32-
                 bit unsigned integer,  32-bit  floating  point,  and  64-bit
                 floating point.

            ...    The IMF tree should be linearized and passed to the VCG as a
                 stream  of  data  in prefix Polish notation.  The linearized
                 form partly reflects the usual Software Tools methodology of
                 expressing even complex data transformations  as  "filters."
                 However, there are other advantages, particularly in storing
                 and  interpreting  the IMF for debugging.  Prefix Polish was
                 chosen because it can be generated easily from the  internal
                 representation  of  the  tree,  and because it minimizes the
                 amount  of  state  information  that  must   be   explicitly
                 maintained  by  both  the  front end and the VCG in order to
                 output or input the IMF.

            ...    The final output of the VCG should  be  a  stream  of  Prime
                 Macro  Assembly  Language  source  code.   Although the time
                 required to  assemble  this  source  imposes  a  significant
                 penalty  on  code  generator  performance,  it appears to be
                 unavoidable if the compiler writer is to be  insulated  from
                 Prime's   object  code  format.   (In  addition,  Prime  has
                 scheduled object code format changes, and it  would  not  be
                 wise to invest heavily in the present format.)



                                        SSStttrrruuuccctttuuurrreee


                 The  VCG "main loop" simply reads each module present on its
            input, rebuilds the tree represented by the input, transforms the
            tree to a linked list of machine instructions, performs  register
            tracking  optimizations  on  that  list, and finally converts the
            list to assembly language and outputs it.

                 The  input  and  output  routines  are  straightforward  and
            relatively uninteresting.


                                          - 3 -                              




            


                 The optimization routines amount to about 13 pages of Ratfor
            code,  and work by simulating the effect of each machine instruc-
            tion on the contents of the six registers that are  tracked.   At
            the moment, three types of optimization are performed:  redundant
            loads  are  eliminated,  some memory references are eliminated in
            favor of register-to-register transfers, and general  instruction
            sequences are replaced with special-case code.

                 The heart of the code generator is the set of transformation
            routines  that  convert  the  tree  representation to the doubly-
            linked list of machine instructions.  The transformation routines
            exhibit a great deal of knowledge about the machine architecture,
            but  actually  employ  only  very  simple  algorithms  for   code
            generation.

                 IMF  operators  may  appear  in  one  of several "contexts,"
            identified internally by the following terms:

                 RRReeeaaaccchhh.  An operator evaluated in reach  context  yields  the
                 address  of  a  word  in memory containing the result of the
                 operation,  if  possible.   At  present,  only  the  object,
                 constant,  pointer dereferencing, array indexing, and struc-
                 ture member selection operators yield addresses.  All  other
                 operators  behave  as  if  they  were  evaluated  in  "load"
                 context.

                 LLLoooaaaddd.  An operator evaluated in load context yields a  value
                 in a machine register.  The particular register used depends
                 only  on the basic machine data mode of the operation.  Most
                 IMF operators are evaluated only in this context.

                 VVVoooiiiddd.  An operator evaluated in  void  context  yields  side
                 effects  only.   In  a  very  few  cases, this results in an
                 opportunity to  exploit  special-case  machine  instructions
                 that  perform  some  calculation  without  making the result
                 available in a register (incrementing a memory location, for
                 example).

                 FFFlllooowww.  An operator evaluated in flow context yields a change
                 in flow-of-control rather than  a  value.   For  example,  a
                 "test  for  equality" operator would return 1 or 0 in a load
                 context, but in flow context would cause a jump to  a  given
                 label depending on the outcome of the test.

                 AAAPPP.  An operator evaluated in AP context yields an "argument
                 pointer" rather than a value.  Argument pointers are used to
                 pass parameters to procedures.


                 Context  information  is  propagated  top-down  by  the code
            generator as it scans the IMF tree.   Additional  information  in
            the  form  of register requirements is propagated from the bottom
            up during the same scan.  Together, context  and  register  usage
            determine  with  fair  accuracy  the  optimal code sequence to be
            generated for a given operator.



                                          - 4 -                              




            


                                 IIInnnpppuuuttt///OOOuuutttpppuuuttt SSSeeemmmaaannntttiiicccsss


            IIInnnpppuuuttt SSStttrrruuuccctttuuurrreee

                 The IMF passed to the VCG consists of a sequence of _m_o_d_u_l_e_s.
            A module is a sequence  of  procedure  definitions,  static  data
            definitions,  and  entry  point  declarations.   The  static data
            definitions build a data area that is shared by all procedures in
            the module, while the procedure definitions build code  and  data
            areas  that  are  strictly local to each procedure, and the entry
            point declarations  make  the  static  data  area  or  procedures
            visible to Prime's link editor.

                 Prime's  Fortran  compilers  currently generate code that is
            equivalent to one procedure per module under this scheme; Prime's
            PL/I and Pascal compilers generate code that is equivalent  to  a
            single  IMF  module.   The  VCG  module  structure  permits  com-
            patibility with either of these alternatives,  as  well  as  com-
            promise forms that are more suitable for other languages.

                 Note:  Separate compilation capability directly affects
                 module  structure.   At  present,  there  is no way for
                 separately compiled procedures to share a  static  data
                 area.   Furthermore, separately-compiled static objects
                 must be referenced by a unique  8  or  fewer  character
                 name  made  visible  to  the  loader.  A Fortran COMMON
                 block definition can be used to reduce  the  number  of
                 such  external  symbols,  but  COMMON  definitions must
                 match exactly in all separately-maintained modules.  In
                 addition, note that  Prime's  current  loader  software
                 requires that external objects be referenced through an
                 indirect  address, which can cause a significant reduc-
                 tion in performance.


                 Each _s_t_a_t_i_c_ _d_a_t_a_ _d_e_f_i_n_i_t_i_o_n allocates space  for  an  object
            and  may  specify an initial value for the object.  A _s_t_a_t_i_c_ _d_a_t_a_
            _d_e_c_l_a_r_a_t_i_o_n names an object that is defined outside  the  current
            module, but provides no other information about the object.

                 Each _p_r_o_c_e_d_u_r_e_ _d_e_f_i_n_i_t_i_o_n consists of information associated
            with  a  closed routine defined by the front end.  In particular,
            the procedure's argument types and code tree are included.

                 The bulk of the IMF will be in subtrees  defining  the  code
            associated  with procedures.  Most storage allocators, arithmetic
            operators, and flow controllers are  straightforwardly  expressed
            in  tree form; a description of these IMF components is available
            elsewhere.


            OOOuuutttpppuuuttt SSStttrrruuuccctttuuurrreee

                 Each VCG input module generates a single PMA  input  module,
            terminated  by  an  END  pseudo-op.   The PMA input module may be


                                          - 5 -                              




            


            assembled,   link-edited,   and   subsequently   executed.    The
            concatenation  of  all  static  data definitions and declarations
            forms a _l_i_n_k_ _f_r_a_m_e that  is  shared  by  all  procedures  in  the
            module.   Each procedure definition yields an entry control block
            (ECB) and a chunk of machine code that implements the function of
            the  procedure,  including  the  allocation  of  space   in   the
            procedure's _s_t_a_c_k _f_r_a_m_e for local variables.



















































                                          - 6 -                              




            


                                  ___CCC___ooo___ddd___eee___ ___GGG___eee___nnn___eee___rrr___aaa___ttt___ooo___rrr___ ___UUU___sss___aaa___ggg___eee




                 The  code generator currently resides in the file =bin=/vcg.
            The three input streams can  be  read  from  the  three  standard
            inputs,  or  from three files (if a standard naming convention is
            used).  The PMA output stream is produced on standard  output  1,
            and should be redirected to a file for assembly.

            Assume  temporary  files  will be used for communications between
            the front end and the code generator.  The temporary  files  must
            have  names  of  the form "xxx.ct1" (for IMF stream 1), "xxx.ct2"
            (for IMF stream 2), and "xxx.ct3" (for IMF stream 3), where "xxx"
            is completely arbitrary but must be the same for all of the three
            temporary files in a given  run.   When  the  code  generator  is
            invoked,  the string "xxx" must be passed to it as a command line
            argument.

            To use the code generator, first run the front end to produce the
            temporary files:

                 front_end

            Say, for example, this produces files "temp.ct1", "temp.ct2", and
            "temp.ct3".  Next, run the code generator and produce the  assem-
            bly language output:

                 vcg temp >temp.s

            Run the assembler to convert the PMA source to relocatable binary
            code:

                 pmac temp.s

            Finally,  run  the  link editor to load the VCG main program, the
            binary code for your program, and all required library routines:

                 ld =lib=/vcg_main temp.b =lib=/vcglib -o program

            This produces an object program (in the file "program") which may
            be executed simply by typing its name:

                 program


                 All run-time support routines called by the  output  of  the
            code  generator  are  available in the library =lib=/vcglib.  The
            stub main program in =lib=/vcg_main calls a procedure named MAIN;
            therefore, the user's main program must be named MAIN.  (This  is
            the usual case in C environments.)

                 One  miscellaneous  note:  if the front end is being written
            in  Ratfor,  the  complete  set  of  macro  definitions  for  the
            intermediate  form  operators can be obtained by simply including


                                          - 7 -                              




            


            the file "=incl=/vcg_defs.r.i".  If the front end is being  writ-
            ten  in  Pascal, the complete set of constant definitions for the
            intermediate form operators can be obtained by including the file
            "=incl=/vcg_defs.p.i".






















































                                          - 8 -                              




            


                                ___III___nnn___ppp___uuu___ttt___ ___DDD___aaa___ttt___aaa___ ___SSS___ttt___rrr___eee___aaa___mmm___ ___FFF___ooo___rrr___mmm___aaa___ttt___sss




                 This  section  describes  the  formats  of  the  three  code
            generator input streams.  Note that all three have the same basic
            format:

                                                        _
            32 MODULE_OP                                 |
                                         _               |
            59    SEQ_OP                  |  Repeat for  | Repeat for each
            ...      Item of information _|  each item   |      module
                                                         |
            39    NULL_OP                               _|
            
            39 NULL_OP                                     Stream termination

            Detailed examples of the code generator input can be found in the
            "Extended Examples" section of this guide.



                          SSStttrrreeeaaammm 111 --------- EEEnnntttrrryyy PPPoooiiinnnttt DDDeeeccclllaaarrraaatttiiiooonnnsss


                 The  first  intermediate form stream consists of one or more
            _m_o_d_u_l_e_s.  Each module consists of a MODULE_OP, a  list  of  _e_n_t_r_y
            _p_o_i_n_t  _d_e_c_l_a_r_a_t_i_o_n_s separated by SEQ_OPs, and a NULL_OP terminat-
            ing the list of entry point declarations.  The list of modules is
            terminated by a final NULL_OP.

                 Each entry point declaration  is  an  object  identification
            number followed by a character string, expressed as the length of
            the  string followed by the ASCII character codes for the charac-
            ters in the string.  Each such string is assumed to be  the  name
            of  a  location  defined in the current input module, and is made
            available to the link editor for  resolving  references  made  by
            other modules.

                 A template for stream 1 would look something like this:

                                                           _
            32 MODULE_OP                                    |
                                       _                    |
            59    SEQ_OP                | Repeat for each   | Repeat for each
                     Entry object id    |   entry point     |      module
            ...      Entry point name  _|                   |
                                                            |
            39    NULL_OP                                  _|
            
            39 NULL_OP                                        Terminate stream





                                          - 9 -                              




            


                    SSStttrrreeeaaammm 222 --------- SSStttaaatttiiiccc DDDaaatttaaa DDDeeeccclllaaarrraaatttiiiooonnnsss///DDDeeefffiiinnniiitttiiiooonnnsss


                 In C terminology, a data "definition" reserves storage space
            for an object and possibly initializes that space, whereas a data
            "declaration"  simply  indicates  that  the  storage space for an
            object  resides  outside  the   current   module.    The   second
            intermediate  form  input  stream defines or declares static data
            (objects that are not automatically allocated on the stack when a
            procedure is entered).

                 The input stream consists of a series of _m_o_d_u_l_e_s, terminated
            by a NULL_OP.  Each module contains a sequence of _D_E_F_I_N_E__S_T_A_T__O_Ps
            and _D_E_C_L_A_R_E__S_T_A_T__O_Ps, terminated by a NULL_OP.

                 A template for the static data stream would  look  something
            like this:

                                                                _
            32 MODULE_OP                                         |
                                              _                  |
            59    SEQ_OP                       |   Repeat for    | Repeat for
            14/11    DEFINE/DECLARE_STAT_OP    | each defn/decl  | each module
            ...         with associated info  _|                 |
                                                                 |
            39    NULL_OP                                       _|
            
            39 NULL_OP                                             Terminate stream




                           SSStttrrreeeaaammm 333 --------- PPPrrroooccceeeddduuurrreee DDDeeefffiiinnniiitttiiiooonnnsss


                 The  third intermediate form input stream consists of one or
            more _m_o_d_u_l_e_s, terminated by a NULL_OP.  Each  module  contains  a
            list of _P_R_O_C__D_E_F_N__O_Ps, separated by SEQ_OPs and terminated with a
            NULL_OP.

                 Each  PROC_DEFN_OP causes a procedure to be defined and code
            for it to be generated.

                 A template for stream 3 would look something like this:

                                                                _
            32 MODULE_OP                                         |
                                              _                  |
            59    SEQ_OP                       |   Repeat for    | Repeat for
            50       PROC_DEFN_OP              | each procedure  | each module
            ...         with associated info  _|                 |
                                                                 |
            39    NULL_OP                                       _|
            
            39 NULL_OP                                             Terminate stream



                                         - 10 -                              




            


                                  ___PPP___rrr___iii___mmm___iii___ttt___iii___vvv___eee___ ___DDD___aaa___ttt___aaa___ ___MMM___ooo___ddd___eee___sss




                 The following primitive data modes are presently handled  by
            the code generator:



            IIINNNTTT___MMMOOODDDEEE 111

            Integer  objects are one 16-bit word in size.  They have integral
            values in the range (-2**15) to (2**15 - 1), inclusive.



            LLLOOONNNGGG___IIINNNTTT___MMMOOODDDEEE 222

            Long integer objects are two 16-bit words  in  size.   They  have
            integral values in the range (-2**31) to (2**31 - 1), inclusive.



            UUUNNNSSS___MMMOOODDDEEE 333

            Unsigned  objects  are  nominally  one 16-bit word in size.  They
            have integral values in the range 0 to (2**16 - 1).   Bit  fields
            (see  FIELD_OP) can be of mode UNSIGNED, and may range from 1 bit
            to 16 bits in length (with consequent  change  in  the  range  of
            values they can represent).



            LLLOOONNNGGG___UUUNNNSSS___MMMOOODDDEEE 444

            Long  unsigned  objects  are  nominally two 16-bit words in size.
            They have integral values in the range 0 to (2**32 - 1).  Machine
            addresses (pointers) are represented as long unsigned quantities.
            Bit fields (see FIELD_OP) can be of mode LONG UNSIGNED,  and  may
            range  from 1 bit to 32 bits in length (with consequent change in
            the range of values they can represent).



            FFFLLLOOOAAATTT___MMMOOODDDEEE 555

            Floating point objects are two 16-bit words in size.



            LLLOOONNNGGG FFFLLLOOOAAATTT___MMMOOODDDEEE 666

            Long floating point objects are four 16-bit words in size.




                                         - 11 -                              




            


            SSSTTTOOOWWWEEEDDD___MMMOOODDDEEE 777

            STOWED mode is the  mode  assigned  to  structured  objects  like
            arrays and structs (Pascal "records").  STOWED objects may be any
            size  from  1  to  65536 16-bit words; IMF operators that need to
            know the size of a STOWED object invariably have  a  "length"  or
            "size" parameter to carry that information.



















































                                         - 12 -                              




            


                       ___OOO___ppp___eee___rrr___aaa___ttt___ooo___rrr___sss___ ___UUU___sss___eee___fff___uuu___lll___ ___iii___nnn___ ___ttt___hhh___eee___ ___SSS___ttt___aaa___ttt___iii___ccc___ ___DDD___aaa___ttt___aaa___ ___SSS___ttt___rrr___eee___aaa___mmm




            DDDEEECCCLLLAAARRREEE___SSSTTTAAATTT___OOOPPP 111111

            int 11
            int object_id
            string external_name

            DECLARE_STAT  informs  the  code generator that an object defined
            outside the current module will be referenced by a given  integer
            object  id.  The parameter 'external_name' is a character string,
            represented in the IMF by a length followed by a stream of  ASCII
            characters  (one  per  word,  right justified, zero filled).  The
            external name is used by  the  link  editor  and  the  loader  to
            resolve actual references to the object.

            Example:  extern int abc
                      where 'abc' is assigned the object id 6
            
                     11       DECLARE_STAT_OP
                     6           Object id of 'abc'
                     3           Length of name 'abc'
                     225            character 'a'
                     226            character 'b'
                     227            character 'c'




            DDDEEEFFFIIINNNEEE___SSSTTTAAATTT___OOOPPP 111444

            int 14
            int object_id
            tree init_list
            int size

            This  operator  causes  storage  for  the  object  identified  by
            'object_id' to be allocated in the  current  link  frame  (static
            data   area).    'Object_id'  must  be  used  in  all  subsequent
            references to  the  object,  and  the  object's  definition  with
            DEFINE_STAT must precede all such references.  The init_list is a
            list  of initializers whose values will be assigned to successive
            portions  of  the  newly-declared  object.   The  size  parameter
            specifies the amount of storage to be reserved for the object, in
            words.   (Slightly  fewer  than  65,535  words  are available for
            static storage in each module.)

            Example:  static int abc[100]
                      where abc is assigned the object id 6
            
                     14       DEFINE_STAT_OP
                     6           Object id for 'abc'
                     39          NULL_OP (no initializers present)


                                         - 13 -                              




            


                     100         Object is 100 words long

























































                                         - 14 -                              




            


                   ___OOO___ppp___eee___rrr___aaa___ttt___ooo___rrr___sss___ ___UUU___sss___eee___fff___uuu___lll___ ___iii___nnn___ ___ttt___hhh___eee___ ___PPP___rrr___ooo___ccc___eee___ddd___uuu___rrr___eee___ ___DDD___eee___fff___iii___nnn___iii___ttt___iii___ooo___nnn___ ___SSS___ttt___rrr___eee___aaa___mmm




            PPPRRROOOCCC___DDDEEEFFFNNN___OOOPPP 555000

            int 50
            int object_id
            int number_of_args
            string proc_name
            tree argument_list
            tree code

            Each procedure to be generated by the code generator  is  defined
            by a PROC_DEFN_OP.  The 'object_id' is an integer identifier that
            must  be  used  on calls to the procedure and other references to
            its entry control block (for example, pointers  to  functions  as
            used   in   C).   'Number_of_args'  should  be  self-explanatory.
            'Proc_name' is a string (in the IMF, a length followed  by  ASCII
            character  values)  giving  the  internal  name of the procedure.
            (This information is  used  to  print  trace  information  during
            debugging.)   Each  formal parameter (argument) is described by a
            PROC_DEFN_ARG_OP; 'argument_list' is  simply  a  linked  list  of
            those  descriptions.   'Code' is a subtree containing the body of
            the procedure:  local variable definitions and expressions to  be
            evaluated.

            Example:  the following C function
            
                     main (argc, argv)
                     int argc;
                     char **argv;
                        {
                        int i;
                        i = 4;
                        }
            
                     50       PROC_DEFN_OP
                     1           Procedure is object number 1
                     2           Procedure has 2 arguments
                     4           Procedure name is 4 characters long
                     237            m
                     225            a
                     233            i
                     238            n
                     49          PROC_DEFN_ARG_OP
                     2              Argument is object number 2
                     1              INT_MODE
                     0              VAL_DISP; pass argument by value
                     1              Argument is 1 word long
                     49          PROC_DEFN_ARG_OP
                     3              Argument is object number 3
                     4              LONG_UNS_MODE (a pointer)
                     1              REF_DISP; pass argument by reference
                     2              Argument is 2 words long


                                         - 15 -                              




            


                     39          NULL_OP; end of argument description list
                     59          SEQ_OP; beginning of procedure code
                     13             DEFINE_DYNM_OP
                     4                 Object id is 4
                     39                NULL_OP; no initializers
                     1                 Object is 1 word long
                     59          SEQ_OP; procedure code continues
                     5              ASSIGN_OP
                     1                 INT_MODE
                     40                OBJECT_OP
                     1                    INT_MODE
                     4                    Object id is 4
                     9                 CONST_OP
                     1                    INT_MODE
                     1                    Constant is 1 word long
                     4                    Constant has value 4
                     1                 Assignment transfers 1 word
                     39          NULL_OP; end of procedure code




            PPPRRROOOCCC___DDDEEEFFFNNN___AAARRRGGG___OOOPPP 444999

            int 49
            int object_id
            int mode
            int disposition
            int length
            tree next_argument

            Formal  parameters  to procedures are described by this operator.
            The 'object_id' is an integer identifier that must be supplied on
            subsequent references to  the  parameter  (see  OBJECT_OP).   The
            'mode'  is the machine data type of the parameter.  'Disposition'
            indicates how the argument is to be treated on the call; the  two
            alternatives  at  the moment are 0 (VALUE_DISP) for pass-by-value
            (aka copy in) and 1 (REF_DISP) for  pass-by-reference.   'Length'
            gives  the  size of the argument in 16-bit words; it is primarily
            necessary for handling of STOWED arguments  that  are  passed  by
            value.    'Next_argument'   is   simply   a   link  to  the  next
            PROC_DEFN_ARG_OP in a procedure's argument descriptor list, or  a
            NULL_OP.

            See PROC_DEFN_OP for examples of PROC_DEFN_ARG_OP.













                                         - 16 -                              




            


                        ___OOO___ppp___eee___rrr___aaa___ttt___ooo___rrr___sss___ ___UUU___sss___eee___fff___uuu___lll___ ___iii___nnn___ ___PPP___rrr___ooo___ccc___eee___ddd___uuu___rrr___eee___ ___DDD___eee___fff___iii___nnn___iii___ttt___iii___ooo___nnn___sss




            AAADDDDDDAAAAAA___OOOPPP 111

            int 1
            int mode
            tree left
            tree right

            The  result  of this operator is an rvalue, the sum of the values
            of the left and right operands.  As a side  effect,  the  sum  is
            stored  back  into the left operand.  The left operand must be an
            lvalue or a bit field (see FIELD_OP).  Both  operands  must  have
            the same mode as the ADDAA operation.  The operation mode may not
            be STOWED.

            ADDAA  stands  for  "add  and assign."  This operator is normally
            used to implement the addition assignment operator  ("+="  in  C,
            "+:=" in Algol 68).

            Example:  i += 1 (where i is an integer object with object id 12)
                     1              ADDAA_OP
                     1                 INT_MODE
                     40                OBJECT_OP
                     1                    INT_MODE
                     12                   Object id 12
                     9                 CONST_OP
                     1                    INT_MODE
                     1                    length is 1 word
                     1                    value of first word is 1




            AAADDDDDD___OOOPPP 222

            int 2
            int mode
            tree left
            tree right

            The  result  of this operator is an rvalue, the sum of the values
            of the left and right operands.  Both operands must have the same
            mode as the ADD, and STOWED mode is not allowed.

            ADD is used to implement simple addition  of  fixed  or  floating
            point values.

            Example:  i + 1 (where i is an integer object with object id 12)
                     2              ADD_OP
                     1                 INT_MODE
                     40                OBJECT_OP
                     1                    INT_MODE


                                         - 17 -                              




            


                     12                   Object id 12
                     9                 CONST_OP
                     1                    INT_MODE
                     1                    length is 1 word
                     1                    value of first word is 1




            AAANNNDDDAAAAAA___OOOPPP 333

            int 3
            int mode
            tree left
            tree right

            The  result  of  this  operator is an rvalue, the bitwise logical
            "and" of the values of the left and right operands.   As  a  side
            effect,  the  conjunction  is  stored back into the left operand.
            The left operand must be an lvalue or a bit field (see FIELD_OP).
            Both operands must have the same mode as the ANDAA operation; the
            only allowable modes  are  INT,  UNSIGNED,  LONG  INT,  and  LONG
            UNSIGNED.

            ANDAA  stands  for  "'and'  and  assign."   ANDAA_OP  is  used to
            implement the logical-and assignment operator ("&=" in C).

            Example:  i &= 1 (where i is an integer object with object id 12)
                     3              ANDAA_OP
                     1                 INT_MODE
                     40                OBJECT_OP
                     1                    INT_MODE
                     12                   Object id 12
                     9                 CONST_OP
                     1                    INT_MODE
                     1                    length is 1 word
                     1                    value of first word is 1




            AAANNNDDD___OOOPPP 444

            int 4
            int mode
            tree left
            tree right

            The result of this operator is an rvalue,  the  bitwise  logical-
            "and"  of  the  values  of  the  left  and  right operands.  Both
            operands must have the same mode as the AND operation;  the  only
            allowable modes are INT, LONG INT, UNSIGNED, and LONG UNSIGNED.

            AND_OP is normally used to implement the bitwise logical conjunc-
            tion  of  integers  ("&"  in  C).  Although AND_OP can be used to
            implement conjunction in Boolean expressions,  the  short-circuit


                                         - 18 -                              




            


            conjunction operator (SAND_OP) is probably a better choice, since
            it  guarantees  evaluation  order  and  prevents undesirable side
            effects.

            Example:  i & 1 (where i is an integer object with object id 12)
                     4              AND_OP
                     1                 INT_MODE
                     40                OBJECT_OP
                     1                    INT_MODE
                     12                   Object id 12
                     9                 CONST_OP
                     1                    INT_MODE
                     1                    length is 1 word
                     1                    value of first word is 1




            AAASSSSSSIIIGGGNNN___OOOPPP 555

            int 5
            int mode
            tree left
            tree right
            int length

            The result of this operator is an rvalue, namely the value of the
            right operand.  As a side effect, the result is stored  into  the
            left  operand.  The left operand must be an lvalue or a bit field
            (see FIELD_OP).  Both operands must have the  same  mode  as  the
            ASSIGN  operation.   Any  mode  is  allowable,  but the parameter
            'length' must be set to the operand length, in 16-bit words.

            ASSIGN implements the semantics of assignment statements in  most
            algorithmic languages.  Note that STOWED mode values are allowed,
            so things like Pascal record assignment can be handled.

            Example:  i = 1 (where i is anDDDDAAAAAA___OOOPPP 111

            int 1
            int mode
            tree left
            tree right

            The  result  of this operator is an rvalue, the sum of the values
            of the left and right operands.  As a side  effect,  the  sum  is
            stored  back  into the left operand.  The left operand must be an
            lvalue or a bit field (see FIELD_OP).  Both  operands  must  have
            the same mode as the ADDAA operation.  The operation mode may not
            be STOWED.

            ADDAA  stands  for  "add  and assign."  This operator is normally
            used to implement the addition assignment operator  ("+="  in  C,
            "+:=" in Algol 68).

            Example:  i += 1 (where i is an integer object with object id 12)
                     1              ADDAA_OP
                     1                 INT_MODE
                     40                OBJECT_OP
                     1                    INT_MODE
                     12                   Object id 12
                     9                 CONST_OP
                     1                    INT_MODE
                     1                    length is 1 word
                     1                    value of first word is 1




            AAADDDDDD___OOOPPP 222

            int 2
            int mode
            tree left
            tree right

            The  result  of this operator is an rvalue, the sum of the values
            of the left and right operands.  Both operands must have the same
            mode as the ADD, and STOWED mode is not allowed.

            ADD is used to implement simple addition  of  fixed  or  floating
            point values.

            Example:  i + 1 (where i is an integer object with object id 12)
                     2              ADD_OP
                     1                 INT_MODE
                     40                OBJECT_OP
                     1                    INT_MODE


                                         - 17 -                              




            


                     12                   Object id 12
                     9                 CONST_OP
                     1                    INT_MODE
                     1                    length is 1 word
                     1                    value of first word is 1




            AAANNNDDDAAAAAA___OOOPPP 333

            int 3
            int mode
            tree left
            tree right

            The  result  of  this  operator is an rvalue, the bitwise logical
            "and" of the values of the left and right operands.   As  a  side
            effect,  the  conjunction  is  stored back into the left operand.
            The left operand must be an lvalue or a bit field (see FIELD_OP).
            Both operands must have the same mode as the ANDAA operation; the
            only allowable modes  are  INT,  UNSIGNED,  LONG  INT,  and  LONG
            UNSIGNED.

            ANDAA  stands  for  "'and'  and  assign."   ANDAA_OP  is  used to
            implement the logical-and assignment operator ("&=" in C).

            Example:  i &= 1 (where i is an integer object with object id 12)
                     3              ANDAA_OP
                     1                 INT_MODE
                     40                OBJECT_OP
                     1                    INT_MODE
                     12                   Object id 12
                     9                 CONST_OP
                     1                    INT_MODE
                     1                    length is 1 word
                     1                    value of first word is 1




            AAANNNDDD___OOOPPP 444

            int 4
            int mode
            tree left
            tree right

            The result of this operator is an rvalue,  the  bitwise  logical-
            "and"  of  the  values  of  the  left  and  right operands.  Both
            operands must have the same mode as the AND operation;  the  only
            allowable modes are INT, LONG INT, UNSIGNED, and LONG UNSIGNED.

            AND_OP is normally used to implement the bitwise logical conjunc-
            tion  of  integers  ("&"  in  C).  Although AND_OP can be used to
            implement conjunction in Boolean expressions,  the  short-circuit


                                         - 18 -                              




            


            conjunction operator (SAND_OP) is probably a better choice, since
            it  guarantees  evaluation  order  and  prevents undesirable side
            effects.

            Example:  i & 1 (where i is an integer object with object id 12)
                     4              AND_OP
                     1                 INT_MODE
                     40                OBJECT_OP
                     1                    INT_MODE
                     12                   Object id 12
                     9                 CONST_OP
                     1                    INT_MODE
                     1                    length is 1 word
                     1                    value of first word is 1




            AAASSSSSSIIIGGGNNN___OOOPPP 555

            int 5
            int mode
            tree left
            tree right
            int length

            The result of this operator is an rvalue, namely the value of the
            right operand.  As a side effect, the result is stored  into  the
            left  operand.  The left operand must be an lvalue or a bit field
            (see FIELD_OP).  Both operands must have the  same  mode  as  the
            ASSIGN  operation.   Any  mode  is  allowable,  but the parameter
            'length' must be set to the operand length, in 16-bit words.

            ASSIGN implements the semantics of assignment statements in  most
            algorithmic languages.  Note that STOWED mode values are allowed,
            so things like Pascal record assignment can be handled.

            Example:  i = 1 (where i is an
