7. Design and Structure of LIR

7.1. Design of LIR

A compiler intermediate language is usually introduced as a private language that is specific to a certain compiler, and is known only to the compiler writers. However, many compiler bugs are caused by ambiguities in the specification of a compiler's intermediate language. Moreover, the COINS compiler is an open source program that can be freely modified and extended by any users. Thus, LIR is defined as an independent and self-contained programming language that has the constructs of a high-level language, such as variable declarations, and their formal semantics are defined by the ordinary denotational semantics.

All compiler back-end passes, including instruction selection by our code generator and register allocation, are regarded as program transformations in LIR, which preserve the formal semantics of LIR programs.

Consequently, LIR provides a concise interface for interaction with the compiler for users who want to replace part of the compiler with their own code.

A retargetable code generator is one that can produce object code for various target machines without any modification to the generator. In such a code generator, the characteristics of a target machine are described in the machine description language of the generator, which is independent of any target machine. Most recently developed retargetable code generators, such as Twig, Burg, etc., are based on the DP (Dynamic Programming) matching method. Their machine description language consists of rewriting rules with code generation actions. Theoretically, this method gives the best results. However, the rules that are used to describe a machine do not correspond directly to any of the existing instructions of the machine owing to the characteristics and theory of the DP method. This mismatch often makes the work of describing a machine a lengthy and somewhat onerous process.

On the other hand, the code generator that is used by GCC, one of the most widely used retargetable compilers, employs a unique method that differs considerably from the DP method. Its description language consists of descriptive statements that correspond to each of the target's existing machine instructions. However, GCC code generator still has some limitations that prevent it from producing optimal code.

Our code generator takes advantage of the good points of both the DP and GCC methods by translating the GCC descriptive statements into rewriting rules that are suitable for use by the DP matching method.

Furthermore, DP matching is also implemented as a kind of transformation of an LIR program, and later transformations such as register allocation are applied to the resulting LIR program. The description language of our code generator has a simple macro feature to improve expressiveness.

7.2. Structure of LIR

In this subsection, LIR is described by using examples to explain its overall structure. The examples are written in C, since it, like LIR, is a low-level language that is close to the actual hardware.

The program listings in Fig.7-1 are two C programs, main.c, and sub.c, in which the function prodv returns the product of all the elements of the array v using the function fold1.

main.c :   extern float fold1(float f(float,float), float v[], int n);
           static float v[] = {1, 2.5, 3};
           static int n = sizeof v / sizeof v[0];
           static float fmul(float x, float y){float r=x*y; return r;};
           float prodv(){return fold1(fmul,v,n);};

sub.c :    float fold1(float f(float,float), float v[], int n)
           {
             int i; float r;
             for (r=v[0], i=1; i<n; i++) r = f(r,v[i]);
             return r;
           }
Fig.7-1 A sample C program

The first C program `main.c' is translated into the LIR code shown in Fig.7-2, which is called an L-module. This information is produced as the file main.lir when the following options are specified.
-S -coins:suffixoption=out-newlir
The translation assumes that an int, a pointer, and a float are all 32 bits long. It also assumes that their required alignments are in the same four-byte boundary. Machine instructions and data are stored in the segments text and data, respectively.
 1 (MODULE "main.c"
 2   (SYMTAB
 3     ;; name  class  L-type align segment linkage
 4     ("prodv" STATIC UNKNOWN  4   ".text" XDEF)
 5     ("fmul"  STATIC UNKNOWN  4   ".text" LDEF)
 6     ("n"     STATIC I32      4   ".data" LDEF)
 7     ("v"     STATIC A96      4   ".data" LDEF)
 8     ("fold1" STATIC UNKNOWN  4   ".text" XREF))
 9   ;; definition of the function fmul
10   (FUNCTION "fmul"
11     (SYMTAB
12       ("x.1" FRAME F32 4 0)
13       ("y.2" FRAME F32 4 0)
14       ("r.3" FRAME F32 4 0)
15       ("returnvalue.4" FRAME F32 4 0))  ; generated by the translator
16     ;; L-sequence
17     (PROLOGUE (0 0) (MEM F32 (FRAME I32 "x.1")) (MEM F32 (FRAME I32 "y.2")))
18    (DEFLABEL "_lab1")
19     (SET F32 (MEM F32 (FRAME I32 "r.3"))     ; r = x*y
20              (MUL F32 (MEM F32 (FRAME I32 "x.1"))
21                       (MEM F32 (FRAME I32 "y.2"))))
22     (SET F32 (MEM F32 (FRAME I32 "returnvalue.4")) (MEM F32 (FRAME I32 "r.3")))
23     (JUMP (LABEL I32 "_epilogue"))
24    (DEFLABEL "_epilogue")
25     (EPILOGUE (0 0) (MEM F32 (FRAME I32 "returnvalue.4"))))
26   ;; definition of the function prodv
27   (FUNCTION "prodv"
28     (SYMTAB
29       ("returnvalue.5" FRAME F32 4 0)     ; generated by the translator
30       ("functionvalue.6" FRAME F32 4 0))  ; generated by the translator
31     (PROLOGUE (0 0))
32    (DEFLABEL "_lab3")
33     (CALL (STATIC I32 "fold1")     ; functionvalue.6=fold1(fmul,v,n)
34           ((STATIC I32 "fmul") (STATIC I32 "v") (MEM I32 (STATIC I32 "n")))
35           ((MEM F32 (FRAME I32 "functionvalue.6"))))
36     (SET F32 (MEM F32 (FRAME I32 "returnvalue.5")) (MEM F32 (FRAME I32 "functionvalue.6")))
37     (JUMP (LABEL I32 "_epilogue"))
38    (DEFLABEL "_epilogue")
39     (EPILOGUE (0 0) (MEM F32 (FRAME I32 "returnvalue.5"))))
40   ;; definition of the data v and n
41   (DATA "v" (F32 (FLOATCONST F32 1.0) (FLOATCONST F32 2.5) (FLOATCONST F32 3.0)))
42   (DATA "n" (I32 3)))
Fig.7-2 The LIR code for main.c

The syntax of LIR is built on top of S-expressions. A semicolon is used to indicate a comment. All of the characters following it in the same line are part of a comment. Also, the numbers that appear on the left side of the LIR listing are not part of LIR; they are used only as line references in the following explanation.

The listing in Fig.7-2 is an example of an L-module. An L-module consists of its module name, its symbol table, and the definitions of L-functions and L-data. An L-function definition consists of its name, its local symbol table, and its L-sequence. An L-sequence is a list of L-expressions beginning with a PROLOGUE expression and ending with an EPILOGUE expression. An L-data definition consists of its name and a list of its contents (line 41 and 42).

An symbol table, beginning with the keyword SYMTAB, consists of several entries. The first element of each entry is a name that is defined by the rest of the elements of the entry. The second element of each entry is called a class, which is used to dictate the syntax for the rest of the entry. It also determines how the entry's remaining definitions are to be interpreted. Names declared in symbol tables are referred to by L-expressions in L-functions that follow the same static scope rules as those that are found in the C programming language.

A name with the class STATIC represents a statically allocated object. A name with the class FRAME represents an object that is allocated on the stack frame. For example, in line 6 of the L-module main above, the name n is declared to be a statically allocated object having the L-type I32 (a 32-bit integer) along with its alignment, segment, and linkage information. An object's linkage information will always be one of three symbols, LDEF, XDEF, and XREF, which respectively mean that the name is locally defined, globally defined, or that the name is an external reference.

The declaration of x.1 (local symbol x is renamed to the unique name x.1) in line 12 is an example of a frame variable and another kind of L-type. F32 is the L-type that is used to designate 32-bit floating point numbers. The last 0 has no meaning when the LIR codes are generated. In the later phase of the backend process this field will be replaced by the offset of the frame variable from the frame pointer. Although we assume the existence of a frame pointer, we treat it implicitly. In line 7 of the module, the L-type of the name v is A96. It means the type of an object has 96-bits (12-bytes). We have introduced three kinds of L-types; namely, n-bit integers In, n-bit floats Fn, and just n-bits. These comprise all of the kinds of L-types that we use. The symbol UNKNOWN is used to indicate a type whose size is unknown to the compiler. UNKNOWN is not an L-type.

Line 10 shows an example of a function definition. Two L-expressions, PROLOGUE and EPILOGUE, are used to specify the interface of the L-function. They are collectively called interface expressions. The second element of the PROLOGUE expression in line 17 (and the second element of EPILOGUE), (0 0), was used in the older version of LIR to designate the size of the frame and the register frame to be allocated. In the current version It has no meaning. The remaining elements of the PROLOGUE expression specify the arguments of the L-function. The remaining elements of the EPILOGUE expression specify the list of expressions to be returned as multiple return values.

Line 19 shows a typical example of an L-expression. Unlike the corresponding C code r=x*y, it explicitly represents memory accesses using the expression (MEM type address), which refers to the object with the specified type and address. The frame expression (FRAME I32 "x.1") represents the address of the variable x.1 that was declared in line 12. I32 is the type of type address.

Line 33 shows an example of a function call. Its syntax has the form:

  (CALL addr (args ... ) (results ...))
where addr is the address of the function to be called, args are the L-expressions to be passed to the function, and results are the variables to which the multiple return values of the function will be assigned. As the CALL expression cannot be part of any other L-expression, the temporary variable `functionvalue.6' is introduced by the translator.

Line 34 shows an example of accessing a global (as in the C language) variable, where the L-expression (MEM I32 (STATIC I32 "n")) represents the address of the variable n that was declared in line 6.

This L-module does not have any examples of registers. In LIR, a register is expressed as (REG type name) and the name is declared in a symbol table as (name REG type offset), where type is the type of the register. There is no syntactic distinction between virtual and real registers.

As we have seen, our expressions for a calling convention are at a much higher level than the corresponding GCC expressions in RTL. To realize a calling convention with existing instructions is often called calling convention expansion.

GCC expands all of its calling conventions and designates some real registers at an early stage of its compilation process. The advantage of GCC's approach is that optimizers can achieve various machine specific optimizations. For example, as the stack pointer is a pre-allocated register, it explicitly exists throughout compiler passes; this enables optimizers to do some stack related optimizations, such as defer pop.

The disadvantage is that the approach makes optimizers so complex since function interface codes are already expanded. Code optimizers can hardly recover them from a given code; this disables optimizers to do some higher-level optimizations, such as inline expansion, tail recursion elimination, and partial evaluation.

The constructs of LIR for a (multiple-valued) function consisting of PROLOGUE, EPILOGUE, and CALL expressions enable the code optimizer to handle registers by making the following assumptions:

  1. Arbitrariness of register names:
    Renaming registers local to a function does not change the meaning of the function.
  2. Independence of registers:
    Assigning a register local to a function does not alter any other registers.
As the parameters of a function are specified in an interface expression, renaming them does not change the meaning of the function. Designating real registers before code optimization clearly makes the above assumptions impossible, as the registers will now have unique names that sometimes partly overlap.

The register must, of course, know everything about the real registers. Our intention in introducing such higher constructs was to clarify and simplify code optimizers by separating and delaying the designation of real registers.

We can describe all of the passes of a compiler including code optimization, instruction pattern matching, register allocation, and peephole optimization in terms of program transformations using LIR. With this in mind, the task of instruction selection that is based on a machine's description can be formalized as a program transformation that reforms each L-expression into one that expresses a real instruction of a real machine. The task of register allocation can also be formalized as a transformation to change local registers to global ones.

The translated L-module for sub.c is shown in Fig.7-3. Note that this example includes control structures.

 1 (MODULE "sub.c"
 2   (SYMTAB
 3     ("fold1" STATIC UNKNOWN 4 ".text" XDEF))
 4   (FUNCTION "fold1"
 5     (SYMTAB
 6       ("f.1" FRAME I32 4 0)
 7       ("v.2" FRAME I32 4 0)
 8       ("n.3" FRAME I32 4 0)
 9       ("i.4" FRAME I32 4 0)
10       ("r.5" FRAME F32 4 0)
11       ("returnvalue.6" FRAME F32 4 0))
12     (PROLOGUE (0 0) (MEM I32 (FRAME I32 "f.1")) 
13                     (MEM I32 (FRAME I32 "v.2"))
14                     (MEM I32 (FRAME I32 "n.3")))
15    (DEFLABEL "_lab1")
16     (SET F32 (MEM F32 (FRAME I32 "r.5"))      ; r = v[0]
17              (MEM F32 (ADD I32 (MEM I32 (FRAME I32 "v.2")) 
18                                (MUL I32 (INTCONST I32 4) (INTCONST I32 0)))))
19     (SET I32 (MEM I32 (FRAME I32 "i.4"))      ; i = 1
20              (INTCONST I32 1))    
21    (DEFLABEL "_lab5")
22    (JUMPC (TSTLTS I32 (MEM I32 (FRAME I32 "i.4"))   ; if (i<n) goto _lab6; else goto _lab4
23                       (MEM I32 (FRAME I32 "n.3"))) (LABEL I32 "_lab6") (LABEL I32 "_lab4"))
24   (DEFLABEL "_lab6")
25    (CALL (MEM I32 (FRAME I32 "f.1"))          ; r = f(r,v[i])
26          ((MEM F32 (FRAME I32 "r.5"))
27           (MEM F32 (ADD I32 (MEM I32 (FRAME I32 "v.2"))
28                             (MUL I32 (INTCONST I32 4)
29                                      (MEM I32 (FRAME I32 "i.4"))))))
30          ((MEM F32 (FRAME I32 "r.5"))))
31   (DEFLABEL "_lab3")
32    (SET I32 (MEM I32 (FRAME I32 "i.4"))       ; i++
33             (ADD I32 (MEM I32 (FRAME I32 "i.4"))
34                      (INTCONST I32 1)))
35    (JUMP (LABEL I32 "_lab5"))
36   (DEFLABEL "_lab4")
37    (SET F32 (MEM F32 (FRAME I32 "returnvalue.6")) (MEM F32 (FRAME I32 "r.5")))
38    (JUMP (LABEL I32 "_epilogue"))
39   (DEFLABEL "_epilogue")
40    (EPILOGUE (0 0) (MEM F32 (FRAME I32 "returnvalue.6")))))
Fig.7-3 The LIR code for sub.c

We never introduce `structured' control constructs such as if and while. The expression (DEFLABEL label) defines a label label which is referenced by jump expressions such as an unconditional jump as shown in line 35, a conditional jump as shown in line 22, and a multiway jump. An example of an indirect call is shown in line 25. The address expression in the CALL expression must evaluate to the address of an L-function. In our model, program memory is not an arbitrary list of L-expressions. Rather, it is a list of L-functions that can be invoked only by CALL expressions. At the same time, the targets of any jump expression are limited to those targets that are within the function to which the jump belongs.

7.3. Syntax and Semantics of LIR

7.3.1. Syntax of LIR

The Syntax of L-module and the syntax of L-expression are shown in Fig.7-4.
Syntax of L-module

<Lmod>          ::= (MODULE <Name> <GlobalSymtab> { <Ldata> | <Lfunc> })
<Name>          ::= <QuotedString>
<GlobalSymtab>  ::= (SYMTAB { <StaticSymbol> | <RegSymbol> })

<StaticSymbol>  ::= (<Name> STATIC <Ltype> <Align> <Segment> <Linkage>)
<RegSymbol>     ::= (<Name> REG    <Ltype> <Align> <Offset>)
<FrameSymbol>   ::= (<Name> FRAME  <Ltype> <Align> <Offset>)
<Align>         ::= <Fixnum>
<Offset>        ::= <Fixnum>
<Segment>       ::= <QuotedString>
<Linkage>       ::= LDEF | XDEF | XREF

<Ldata>         ::= (DATA <Name> { <DataSeq> | <ZeroSeq> | <SpaceSeq> })
<DataSeq>       ::= (<Ltype> { <Fixnum> | <Flonum> | <Lexp> })
<ZeroSeq>       ::= (ZEROS <Fixnum>)
<SpaceSeq>      ::= (SPACE <Fixnum>)

<Lfunc>         ::= (FUNCTION <Name> <LocalSymtab> <Lseq>)
<LocalSymtab>   ::= (SYMTAB { <FrameSymbol> | <RegSymbol> })
<Lseq>          ::= { <Lexp> }


Syntax of L-expression:

<Lexp>         ::= <TypedExp> | <UntypedExp>

<TypedExp>     ::= <AtomicTypedExp> | <NonAtomicTypedExp>
<AtomicTypedExp> ::= <ConstExp> | <AddrExp> | <RegExp>
<NonAtomixTypedExp> ::= <PureExp> | <MemExp> | <SetExp>
<UntypedExp>   ::= <JumpExp> | <DefLabelExp> | <CallExp>
                 | <InterfaceExp> | <SpecialExp> | <LineExp>
<Ltype>        ::= <Itype> | <Ftype> | <Atype>
<Itype>        ::= I8 | I16 | I32 | I64 | I128
<Ftype>        ::= F32 | F64 | F128
<Atype>        ::= A<Fixnum>

<ConstExp>     ::= (INTCONST <Itype> <Fixnum>)
                 | (FLOATCONST <Ftype> <Flonum>)

<AddrExp>      ::= <StaticExp> | <FrameExp> | <LabelExp>
<StaticExp>    ::= (STATIC <Ltype> <name>)
<FrameExp>     ::= (FRAME <Ltype> <name>)
<LabelExp>     ::= (LABEL <Ltype> <name>)

<RegExp>       ::= <SimpleRegExp> | <SubregExp>

<SimpleRegExp> ::= (REG <Ltype> <name>)
<SubregExp>    ::= (SUBREG <Ltype> <SimpleRegExp> <Fixnum>)
<PureExp>      ::= (<PureOp> <Ltype> <TypedExp> { <TypedExp> })

<PureOp>       ::= NEG | ADD | SUB | MUL | DIVS | DIVU | MODS | MODU
                 | BAND | BOR | BXOR | BNOT
                 | LSHS | LSHU | RSHS | RSHU
                 | CONVSX | CONVZX | CONVIT
                 | CONVFX | CONVFT | CONVFI | CONVSF | CONVUF
                 | TSTEQ | TSTNE | TSTLTS | TSTLES | TSTGTS
                 | TSTGES | TSTLTU | TSTLEU | TSTGTU | TSTGEU

<MemExp>       ::= (MEM <Ltype> <TypedExp> [&<MemModifier>])
<MemModifier>  ::= V | N
<SetExp>       ::= (SET <Ltype> <LvalueExp> <TypedExp>)
<LvalueExp>    ::= <MemExp> | <RegExp>
<JumpExp>      ::= (JUMP <LabelExp>)
                 | (JUMPC <TypedExp> <LabelExp> <LabelExp>)
                 | (JUMPN <TypedExp> ( { (<Fixnum> <LabelExp>) } ))

<DefLabelExp>  ::= (DEFLABEL <label>)
<label>        ::= <QuotedString>

<CallExp>      ::= (CALL <Callee> <Arguments> <Receivers>)
<Arguments>    ::= ( { <TypedExp> } )
<Receivers>    ::= ( { <LvalueExp> } )

<InterfaceExp> ::= <PrologueExp> | <EpilogueExp>
<PrologueExp>  ::= (PROLOGUE (<Fixnum> <Fixnum>) { <LvalueExp> })
<EpilogueExp>  ::= (EPILOGUE (<Fixnum> <Fixnum>) { <TypedExp> })

<SpecialExp>   ::= <ParallelExp> | <UseExp> | <ClobberExp>
<ParallelExp>  ::= (PARALLEL { <SetExp> | <CallExp> | <UseExp> | <ClobberExp> })
<UseExp>       ::= (USE { <RegExp> })
<ClobberExp>   ::= (CLOBBER { <RegExp> })

<LineExp>      ::= (LINE <Fixnum>)
Fig.7-4 Syntax of LIR

7.3.2. Semantics of LIR

Const-expression
(INTCONST t z)  t∈Itype
Integer value of z∈Z in type t
(FLOATCONST t r)  t∈Ftype
Float value of r∈R in typw t
Addr-expression

STATIC-expression represents the address of a global variable. FRAME-expression represents the address of a local vaariable. LABEL-expression represents the location of a L-function.

(STATIC t s)  t∈Itype
Address of the program memory or the data memory pointed by s∈String
(FRAME t s)  t∈Itype
Address of the data memory pointed by the sum of the offset indicated by s∈String and the frame pointer.
(LABEL t s)  t∈Itype
Location indicated by s∈String
Reg-expression
(REG t s)
Value of the register indicated by s∈String
(SUBREG t x n)

Value of the n-th sub-register of the register x

For example, (SUBREG I8 (REG I32 "x") 2) is the sub-register (bit16-bit23) of the register x, and (SUBREG I10 (REG I32 "x") 1) is the sub-register (bit10-bit19) of the register x.

Pure-expression
(NEG t x)  t = tx  (the same type)
Negation
(ADD t x y)  t = tx = ty
Addition
(SUB t x y)  t = tx = ty
Subtraction
(MUL t x y)  t = tx = ty
Multiplication
(DIVS t x y)  t = tx = ty
Signed division
(DIVU t x y)  t∈Itype∧t = tx = ty
Unsigned division
(MODS t x y)  t∈Itype∧t = tx = ty
Signed remainder
(MODU t x y)  t∈Itype∧t = tx = ty
Unsigned remainder
(CONVSX t x)  t,tx∈Itype
Sign extension
(CONVZX t x)  t,tx∈Itype
Zero extension
(CONVIT t x)  t,tx∈Itype
Conversion to shorter integer
(CONVFX t x)  t,tx∈Ftype
Conversion to higher precision floating point number
(CONVFT t x)  t,tx∈Ftype
Conversion to lower precision floating point number
(CONVFI t x)  t∈Itype∧tx∈Ftype
Conversion from floating point number to integer
(CONVSF t x)  t∈Ftype∧tx∈Itype
Conversion from signed integer to floating point number
(CONVUF t x)  t∈Ftype∧tx∈Itype
Conversion from unsigned integer to floating point number
(BAND t x y)  t∈Itype∧t = tx = ty
Logical and
(BOR t x y)  t∈Itype∧t = tx = ty
Logical or
(BXOR t x y)  t∈Itype∧t = tx = ty
Exclusive or
(BNOT t x)  t∈Itype∧t = tx
Logical complement
(LSHS t x y)  t,ty∈Itype∧t = tx

Signed left shift

(LSHU t x y)  t,ty∈Itype∧t = tx
Unsigned left shift
(RSHS t x y)  t,ty∈Itype∧t = tx
Signed right shift
(RSHU t x y)  t,ty∈Itype∧t = tx
Unsigned right shift
(TSTEQ t x y)  t∈Itype∧tx = ty
Comparison (x = y)
(TSTNE t x y)  t∈Itype∧tx = ty
Comparison (x≠y)
(TSTLTS t x y)  t∈Itype∧tx = ty
Signed comparison (x < y)
(TSTLES t x y)  t∈Itype∧tx = ty
Signed comparison (x≤y)
(TSTGTS t x y)  t∈Itype∧tx = ty
Signed comparison (x > y)
(TSTGES t x y)  t∈Itype∧tx = ty
Signed comparison (x≥y)
(TSTLTU t x y)  t,tx∈Itype∧tx = ty
Unsigned comparison (x < y)
(TSTLEU t x y)  t,tx∈Itype∧tx = ty
Unsigned comparison (x≤y)
(TSTGTU t x y)  t,tx∈Itype∧tx = ty
Unsigned comparison (x > y)
(TSTGEU t x y)  t,tx∈Itype∧tx = ty
Unsigned comparison (x≥y)
(ASMCONST t x)  t = tx∧isasmconst x
Same as x (Currently unsupported)
(PURE t x)  x∈IntConstExp
Any operation without side effect (Currently unsupported)
Mem-expression
(MEM t x)  tx∈Itype
Value of the object in the address x of the data memory
Set-expression
(SET t (MEM t' x) y)  t=t'=ty
Assign the value of y to the object in the address x
(SET t (REG t' s) x)  t=t'=tx
Assign the value of x to the register indicated by s
(SET t (SUBREG t' (REG tx s) n) x)  t=t'=tx
Assign the value of x to the n-th sub-register of s
Jump-expression
(JUMP l)
Jump to the location indicated by the label-expression l
(JUMPC x l1 l2)  x.code∈TstOps
Jump to l1 if the value of x is equal to 1, and jump to l2 if equal to 0
(JUMPN x ((c1 l1)...(cn ln)) l0)  tx∈Itype∧i≠j ⇒ ci≠cj
Jump to li if the value of integer x is equal to ci, otherwise jump to l0
DefLabel-expression
(DEFLABEL s)
Define label s
Call-expression
(CALL x1 (x2...xn) (y1...ym))
Call the L-function pointed by x1 with the actual parameter x2...xn. The return values are assigned to y1...ym
Interface-expression
(PROLOGUE (wf wr) x1...xn)

wf is the size of the frame, and wr is the size of the register fram (currently unsupported). xiis a formal parameter

(EPILOGUE (wf wr) x1...xn)

wf is the size of the frame, and wr is the size of the register fram (currently unsupported). xiis a return value.

Special-expression
(PARALLEL x1...xn)
Parallel execution of x1,...,xn.
xi is a SET-expression, a USE-expression, or a CLOBBER-expression.
(USE r1...rn)
Indicates that the registers r1,...,rn may be used.
(CLOBBER x1...xn)
Indicates that the registers x1,...,xn may be modified.
(PHI x (x1 l1)...(xn ln))

Φ function( x = Φ(x1,..., xn) )

Assign the value of xi to x if the preceeding basic block has label li

IF-expression
(IF t cond then else)  t = tthen = telse
If the value of cond-expression is true, return the value of then-expression, otherwise return the value of else-expression.
LINE-expression
(LINE N)
Indicates that the following L-expressions are generated from the line N of the source program.