Initial revision
This commit is contained in:
		
							parent
							
								
									96d9890d86
								
							
						
					
					
						commit
						df86573d4c
					
				
					 3 changed files with 877 additions and 0 deletions
				
			
		
							
								
								
									
										6
									
								
								doc/top/Makefile
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								doc/top/Makefile
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||
							
								
								
									
										79
									
								
								doc/top/refs.top
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										79
									
								
								doc/top/refs.top
									
										
									
									
									
										Normal file
									
								
							|  | @ -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 | ||||
| 
 | ||||
							
								
								
									
										792
									
								
								doc/top/top.n
									
										
									
									
									
										Normal file
									
								
							
							
						
						
									
										792
									
								
								doc/top/top.n
									
										
									
									
									
										Normal file
									
								
							|  | @ -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$ | ||||
| .] | ||||
		Loading…
	
	Add table
		
		Reference in a new issue