From df86573d4cf0d4e046b4b4f513d2a0f73d5d16f7 Mon Sep 17 00:00:00 2001 From: ceriel Date: Wed, 10 Dec 1986 11:40:00 +0000 Subject: [PATCH] Initial revision --- doc/top/Makefile | 6 + doc/top/refs.top | 79 +++++ doc/top/top.n | 792 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 877 insertions(+) create mode 100644 doc/top/Makefile create mode 100644 doc/top/refs.top create mode 100644 doc/top/top.n diff --git a/doc/top/Makefile b/doc/top/Makefile new file mode 100644 index 000000000..fa5ee63cb --- /dev/null +++ b/doc/top/Makefile @@ -0,0 +1,6 @@ +top.f: + refer -sA+T -l4,2 -p refs.top top.n | nroff -ms > top.f +top.f.35: + refer -sA+T -l4,2 -p refs.top top.n | nroff -ms -Thr35 > top.f.35 +top.f.agfa: + refer -sA+T -l4,2 -p refs.top top.n | nroff -ms -Tlp > top.f.agfa diff --git a/doc/top/refs.top b/doc/top/refs.top new file mode 100644 index 000000000..5cac9ed6b --- /dev/null +++ b/doc/top/refs.top @@ -0,0 +1,79 @@ +%T A Practical Toolkit for Making Portable Compilers +%A A.S. Tanenbaum +%A J.M. van Staveren +%A E.G. Keizer +%A J.W. Stevenson +%I Vrije Universiteit, Amsterdam +%R Rapport nr IR-74 +%D October 1981 + +%T A Practical Toolkit for Making Portable Compilers +%A A.S. Tanenbaum +%A J.M. van Staveren +%A E.G. Keizer +%A J.W. Stevenson +%J CACM +%V 26 +%N 9 +%P 654-660 +%D September 1983 + +%T A Unix Toolkit for Making Portable Compilers +%A A.S. Tanenbaum +%A J.M. van Staveren +%A E.G. Keizer +%A J.W. Stevenson +%J Proceedings USENIX conf. +%C Toronto, Canada +%V 26 +%D July 1983 +%P 255-261 + +%T Using Peephole Optimization on Intermediate Code +%A A.S. Tanenbaum +%A J.M. van Staveren +%A J.W. Stevenson +%J TOPLAS +%V 4 +%N 1 +%P 21-36 +%D January 1982 + +%T Amsterdam Compiler Kit documentation +%A A.S. Tanenbaum +%A E.G. Keizer +%A J.M. van Staveren +%A J.W. Stevenson +%I Vrije Universiteit, Amsterdam +%R Rapport nr IR-90 +%D June 1984 + +%T Language- and Machine-independant Global Optimization on +Intermediate Code +%A H.E. Bal +%A A.S. Tanenbaum +%I Vrije Universiteit, Amsterdam +%R Rapport IR-98 +%D March 1985 + +%T The Design and Implementation of the EM Global Optimizer +%A H.E. Bal +%I Vrije Universiteit, Amsterdam +%R Rapport IR-99 +%D March 1985 + + +%T The C Programming Language +%A B.W. Kernighan +%A D.M. Ritchie +%I Prentice-Hall, Inc +%C Englewood Cliffs,NJ +%D 1978 + +%T Principles of compiler design +%A A.V. Aho +%A J.D. Ullman +%I Addison-Wesley +%C Reading, Massachusetts +%D 1978 + diff --git a/doc/top/top.n b/doc/top/top.n new file mode 100644 index 000000000..5c524a7b8 --- /dev/null +++ b/doc/top/top.n @@ -0,0 +1,792 @@ +.ND +.pl 11.7i +.ll 80m +.nr LL 80m +.nr tl 78m +.tr ~ +.ds >. . +.TL +The ACK Target Optimizer +.AU +H.E. Bal +.AI +Vrije Universiteit +Wiskundig Seminarium, Amsterdam +.AB +The Target Optimizer is one of several optimizers that are part of +the Amsterdam Compiler Kit. +It operates directly on assembly code, +rather than on a higher level intermediate code, +as the Peephole Optimizer and Global Optimizer do. +Consequently, the Target Optimizer can do optimizations +that are highly machine-dependent. +.PP +Each target machine has its own Target Optimizer. +New optimizers are generated by the Target Optimizer Generator, +which uses a machine-dependent table as input. +This document contains full information on how to +write such a table for a new machine. +It also discusses the implementation of the +Target Optimizer and its generator. +.AE +.bp +.NH 1 +Introduction +.PP +.FS +This work was supported by the +Stichting Technische Wetenschappen (STW) +under grant VWI03.0001. +.FE +This document describes the target optimizer component +of the Amsterdam Compiler Kit (ACK) . +.[ +tanenbaum staveren amsterdam toolkit +.] +.[ +tanenbaum staveren cacm +.] +.[ +tanenbaum staveren toronto +.] +Optimization takes place in several parts of ACK compilers, +most notably in the Peephole Optimizer +.[ +staveren peephole toplas +.] +and +the Global Optimizer, +.[ +bal tanenbaum global optimization +.] +.[ +bal implementation global optimizer +.] +which are both language- and machine-independent, +and in the machine-specific code generators. +.[ +documentation amsterdam compiler kit +.] +The target optimizer is the finishing touch in this sequence of +optimizers. +It can be used to capture those optimizations that are hard +to express in the other parts of ACK. +These optimizations will typically be very machine-specific. +.PP +The target optimizer operates on the assembly code of some target machine. +Hence there is one target optimizer per machine. +However, just as for the ACK code generators and assemblers, +a framework has been build that allows easy generation of +target optimizers out of machine-independent parts and a +machine-dependent description table (see figure 1.). +So the major part of the code of a target optimizer is +shared among all target optimizers. +.DS + + + |-------------------------| + | machine-independent | + | code | + | | + |-----------------| |-------------------------| +descrip- |target optimizer | | machine-dependent code | + tion --> |generator | ----> | + tables | +table | | | | + |-----------------| |-------------------------| + + target optimizer + + Figure 1: Generation of a target optimizer. + +.DE +.PP +This document focusses on the description of the machine-dependent table. +In chapter 2 we give an informal introduction to the optimization +algorithm and to the definition of the table format. +Chapters 3 and 4 discuss the implementation of the target optimizer +and the target optimizer generator. +Appendix A gives full information for writing a description table. +.bp +.NH 1 +Global structure of the target optimizer +.PP +The target optimizer is based on the well understood model +of a \fIpeephole optimizer\fR. +.[ +aho ullman compiler +.] +It contains a machine-dependent table +of (pattern,replacement) pairs. +Each pattern describes +a sequence of one or more assembler instructions +that can be replaced by zero or more equivalent, yet cheaper, +instructions (the 'replacement'). +The optimizer maintains a \fIwindow\fR that moves over the input. +At any moment, the window contains some contiguous part of the input. +If the instructions in the current window match some pattern +in the table, +they are replaced by the corresponding replacement; +else, the window moves one instruction to the right. +.PP +In the remainder of this section we will give an informal +description of the machine-dependent table. +A more precise definition is given in appendix A. +We will first discuss the restrictions put on the +format of the assembly code. +.NH 2 +Assumptions about the assembly code format +.PP +We assume that a line of assembly code begins with an +instruction \fImnemonic\fR (opcode), +followed by zero or more \fIoperands\fR. +The mnemonic and the first operand must be separated by a special +character (e.g. a space or a tab). +Likewise, the operands must be separated by a special +character (e.g. a comma). +These separators need not be the same for all machines. +.NH 2 +Informal description of the machine-dependent tables +.PP +The major part of the table consists of (pattern,replacement) pairs +called \fIentries\fR. +.PP +A pattern is a list of instruction descriptions. +Each instruction description describes the instruction mnemonic and +the operands. +.PP +A mnemonic is described either by a string constant or by the +keyword ANY. +As all entities dealt with by the target optimizer are strings, +string constants do not contain quotes. +A string constant matches only itself. +ANY matches every instruction mnemonic. +.nf + +Examples of mnemonic descriptions: + + add + sub.l + mulw3 + ANY +.fi +.PP +An operand can also be described by a string constant. +.nf + +Examples: + + (sp)+ + r5 + -4(r6) + +.fi +Alternatively, it can be described by means of a \fIvariable name\fR. +Variables have values which are strings. +They have to be declared in the table before the patterns. +Each such declaration defines the name of a variable and +a \fIrestriction\fR to which its value is subjected. +.nf +Example of variable declarations: + + CONST { VAL[0] == '$' }; + REG { VAL[0] == 'r' && VAL[1] >= '0' && VAL[1] <= '3' && + VAL[2] == '\\0' }; + X { TRUE }; + +.fi +The keyword VAL denotes the value of the variable, which is +a null-terminated string. +An operand description given via a variable name matches an +actual operand if the actual operand obeys the associated restriction. +.nf + + CONST matches $1, $-5, $foo etc. + REG matches r0, r1, r2 and r3 + X matches anything +.fi +The restriction (between curly braces) may be any legal "C" +.[ +kernighan ritchie c programming +.] +expression. +It may also contain calls to user-defined procedures. +These procedures must be added to the table after the patterns. +.nf + +Example: + + FERMAT_NUMBER { VAL[0] == '$' && is_fermat_number(&VAL[1]) }; + +.fi +An operand can also be described by a mixture of a string constant +and a variable name. +The most general form allowed is: +.nf + + string_constant1 variable_name string_constant2 + +Example: + + (REG)+ matches (r0)+, (r1)+, (r2)+ and (r3)+ + +.fi +Any of the three components may be omitted, +so the first two forms are just special cases of the general form. +The name of a variable can not be used as a string constant. +In the above context, it is impossible to define an operand that +matches the string "REG". +This limitation is of little consequence, +as the table writer is free to choose the names of variables. +This approach, however, avoids the need for awkward escape sequences. +.PP +A pattern consists of one or more instruction descriptions +(separated by a colon) +followed by an optional constraint. +A pattern "P1 : P2 : .. : Pn C" matches the sequence of +instructions "I1 I2 .. In" if: +.IP (i) 7 +for each i, 1 <= i <= n, Pi matches Ii, as described above; +.IP (ii) +multiple occurrences of the same variable name or of +the keyword ANY stand for the same values throughout the pattern; +.IP (iii) +the optional constraint C is satisfied, i.e. it evaluates to TRUE. +.LP +.nf +The pattern: + + dec REG : move.b CONST,(REG) + +matches: + + dec r0 : move.b $4,(r0) + +but not: + + dec r0 : move.b $4,(r1) + +(as the variable REG matches two different strings). +.fi +If a pattern containing different registers must be described, +extra names for a register should be declared, all sharing +the same restriction. +.nf +Example: + + REG1,REG2 { VAL[0] == 'r' && ..... }; + + addl3 REG1,REG1,REG2 : subl2 REG2,REG1 +.fi +.PP +The optional constraint is an auxiliary "C" expression (just like +the parameter restrictions). +The expression may refer to the variables and to ANY. +.nf +Example: + + move REG1,REG2 { REG1[1] == REG2[1] + 1 } + +matches + + move r1,r0 + move r2,r1 + move r3,r2 +.fi +.PP +The replacement part of a (pattern,replacement) table entry +has the same structure as a pattern, except that: +.IP (i) +it may not contain an additional constraint; +.IP (ii) +it may be empty. +.LP +A replacement may also refer to the values of variables and ANY. +.NH 2 +Examples +.PP +This section contains some realistic examples for +optimization on PDP-11 and Vax assembly code. +.NH 3 +Vax examples +.PP +Suppose the table contains the following declarations: +.nf + X, LOG { TRUE }; + LAB { VAL[0] == 'L' }; /* e.g. L0017 */ + A { no_side_effects(VAL) }; + NUM { is_number(VAL) }; + +.fi +The procedure "no_side_effects" checks if its argument +contains any side effects, i.e. auto increment or auto decrement. +The procedure "is_number" checks if its argument contains only digits. +These procedures must be supplied by the table-writer and must be +included in the table. +.PP +.nf +\fIentry:\fR addl3 X,A,A -> addl2 X,A; + +.fi +This entry changes a 3-operand instruction into a cheaper 2-operand +instruction. +An optimization like: +.nf + + addl3 r0,(r2)+,(r2)+ -> addl2 r0,(r2)+ + +.fi +is illegal, as r2 should be incremented twice. +Hence the second argument is required to +be side-effect free. +.PP +.nf +\fIentry:\fR addw2 $-NUM,X -> subw2 $NUM,X; + +.fi +An instruction like "subw2 $5,r0" is cheaper +than "addw2 $-5,r0", +because constants in the range 0 to 63 are represented +very efficiently on the Vax. +.PP +.nf +\fIentry:\fR bitw $NUM,A : jneq LAB + { is_poweroftwo(NUM,LOG) } -> jbs $LOG,A,LAB; + +.fi +A "bitw x,y" sets the condition codes to the bitwise "and" of +x and y. +A "jbs n,x,l" branches to l if bit n of x is set. +So, for example, the following transformation is possible: +.nf + + bitw $32,r0 : jneq L0017 -> jbs $5,r0,L0017 + +.fi +The user-defined procedure "is_poweroftwo" checks if its first argument is +a power of 2 and, if so, sets its second argument to the logarithm +of the first argument. (Both arguments are strings). +Note that the variable LOG is not used in the pattern itself. +It is assigned a (string) value by "is_poweroftwo" and is used +in the replacement. +.NH 3 +PDP-11 examples +.PP +Suppose we have the following declarations: +.nf + X { TRUE }; + A { no_side_effects(VAL) }; + L1, L2 { VAL[0] == 'I' }; + REG { VAL[0] == 'r' && VAL[1] >= '0' && VAL[1] <= '5' && + VAL[2] == '\\0' }; + +.fi +The implementation of "no_side_effects" may of course +differ for the PDP-11 and the Vax. +.PP +.nf +\fIentry:\fR mov REG,A : ANY A,X -> mov REG,A : ANY REG,X ; + +.fi +This entry implements register subsumption. +If A and REG hold the same value (which is true after "mov REG,A") +and A is used as source (first) operand, it is cheaper to use REG instead. +.PP +.nf +\fIentry:\fR jeq L1 : jbr L2 : labdef L1 -> jne L2 : labdef L1; + +.fi +The "jeq L1" is a "skip over an unconditional jump". "labdef L1" +denotes the definition (i.e. defining occurrence) of label L1. +As the target optimizer has to know how such a definition +looks like, this must be expressed in the table (see Appendix A). +.PP +.nf +\fIentry:\fR add $01,X { carry_dead(REST) } -> inc X; + +.fi +On the PDP-11, an add-one is not equivalent to an increment. +The latter does not set the carry-bit of the condition codes, +while the former does. +So a look-ahead is needed to see if the rest of the input uses +the carry-bit before changing the condition codes. +A look-ahead of one instruction is provided by +the target optimizer. +This will normally be sufficient for compiler-generated code. +The keyword REST contains the mnemonic of the first instruction of +the rest of the input. +If this instruction uses the carry-bit (e.g. an adc, subc, bhis) +the transformation is not allowed. +.bp +.NH 1 +Implementation of the target optimizer +.PP +The target optimizer reads one input file of assembler instructions, +processes it, and writes the optimized code +to the output file. +So it performs one pass over the input. +.NH 2 +The window mechanism +.PP +The optimizer uses a \fIwindow\fR that moves over the input. +It repeatedly tries to match the instructions in the window +with the patterns in the table. +If no match is possible, the window moves +one instruction forwards (to the right). +After a successful match the matched instructions are +removed from the window and are replaced by the +replacement part of the table entry. +Furthermore, the window is moved a few instructions +backwards, +as it is possible that instructions that were rejected earlier now do match. +For example, consider the following patterns: +.DS +cmp $0, X -> tst X ; +mov REG,X : tst X -> move REG.X ; /* redundant test */ +.DE +If the input is: +.DS +mov r0,foo : cmp $0,foo +.DE +then the first instruction is initially rejected. +However, after the transformation +.DS +cmp $0,foo -> tst foo +.DE +the following optimization is possible: +.DS +mov r0,foo : tst foo -> mov r0,foo +.DE +.PP +The window is implemented a a \fIqueue\fR. +Matching takes place at the head of the queue. +New instructions are added at the tail. +If the window is moved forwards, the instruction at the head +is not yet written to the output, +as it may be needed later on. +Instead it is added to a second queue, +the \fIbackup queue\fR. +After a successful match, the entire backup queue is +inserted at the front of the window queue, +which effectively implements the shift backwards. +.PP +Both queues have the length of the longest pattern in the table. +If, as a result of a forward window move, +the backup queue gets full, +the instruction at its head is outputted and removed. +Instructions are read from the input whenever the +window queue contains fewer elements than the length +of the longest pattern. +.NH 2 +Pattern matching +.PP +Pattern matching is done in three steps: +.IP (i) 7 +find patterns in the table whose instruction mnemonics +match the mnemonics of the instructions in the +current window; +.IP (ii) +check if the operands of the pattern match the operands of the +instructions in the current window; +.IP (iii) +check if the optional constraint is satisfied. +.LP +For step (i) hashing is used. +The mnemonic of the first instruction of the window +is used to determine a list of possible patterns. +Patterns starting with ANY are always tried. +.PP +Matching of operand descriptions against actual operands +takes place as follows. +The general form of an operand description is: +.DS +string_constant1 variable_name string_constant2 +.DE +The actual operand should begin with string_constant1 and end +on string_constant2. +If so, these strings are stripped from it and the remaining string is +matched against the variable. +Matching a string against a variable is +defined as follows: +.IP 1. +initially (before the entire pattern match) +all variables are uninstantiated; +.IP 2. +matching a string against an uninstantiated variable +succeeds if the restriction associated with the variable is +satisfied. +As a side effect, it causes the variable to be instantiated to +the string; +.IP 3. +matching a string against an instantiated variable succeeds +only if the variable was instantiated to the same string. +.LP +Matching an actual mnemonic against the keyword ANY is defined likewise. +.PP +The matching scheme implements the requirement that multiple occurrences +of the same variable name or of the keyword ANY should +stand for the same values throughout the entire pattern +(see section 2.). +.PP +Both the parameter restriction of 2. and the constraint of step (iii) +are checked by executing the "C" expression. +.NH 2 +Data structures +.PP +The most important data structure is the representation +of the input instructions. +For every instruction we use two representations: +.IP (i) +the textual representation, +i.e. the exact code as it appeared in the input; +.IP (ii) +a structural representation, +containing the opcode and the operands. +.LP +The opcode of an instruction is determined as soon as it is read. +If the line contains a label definition, the opcode is set +to "labdef", so a label definition is treated like a normal +instruction. +.PP +The operands of an instruction are not determined until +they are needed, i.e. until step (i) of the pattern matching +process has succeeded. +For every instruction we keep track of a \fIstate\fR. +After the opcode has successfully been determined, +the state is OPC_ONLY. +Once the operands have been recognized, the state is set to DONE. +If the opcode or operands can not be determined, +or if the instruction cannot be optimized for any other +reason (see Appendix A), the state is set to JUNK +and any attempt to match it will fail. +.PP +For each table entry we record the following information: +.IP (i) 7 +the length of the pattern (i.e. the number of instruction descriptions) +.IP (ii) +a description of the instructions of the pattern +.IP (iii) +the length of the replacement +.IP (iv) +a description of the instructions of the replacement. +.LP +The description of an instruction consists of: +.IP (i) +the opcode +.IP (ii) +for each operand, a description of the operand. +.LP +The description of an operand of the form: +.DS +string_constant1 variable_name string_constant2 +.DE +contains: +.IP (i) +both string constants +.IP (ii) +the number of the variable. +.LP +Each declared variable is assigned a unique number. +For every variable we maintain: +.IP (i) +its state (instantiated or not instantiated) +.IP (ii) +its current value (a string). +.LP +The restrictions on variables and the constraints are stored +in a switch-statement, +indexed by variable number and entry number respectively. +.bp +.NH 1 +Implementation of the target optimizer generator +.PP +The target optimizer generator (\fItopgen\fR) +reads a target machine description table and produces +two files: +.IP gen.h: 9 +contains macro definitions for +machine parameters that were changed +in the parameter section of the table (see appendix A) +and for some attributes derived from the table +(longest pattern, number of patterns, number +of variables). +.IP gen.c: +contains the entry description tables, +code for checking the parameter restrictions and constraints +(switch statements) +and the user-defined procedures. +.LP +These two files are compiled together with some machine-independent +files to produce a target optimizer. +.PP +Topgen is implemented using +the LL(1) parser generator system LLgen, +a powerful tool of the Amsterdam Compiler Kit. +This system provides a flexible way of describing the syntax of the tables. +The syntactical description of the table format included +in Appendix A was derived from the LLgen syntax rules. +.PP +The parser uses a simple, hand-written, lexical analyzer (scanner). +The scanner returns a single character in most cases. +The recognition of identifiers is left to the parser, as +this eases the analysis of operand descriptions. +Comments are removed from the input by the scanner, +but white space is passed to the parser, +as it is meaningful in some contexts (it separates the +opcode description from the description of the first operand). +.PP +Topgen maintains two symbol tables, one for variable names and one +for tunable parameters. +The symbol tables are organized as binary trees. +.bp +.SH +Appendix A +.PP +In this appendix we present a complete definition of the target +optimizer description table format. +This appendix is intended for table-writers. +We use syntax rules for the description of the table format. +The following notation is used: +.nf + { a } zero or more of a + [ a ] zero or one of a + a b a followed by b + a | b a or b + +.fi +Terminals are given in quotes, as in ';'. +.PP +The table may contain white space and comment at all reasonable places. +Comments are as in "C", so they begin with /* and end on */. +Identifiers are sequences of letters, digits and the underscore ('_'), +beginning with a letter. +.PP +.DS +table -> {parameter_line} '%%;' {variable_declaration} '%%;' + {entry} '%%;' user_routines. + +.DE +A table consists of four sections, containing machine-dependent +constants, variable declarations, pattern rules and +user-supplied subroutines. +.PP +.DS +parameter_line -> identifier value ';' . + +.DE +A parameter line defines some attributes of the target machines +assembly code. +For unspecified parameters default values apply. +The names of the parameters and the corresponding defaults +are shown in table 1. +.DS + OPC_TERMINATOR ' ' + OP_SEPARATOR ',' + LABEL_STARTER 'I' + LABEL_TERMINATOR ':' + MAXOP 2 + MAXOPLEN 25 + MAX_OPC_LEN 10 + MAXVARLEN 25 + MAXLINELEN 100 + + table 1: parameter names and defaults +.DE +The OPC_TERMINATOR is the character that separates the instruction +mnemonic from the first operand (if any). +The OP_SEPARATOR separates adjacent operands. +A LABEL_STARTER is the first character of an instruction label. +(Instruction labels are assumed to start with the same character). +The LABEL_TERMINATOR is the last character of a label definition. +It is assumed that this character is not used in an applied +occurrence of the label identifier. +For example, the defining occurrence may be "I0017:" +and the applied occurrence may be "I0017" +as in "jmp I0017". +MAXOP defines the maximum number of operands an instruction can have. +MAXOPLEN is the maximum length (in characters) of an operand. +MAX_OPC_LEN is the maximum length of an instruction opcode. +MAXVARLEN is the maximum length of a declared string variable. +As variables may be set by user routines (see "bitw" example for +the Vax) the table-writer must have access to this length and +must be able to change it. +MAXLINELEN denotes the maximum length of a line of assembly code. +.PP +If a line of assembly code violates any of the assumptions or +exceeds some limit, +the line is not optimized. +Optimization does, however, proceed with the rest of the input. +.PP +.DS +variable_declaration -> identifier {',' identifier} restriction ';' . + +restriction -> '{' anything '}' . +.DE +A variable declaration declares one or more string variables +that may be used in the patterns and in the replacements. +If a variable is used as part of an operand description in +a pattern, the entire pattern can only match if the +restriction evaluates to TRUE. +If the pattern does match, the variable is assigned the matching +part of the actual operand. +Variables that are not used in a pattern are initialized to +null-strings and may be assigned a value in the constraint-part of +the pattern. +.PP +The restriction must be a legal "C" expression. +It may not contain a closing bracket ('}'). +Inside the expression, the name VAL stands for the part of the actual +(matching) operand. +The expression may contain calls to procedures that are defined in the +user-routines section. +.DS +entry -> pattern '->' replacement ';' . + +pattern -> instruction_descr + { ':' instruction_descr } + constraint . + +replacement -> [ instruction_descr { ':' instruction_descr } ] . + +instruction_descr -> opcode + white + [ operand_descr { ',' operand_descr } ] . + +constraint -> '{' anything '}' . + +operand_descr -> [ string_constant ] + [ variable_name ] + [ string_constant ] . + +variable_name -> identifier . + +opcode -> anything . +.DE +The symbol 'white' stands for white space (space or tab). +An opcode can be any string not containing the special +symbols ';', '{', '}', ':', ',', '->' or white space. +To be recognized, it must begin with a letter. +The opcode should either be a mnemonic of a target machine +instruction or it should be one of the keywords ANY and labdef. +ANY matches any actual opcode. labdef matches only label definitions. +.PP +If an operand description contains an identifier (as defined earlier), +it is checked if the identifier is the name of a declared variable. +This effects the semantics of the matching rules for the operand, +as described in section 2. +An operand may contain at most one such variable name. +.PP +The constraint must be a legal "C" expression, just as the operand restriction. +It may call user-defined procedures and use or change the value of +declared variables. +It may also use the string variable REST, +which contains the mnemonic of the first instruction of the +rest of the input. (REST is a null-string if this mnemonic can +not be determined). +.DS +user_routines -> anything . +.DE +The remainder of the table consists of user-defined subroutines. +.bp +.[ +$LIST$ +.] -- 2.34.1