2948 lines
		
	
	
	
		
			84 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
			
		
		
	
	
			2948 lines
		
	
	
	
		
			84 KiB
		
	
	
	
		
			Text
		
	
	
	
	
	
| .\" $Header$
 | |
| .RP
 | |
| .ND
 | |
| .TL
 | |
| The table driven code generator
 | |
| .br
 | |
| from the
 | |
| .br
 | |
| Amsterdam Compiler Kit
 | |
| .br
 | |
| Second Revised Edition
 | |
| .AU
 | |
| Hans van Staveren
 | |
| .AI
 | |
| Dept. of Mathematics and Computer Science
 | |
| Vrije Universiteit
 | |
| Amsterdam, The Netherlands
 | |
| .AB
 | |
| The Amsterdam Compiler Kit is a collection of tools
 | |
| designed to help automate the process of compiler building.
 | |
| Part of it is a table driven code generator,
 | |
| called
 | |
| .I cg ,
 | |
| and a program to check and translate machine description
 | |
| tables called
 | |
| .I cgg .
 | |
| This document provides a description of the internal workings of 
 | |
| .I cg ,
 | |
| and a description of syntax and semantics of the driving table.
 | |
| This is required reading for those wishing to write a new table.
 | |
| .AE
 | |
| .NH 1
 | |
| Introduction
 | |
| .PP
 | |
| Part of the Amsterdam Compiler Kit is a code generator system consisting
 | |
| of a code generator generator (\fIcgg\fP for short) and some machine
 | |
| independent C code.
 | |
| .I Cgg
 | |
| reads a machine description table and creates two files,
 | |
| tables.h and tables.c.
 | |
| These are then used together with other C code to produce
 | |
| a code generator for the machine at hand.
 | |
| .PP
 | |
| This in turn reads compact EM code and produces
 | |
| assembly code.
 | |
| The remainder of this document will first broadly describe
 | |
| the working of the code generator,
 | |
| then the machine table will be described after which
 | |
| some light is shed onto
 | |
| the internal workings of the code generator.
 | |
| .PP
 | |
| The reader is assumed to have at least a vague notion about the
 | |
| semantics of the intermediary EM code.
 | |
| Someone wishing to write a table for a new machine
 | |
| should be thoroughly acquainted with EM code
 | |
| and the assembly code of the machine at hand.
 | |
| .NH 1
 | |
| What has changed since version 1 ?
 | |
| .PP
 | |
| This chapter can be skipped by anyone not familiar with the first version.
 | |
| It is not needed to understand the current version.
 | |
| .PP
 | |
| This paper describes the second version of the code generator system.
 | |
| Although the code generator itself is for the main part unchanged,
 | |
| the table format has been drastically redesigned and the opportunities
 | |
| to make faulty tables are reduced.
 | |
| The format is now aesthaticly more pleasing (according to \fIme\fP that is),
 | |
| mainly because the previous version was designed for one line code rules,
 | |
| which did not work out that way.
 | |
| .PP
 | |
| The `SCRATCH' property is now automatically generated by
 | |
| .I cgg ,
 | |
| .I erase
 | |
| and
 | |
| .I setcc
 | |
| calls and their ilk are now no longer needed
 | |
| (read: can no longer be forgotten)
 | |
| and all this because the table now 
 | |
| .I knows
 | |
| what the machine instructions look like and what arguments they
 | |
| destroy.
 | |
| .PP
 | |
| Checks are now made for register types, so it is no longer possible
 | |
| to generate a `regind2' token with a floating point register as a base.
 | |
| In general, if the instructions of the machine are correctly defined,
 | |
| it is no longer possible to generate code that does not assemble,
 | |
| which of course does not mean that it is not possible to generate
 | |
| assembly code that does not do what was intended!
 | |
| .PP
 | |
| Checks are made now for missing moves, tests, coercions, etc.
 | |
| There is a form of procedure call now to reduce table size:
 | |
| it is no longer necessary to write the code for conditional
 | |
| instructions six times.
 | |
| .PP
 | |
| The inreg() pseudo-function returns other results!!
 | |
| .NH 1
 | |
| Global overview of the workings of the code generator.
 | |
| .PP
 | |
| The code generator or
 | |
| .I cg
 | |
| tries to generate good code by simulating the stack
 | |
| of the compiled program and delaying emission of code as long
 | |
| as possible.
 | |
| It also keeps track of register contents, which enables it to
 | |
| eliminate redundant moves, and tries to eliminate redundant tests
 | |
| by keeping information about condition code status,
 | |
| if applicable for the machine.
 | |
| .PP
 | |
| .I Cg
 | |
| maintains a `fake stack' containing `tokens' that are built
 | |
| by executing the pseudo code contained in the code rules given
 | |
| by the table writer.
 | |
| One can think of the fake stack as a logical extension of the real
 | |
| stack the compiled program will have when run.
 | |
| Alternatively one can think of the real stack as an infinite extension
 | |
| at the bottom of the fake stack.
 | |
| Both ways, the concatenation of the real stack and the fake stack
 | |
| will be the stack as it would have been on a real EM machine (see figure).
 | |
| .KF
 | |
| .DS L
 | |
| .ta 8 16 24 32 40 48 56 64 72
 | |
| 	   EM machine		 target machine
 | |
| 
 | |
| 	|		|	|		|
 | |
| 	|		|	|		|
 | |
| 	|		|	|		|
 | |
| 	|		|	|		|
 | |
| 	|		|	|   real stack	|
 | |
| 	|		|	|		|	|
 | |
| 	|		|	|		|	| growing
 | |
| 	|    EM stack	|	|		|	|
 | |
| 	|		|	|_______________|      \e|/
 | |
| 	|		|	|		|
 | |
| 	|		|	|		|
 | |
| 	|		|	|		|
 | |
| 	|		|	|   fake stack	|
 | |
| 	|		|	|		|
 | |
| 	|_______________|	|_______________|
 | |
| 
 | |
| 
 | |
| .I
 | |
| 	Relation between EM stack, real stack and fake stack.
 | |
| .R
 | |
| .DE
 | |
| .KE
 | |
| During code generation tokens will be kept on the fake stack as long
 | |
| as possible but when they are moved to the real stack,
 | |
| by generating code for the push,
 | |
| all tokens above\u*\d
 | |
| .FS
 | |
| * in this document the stack is assumed to grow downwards,
 | |
| although the top of the stack will mean the first element that will
 | |
| be popped.
 | |
| .FE
 | |
| the pushed tokens will be pushed also,
 | |
| so the fake stack will not contain holes.
 | |
| .PP
 | |
| The information about the machine that 
 | |
| .I cg
 | |
| needs has to be given in a machine description table,
 | |
| with as a major part a list of code rules telling 
 | |
| .I cg
 | |
| what to do when certain EM-instructions occur
 | |
| with certain tokens on the fake stack.
 | |
| Not all possible fake stack possibilities have to be given of course,
 | |
| there is a possibility for providing rewriting rules, or
 | |
| .I coercions
 | |
| as they are called in this document.
 | |
| .PP
 | |
| The main loop of
 | |
| .I cg
 | |
| is:
 | |
| .IP 1)
 | |
| find a pattern of EM instructions starting at the current one to
 | |
| generate code for.
 | |
| This pattern will usually be of length one but longer patterns can be used.
 | |
| Process any pseudo-instructions found.
 | |
| .IP 2)
 | |
| Select one of the possibly many stack patterns that go with this
 | |
| EM pattern on the basis of heuristics, look ahead or both.
 | |
| The cost fields provided in the token definitions and
 | |
| instruction definitions are used
 | |
| to compute costs during look ahead.
 | |
| .IP 3)
 | |
| Force the current fake stack contents to match the pattern.
 | |
| This may involve
 | |
| copying tokens to registers, making dummy transformations, e.g. to
 | |
| transform a `local' into an `indexed from register' or might even
 | |
| cause the move of the complete fake stack contents to the real stack
 | |
| and then back into registers if no suitable coercions
 | |
| were provided by the table writer.
 | |
| .IP 4)
 | |
| Execute the pseudocode associated with the code rule just selected,
 | |
| this may cause registers to be allocated,
 | |
| code to be emitted etc..
 | |
| .IP 5)
 | |
| Put tokens onto the fake stack to reflect the result of the operation.
 | |
| .IP 6)
 | |
| Insert some EM instructions into the stream;
 | |
| this is possible but not common.
 | |
| .IP 7)
 | |
| Account for the cost.
 | |
| The cost is kept in a (space, time) vector and look ahead decisions
 | |
| are based on a linear combination of these.
 | |
| The code generator calls on itself recursively during look ahead,
 | |
| and the recursive incarnations return the costs they made.
 | |
| The costs the top-level code generator makes is of course irrelevant.
 | |
| .PP
 | |
| The table that drives
 | |
| .I cg
 | |
| is not read in every time,
 | |
| but instead is used at compile time
 | |
| of
 | |
| .I cg
 | |
| to set parameters and to load pseudocode tables.
 | |
| A program called
 | |
| .I cgg
 | |
| reads the table and produces large lists of numbers that are
 | |
| compiled together with machine independent code to produce
 | |
| a code generator for the machine at hand.
 | |
| .PP
 | |
| Part of the information needed is not easily expressed in this table
 | |
| format and must be supplied in two separate files,
 | |
| mach.h and mach.c.
 | |
| Their contents are described later in this document.
 | |
| .NH 1
 | |
| Register variables
 | |
| .PP
 | |
| If the machine has more than enough registers to generate code with,
 | |
| it is possible to reserve some of them for use as register variables.
 | |
| If it has not, you can skip this section and ignore any references
 | |
| to register variables in the rest of this document.
 | |
| .PP
 | |
| The front ends generate messages to the back ends telling them which
 | |
| local variables could go into registers.
 | |
| The information given is the offset of the local, it's size and type
 | |
| and a scoring number, roughly the number of times it occurs.
 | |
| .PP
 | |
| The decision which variable to put in which register is taken by the
 | |
| machine independent part of
 | |
| .I cg
 | |
| with the help of a scoring function provided by the table writer in mach.c.
 | |
| The types of variables known are
 | |
| .IP reg_any 12
 | |
| Just a variable of some integer type.
 | |
| Nothing special known about it.
 | |
| .IP reg_float
 | |
| A floating point variable.
 | |
| .IP reg_loop
 | |
| A loop control variable.
 | |
| .IP reg_pointer
 | |
| A pointer variable.
 | |
| Usually they are better candidates to put in registers.
 | |
| .PP
 | |
| If you use register variables in your table you must supply
 | |
| more functions in mach.c.
 | |
| These functions are explained later.
 | |
| .NH 1
 | |
| Description of the machine table
 | |
| .PP
 | |
| The machine description table consists of the
 | |
| concatenation of the following sections:
 | |
| .IP 1)
 | |
| Constant definitions
 | |
| .IP 2)
 | |
| Property definitions
 | |
| .IP 3)
 | |
| Register definitions
 | |
| .IP 4)
 | |
| Token definitions
 | |
| .IP 5)
 | |
| Set definitions
 | |
| .IP 6)
 | |
| Instruction definitions
 | |
| .IP 7)
 | |
| Move definitions
 | |
| .IP 8)
 | |
| Test definitions
 | |
| .IP 9)
 | |
| Stack definitions
 | |
| .IP 10)
 | |
| Coercions
 | |
| .IP 11)
 | |
| Code rules
 | |
| .PP
 | |
| This is the order in the table
 | |
| but the descriptions in this document will use a slightly different
 | |
| order.
 | |
| All sections except the first start with an uppercase header word.
 | |
| Examples may be given in early stages that use knowledge that is explained
 | |
| in a later stage.
 | |
| If something is not clear the first time, please read on.
 | |
| All will clear up in a couple of pages.
 | |
| .PP
 | |
| Input is in free format, white space and newlines may be used
 | |
| at will to improve legibility.
 | |
| Identifiers used in the table have the same syntax as C identifiers,
 | |
| upper and lower case considered different, all characters significant.
 | |
| Here is a list of reserved words; all of these are unavailable as identifiers.
 | |
| .DS L
 | |
| .ta 14 28 42 56
 | |
| ADDR	STACK	from	reg_any	test
 | |
| COERCIONS	STACKINGRULES	gen	reg_float	to
 | |
| INSTRUCTIONS	TESTS	highw	reg_loop	ufit
 | |
| INT	TIMEFACTOR	inreg	reg_pointer	uses
 | |
| MOVES	TOKENS	kills	regvar	with
 | |
| PATTERNS	call	leaving	return	yields
 | |
| PROPERTIES	cost	loww	reusing	
 | |
| REGISTERS	defined	move	rom	
 | |
| SETS	exact	pat	samesign	
 | |
| SIZEFACTOR	example	proc	sfit	
 | |
| .DE
 | |
| C style comments are accepted.
 | |
| .DS
 | |
| /* this is a comment */
 | |
| .DE
 | |
| If the standard constant facility is not enough the C-preprocessor can
 | |
| be used to enhance the table format.
 | |
| .PP
 | |
| Integers in the table have the normal C-style syntax.
 | |
| Decimal by default, octal when preceded by a 0
 | |
| and hexadecimal when preceded by 0x.
 | |
| .NH 2
 | |
| Constant section
 | |
| .PP
 | |
| In the first part of the table some constants can be defined,
 | |
| most with the syntax
 | |
| .DS
 | |
| NAME=value
 | |
| .DE
 | |
| value being an integer or string.
 | |
| Three constants must be defined here:
 | |
| .IP EM_WSIZE 10
 | |
| Number of bytes in a machine word.
 | |
| This is the number of bytes
 | |
| a \fBloc\fP instruction will put on the stack.
 | |
| .IP EM_PSIZE
 | |
| Number of bytes in a pointer.
 | |
| This is the number of bytes
 | |
| a \fBlal\fP instruction will put on the stack.
 | |
| .IP EM_BSIZE
 | |
| Number of bytes in the hole between AB and LB.
 | |
| If the calling sequence just saves PC and LB this
 | |
| size will be twice the pointersize.
 | |
| .PP
 | |
| EM_WSIZE and EM_PSIZE are checked when a program is compiled
 | |
| with the resulting code generator.
 | |
| EM_BSIZE is used by
 | |
| .I cg
 | |
| to add to the offset of instructions dealing with locals
 | |
| having positive offsets,
 | |
| i.e. parameters.
 | |
| .PP
 | |
| Other constants can be defined here to be used as mnemonics
 | |
| later in the table.
 | |
| .PP
 | |
| Optional is the definition of a printformat for integers in the code file.
 | |
| This is given as
 | |
| .DS
 | |
| FORMAT = string
 | |
| .DE
 | |
| The string must be a valid printf(III) format,
 | |
| and defaults to "%d" or "%ld" depending on the wordsize of 
 | |
| the machine. For example on the PDP-11 one can use
 | |
| .DS
 | |
| FORMAT= "0%o"
 | |
| .DE
 | |
| to satisfy the old UNIX assembler that reads octal unless followed by
 | |
| a period, and the ACK assembler that follows C conventions.
 | |
| .PP
 | |
| Tables under control of programs like
 | |
| .I sccs
 | |
| or
 | |
| .I rcs
 | |
| can put their id-string here, for example
 | |
| .DS
 | |
| rcsid="$Header$"
 | |
| .DE
 | |
| These strings, like all strings in the table, will eventually
 | |
| end up in the binary code generator produced.
 | |
| .PP
 | |
| Optionally one can give the factors with which the size and time
 | |
| parts of the cost vector have to be multiplied to ensure they have the
 | |
| same order of magnitude.
 | |
| This can be done as
 | |
| .DS
 | |
| SIZEFACTOR = C\d3\u/C\d4\u
 | |
| TIMEFACTOR = C\d1\u/C\d2\u
 | |
| .DE
 | |
| Above numbers must be read as rational numbers.
 | |
| Defaults are 1/1 for both of them.
 | |
| These constants set the default size/time tradeoff in the code generator,
 | |
| so if TIMEFACTOR and SIZEFACTOR are both 1 the code generator will choose
 | |
| at random between two code sequences where one has
 | |
| cost (10,4) and the other has cost (8,6).
 | |
| See also the description of the cost field below.
 | |
| .NH 2
 | |
| Property definition
 | |
| .PP
 | |
| This part of the table defines the list of properties that can be used
 | |
| to differentiate between register classes.
 | |
| It consists of a list of user-defined 
 | |
| identifiers optionally followed by the size
 | |
| of the property in parentheses, default EM_WSIZE.
 | |
| Example for the PDP-11:
 | |
| .DS
 | |
| .ta 8 16 24 32 40
 | |
| PROPERTIES		/* The header word for this section */
 | |
| 
 | |
| GENREG			/* All PDP registers */
 | |
| REG			/* Normal registers (allocatable) */
 | |
| ODDREG			/* All odd registers (allocatable) */
 | |
| REGPAIR(4)		/* Register pairs for division */
 | |
| FLTREG(4)		/* Floating point registers */
 | |
| DBLREG(8)		/* Same, double precision */
 | |
| GENFREG(4)		/* generic floating point */
 | |
| GENDREG(8)		/* Same, double precision */
 | |
| FLTREGPAIR(8)		/* register pair for modf */
 | |
| DBLREGPAIR(16)		/* Same, double precision */
 | |
| LOCALBASE		/* Guess what */
 | |
| STACKPOINTER
 | |
| PROGRAMCOUNTER
 | |
| .DE
 | |
| Registers are allocated by asking for a property,
 | |
| so if for some reason in later parts of the table
 | |
| one particular register must be allocated it
 | |
| has to have a unique property.
 | |
| .PP
 | |
| There is a bug in the codegenerator that can be circumvented by
 | |
| providing a dummy property at the start of the property list.
 | |
| The example has not been updated to show this.
 | |
| .NH 2
 | |
| Register definition
 | |
| .PP
 | |
| The next part of the tables describes the various registers of the
 | |
| machine and defines identifiers
 | |
| to be used in later parts of the tables.
 | |
| Syntax:
 | |
| .DS
 | |
| <register definitions> : REGISTERS <list of definitions>
 | |
| <definition> : <registerlist> ':' <propertylist> <optional regvar> '.'
 | |
| <register> : ident [ '(' string ')' ] [ '=' ident [ '+' ident ] ]
 | |
| .DE
 | |
| Example for the PDP-11:
 | |
| .DS L
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| REGISTERS
 | |
| 
 | |
| r0,r2,r4				: GENREG,REG.
 | |
| r1,r3					: GENREG,REG,ODDREG.
 | |
| r01("r0")=r0+r1				: REGPAIR.
 | |
| fr0("r0"),fr1("r1"),fr2("r2"),fr3("r3") : GENFREG,FLTREG.
 | |
| dr0("r0")=fr0,dr1("r1")=fr1,
 | |
| 	dr2("r2")=fr2,dr3("r3")=fr3 	: GENDREG,DBLREG.
 | |
| fr01("r0")=fr0+fr1,fr23("r2")=fr2+fr3	: FLTREGPAIR.
 | |
| dr01("r0")=dr0+dr1,dr23("r2")=dr2+dr3	: DBLREGPAIR.
 | |
| lb("r5")				: GENREG,LOCALBASE.
 | |
| sp					: GENREG,STACKPOINTER.
 | |
| pc					: GENREG,PROGRAMCOUNTER.
 | |
| .DE
 | |
| .PP
 | |
| The names in the left hand lists are names of registers as used
 | |
| in the table.
 | |
| They can optionally be followed by a string in parentheses,
 | |
| their name as far as the assembler is concerned.
 | |
| The default assembler name is the same as the table name.
 | |
| A name can also be followed by
 | |
| .DS
 | |
| = othername
 | |
| .DE
 | |
| or
 | |
| .DS
 | |
| = othername + othername
 | |
| .DE
 | |
| which says that the register is composed of the parts
 | |
| after the '=' sign.
 | |
| The identifiers at the right hand side of the lists are
 | |
| names of properties.
 | |
| The end of each register definition is a period.
 | |
| .PP
 | |
| It might seem wise to list every property of a register,
 | |
| so one might give r0 the extra property MFPTREG named after the not
 | |
| too well known MFPT instruction on newer PDP-11 types,
 | |
| but this is not a good idea,
 | |
| especially since no use can be made of that instruction anyway.
 | |
| Every extra property means the register set is more unorthogonal
 | |
| and 
 | |
| .I cg
 | |
| execution time is influenced by that,
 | |
| because it has to take into account a larger set of registers
 | |
| that are not equivalent.
 | |
| So try to keep the number of different register classes to a minimum.
 | |
| When faced with the choice between two possible code rules
 | |
| for a nonfrequent EM sequence,
 | |
| one being elegant but requiring an extra property,
 | |
| and the other less elegant,
 | |
| elegance should probably loose.
 | |
| .PP
 | |
| Tables that implement register variables must mark registers to be used
 | |
| for variable storage here by following the list of properties by one
 | |
| of the following:
 | |
| .DS
 | |
| regvar \fIor\fP regvar(reg_any)
 | |
| regvar(reg_loop)
 | |
| regvar(reg_pointer)
 | |
| regvar(reg_float)
 | |
| .DE
 | |
| meaning they are candidates for that type of variable.
 | |
| All register variables of one type must be of the same size,
 | |
| and they may have no subregisters.
 | |
| Such registers are not available for normal code generation.
 | |
| .NH 2
 | |
| Stack token definition
 | |
| .PP
 | |
| The next part describes all possible tokens that can reside on
 | |
| the fake stack during code generation.
 | |
| Attributes of a token are described as a C struct declaration;
 | |
| this is followed by the size of the token in bytes,
 | |
| optionally followed by the cost of the token when used as an addressing mode
 | |
| and the format to be used on output.
 | |
| .PP
 | |
| In general, when writing a table, it is not wise to try
 | |
| to think of all necessary tokens in advance.
 | |
| While writing the necessity or advisability for some token
 | |
| will be seen and it can then be added together with the
 | |
| stacking rules and coercions needed.
 | |
| .PP
 | |
| Tokens should usually be declared for every addressing mode
 | |
| of the machine at hand and for every size directly usable in
 | |
| a machine instruction.
 | |
| Example for the PDP-11 (incomplete):
 | |
| .DS L
 | |
| TOKENS
 | |
| 
 | |
| const2 		= { INT num; } 2 cost(2,300) "$" num .
 | |
| addr_local 	= { INT ind; } 2 .
 | |
| addr_external 	= { ADDR off; } 2 "$" off.
 | |
| 
 | |
| regdef2 	= { GENREG reg; } 2 "*" reg.
 | |
| regind2 	= { GENREG reg; ADDR off; } 2 off "(" reg ")" .
 | |
| reginddef2 	= { GENREG reg; ADDR off; } 2 "*" off "(" reg ")" .
 | |
| regconst2	= { GENREG reg; ADDR off; } 2 .
 | |
| relative2	= { ADDR off; } 2 off .
 | |
| reldef2		= { ADDR off; } 2 "*" off.
 | |
| .DE
 | |
| .PP
 | |
| Types allowed in the struct are ADDR, INT and all register properties.
 | |
| The type ADDR means a string and an integer,
 | |
| which is output as string+integer,
 | |
| and arithmetic on mixed ADDR and INT is possible.
 | |
| This is the right mode for anything that can be an
 | |
| assembler address expression.
 | |
| The type of the register in the token is strict.
 | |
| At any assignment of an expression of type register to a token attribute
 | |
| of type register
 | |
| .I cgg
 | |
| will check if the set of possible results from the expression is a subset
 | |
| of the set of permissible values for the token attribute.
 | |
| .PP
 | |
| The cost-field is made up by the word
 | |
| .I cost
 | |
| followed by two numbers in parentheses, the size and timecosts
 | |
| of this token when output in the code file.
 | |
| If omitted, zero cost is assumed.
 | |
| While generating code,
 | |
| .I cg
 | |
| keeps track of a linear combination of these costs together
 | |
| with the costs of the instructions itself which we will see later.
 | |
| The coefficients of this linear combination are influenced
 | |
| by two things:
 | |
| .IP 1)
 | |
| The SIZEFACTOR and TIMEFACTOR constants,
 | |
| as mentioned above.
 | |
| .IP 2)
 | |
| A run time option to
 | |
| .I cg
 | |
| that can adjust the time/space tradeoff to all positions
 | |
| from 100% time to 100% space.
 | |
| .LP
 | |
| By supplying different code rules in certain situations
 | |
| it is possible to get a code generator that can adjust it's
 | |
| code to the need of the moment.
 | |
| This is probably most useful with small machines,
 | |
| experience has shown that on the larger micro's and mini's
 | |
| the difference between time-optimal and space-optimal code
 | |
| is often small.
 | |
| .PP
 | |
| The printformat consists of a list of strings intermixed with
 | |
| attributes from the token.
 | |
| Strings are output literally, attributes are printed according
 | |
| to their type and value.
 | |
| Tokens without a printformat should never be output,
 | |
| and
 | |
| .I cgg
 | |
| checks for this.
 | |
| .PP
 | |
| Notice that tokens need not correspond to addressing modes;
 | |
| the regconst2 token listed above,
 | |
| meaning the sum of the contents of the register and the constant,
 | |
| has no corresponding addressing mode on the PDP-11,
 | |
| but is included so that a sequence of add constant, load indirect,
 | |
| can be handled efficiently.
 | |
| This regconst2 token is needed as part of the path
 | |
| .DS
 | |
| REG -> regconst2 -> regind2
 | |
| .DE
 | |
| of which the first and the last "exist" and the middle is needed
 | |
| only as an intermediate step.
 | |
| .PP
 | |
| Tokens with name `LOCAL' or `DLOCAL' are a special case when
 | |
| register variables are used, this is explained further in the
 | |
| section on token descriptions.
 | |
| .NH 2
 | |
| Sets
 | |
| .PP
 | |
| Usually machines have certain collections of addressing modes that
 | |
| can be used with certain instructions.
 | |
| The stack patterns in the table are lists of these collections
 | |
| and since it is cumbersome to write out these long lists
 | |
| every time, there is a section here to give names to these
 | |
| collections.
 | |
| Please note that it is not forbidden to write out a set
 | |
| in the remainder of the table,
 | |
| but for clarity it is usually better not to.
 | |
| .LP
 | |
| Example for the PDP-11 (incomplete):
 | |
| .DS L
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| SETS
 | |
| 
 | |
| src2		= GENREG + regdef2 + regind2 + reginddef2 + relative2 +
 | |
| 		  reldef2 + addr_external + const2 + LOCAL + ILOCAL +
 | |
| 		  autodec + autoinc .
 | |
| dst2		= src2 - ( const2 + addr_external ) .
 | |
| xsrc2		= src2 + ftoint .
 | |
| src1		= regdef1 + regind1 + reginddef1 + relative1 + reldef1 .
 | |
| dst1		= src1 .
 | |
| src1or2		= src1 + src2 .
 | |
| src4		= relative4 + regdef4 + DLOCAL + regind4 .
 | |
| dst4		= src4 .
 | |
| .DE
 | |
| Permissible in the set construction are all the usual set operators, i.e.
 | |
| .IP +
 | |
| set union
 | |
| .IP -
 | |
| set difference
 | |
| .IP *
 | |
| set intersection
 | |
| .PP
 | |
| Normal operator priorities apply, and parentheses can be
 | |
| used.
 | |
| Every token identifier is also a set identifier
 | |
| denoting the singleton collection of tokens containing
 | |
| just itself.
 | |
| Every register property as defined above is also a set
 | |
| matching all registers with that property.
 | |
| The standard set identifier ALL denotes the collection of 
 | |
| all tokens.
 | |
| .NH 2
 | |
| Instruction definitions
 | |
| .PP
 | |
| In the next part of the table the instructions for the machine
 | |
| are declared together with information about their operands.
 | |
| Example for the PDP-11(very incomplete):
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| INSTRUCTIONS
 | |
| /* default cost */
 | |
| 
 | |
| cost(2,600)
 | |
| 
 | |
| /* Normal instructions */
 | |
| 
 | |
| adc dst2:rw:cc .
 | |
| add src2:ro,dst2:rw:cc cost(2,450).
 | |
| ash src2:ro,REG:rw:cc .
 | |
| ashc src2:ro,REGPAIR+ODDREG:rw .
 | |
| asl dst2:rw:cc .
 | |
| asr dst2:rw:cc .
 | |
| bhis "bcc" label .
 | |
| 
 | |
| /* floating point instructions */
 | |
| 
 | |
| movf "ldf" fsrc,freg .
 | |
| movf "stf" freg,fdst .
 | |
| .DE
 | |
| As the examples show an instruction definition consists of the name
 | |
| of the instruction,
 | |
| optionally followed by an assembler mnemonic in
 | |
| quotes-default is the name itself-and then
 | |
| a list of operands,
 | |
| optionally followed by the cost and then a period.
 | |
| If the cost is omitted the cost just after the word
 | |
| INSTRUCTIONS is assumed,
 | |
| if that is also omitted the cost is zero.
 | |
| The cost must be known by
 | |
| .I cg
 | |
| of course if it has multiple
 | |
| code generation paths to choose from.
 | |
| .PP
 | |
| For each operand we have the set of possible token values,
 | |
| followed by a qualifier that can be
 | |
| .IP :ro
 | |
| signifies that this operand is read only,
 | |
| so it can be replaced by a register with the same contents
 | |
| if available.
 | |
| .IP :rw
 | |
| signifies that the operand is read-write
 | |
| .IP :wo
 | |
| signifies that the operand is write only.
 | |
| .IP :cc
 | |
| says that after the instruction is finished, the condition codes
 | |
| are set to this operand.
 | |
| If none of the operands have the :cc qualifier set,
 | |
| .I cg
 | |
| will assume that condition codes were unaffected
 | |
| (but see below).
 | |
| .PP
 | |
| The first three qualifiers are of course mutually exclusive.
 | |
| The :ro qualifier does not cause any special action in the current
 | |
| implementation, and the :wo and :rw qualifiers are treated equal.
 | |
| It must be recommended however to be precise in the specifications,
 | |
| since later enhancements to the code generator might use them.
 | |
| .PP
 | |
| As the last examples show it is not necessary to give one definition
 | |
| for an instruction.
 | |
| There are machines that have very unorthogonal instruction sets,
 | |
| in fact most of them do,
 | |
| and it is possible to declare each possible combination
 | |
| of operands.
 | |
| The
 | |
| .I cgg
 | |
| program will check all uses of the instruction to find out which
 | |
| one was meant.
 | |
| .PP
 | |
| Although not in the PDP-11 example above there is a possibility
 | |
| to describe instructions that have side effects to registers not
 | |
| in the operand list.
 | |
| The only thing possible is to say that the instruction is destructive
 | |
| to some registers or the condition codes, by following the operand list
 | |
| with the word 
 | |
| .I kills
 | |
| and a list of the things destroyed.
 | |
| Example for some hypothetic accumulator machine:
 | |
| .DS
 | |
| add source2:ro kills ACCU :cc .
 | |
| .DE
 | |
| .PP
 | |
| The cost fields in the definitions for tokens and instructions
 | |
| are added together when generating code.
 | |
| It depends on the machine at hand whether the costs are orthogonal
 | |
| enough to make use of both these costs,
 | |
| in extreme cases every combination of instructions and operands
 | |
| can be given in this section,
 | |
| all with their own costs.
 | |
| .NH 2
 | |
| Expressions
 | |
| .PP
 | |
| Throughout the rest of the table expressions can be used in some
 | |
| places.
 | |
| This section will give the syntax and semantics of expressions.
 | |
| There are four types of expressions: integer, address, register and undefined.
 | |
| Really the type register is nonexistent as such,
 | |
| for each register expression
 | |
| .I cgg
 | |
| keeps a set of possible values,
 | |
| and this set can be seen as the real type.
 | |
| .PP
 | |
| Type checking is performed by
 | |
| .I cgg .
 | |
| An operator with at least one undefined operand returns undefined except
 | |
| for the defined() function mentioned below.
 | |
| An undefined expression is interpreted as FALSE when it is needed
 | |
| as a truth value.
 | |
| It is the responsibility of the table writer to ensure no undefined
 | |
| expressions are ever used as initialisers for token attributes.
 | |
| This is unfortunately almost impossible to check for
 | |
| .I cgg
 | |
| so be careful.
 | |
| .LP
 | |
| Basic terms in an expression are
 | |
| .IP number 16
 | |
| A number is a constant of type integer.
 | |
| Also usable is an identifier defined to a number in the constant
 | |
| definition section.
 | |
| .IP """string"""
 | |
| A string within double quotes is a constant of type address.
 | |
| All the normal C style escapes may be used within the string.
 | |
| Also usable is an identifier defined to a string in the constant
 | |
| definition section.
 | |
| .IP [0-9][bf]
 | |
| This must be read as a grep-pattern.
 | |
| It evaluates to a string that is the label name for the
 | |
| temporary label meant.
 | |
| More about this in the section on code rules.
 | |
| .IP REGIDENT
 | |
| The name of a register is a constant of type register.
 | |
| .IP $\fIi\fP
 | |
| A dollarsign followed by a number is the representation of the argument
 | |
| of EM instruction \fI\fP.
 | |
| The type of the operand is dependent on the instruction,
 | |
| sometimes it is integer,
 | |
| sometimes it is address.
 | |
| It is undefined when the instruction has no operand.
 | |
| Watch out for instructions with type-letter w.
 | |
| They can occur without an operand.
 | |
| Check for this in your code rule with the defined() pseudo function.
 | |
| .br
 | |
| If you cannot imagine the operand of the instruction ever to be
 | |
| something different from a plain integer, the type is integer,
 | |
| otherwise it is address.
 | |
| .br
 | |
| Those who want to know it exactly, the integer instruction types
 | |
| are the instructions marked with the
 | |
| type-letters c,f,l,n,o,s,r,w,z in the EM manual.
 | |
| .br
 | |
| .I Cg
 | |
| makes all necessary conversions for you,
 | |
| like adding EM_BSIZE to positive arguments of instructions
 | |
| dealing with locals,
 | |
| prepending underlines to global names,
 | |
| converting code labels into a unique representation etc.
 | |
| Details about this can be found in the section about
 | |
| machine dependent C code.
 | |
| .IP %1
 | |
| This in general means the token mentioned first in the
 | |
| stack pattern.
 | |
| When used inside an expression the token must be a simple register.
 | |
| Type of this is register.
 | |
| .IP %1.off
 | |
| This means attribute "off" of the first stack pattern token.
 | |
| Type is the same as that of attribute "off".
 | |
| To use this expression implies a check that all tokens
 | |
| in the set used have the same attribute in the same place.
 | |
| .IP %off
 | |
| This means attribute "off" in the `current' token.
 | |
| This can only be used when no confusion is possible about which token
 | |
| was meant, eg. in the optional boolean expressions following token sets
 | |
| in the move and test rules, in coercions or in the kills section inside
 | |
| the code rules.
 | |
| Same check as above.
 | |
| .IP %1.1
 | |
| This is the first subregister of the first token.
 | |
| Previous comments apply.
 | |
| .IP %b
 | |
| A percent sign followed by a lowercase letter
 | |
| stands for an allocated register.
 | |
| This is the second allocated register.
 | |
| .IP %a.2
 | |
| The second subregister of the first allocated register.
 | |
| .PP
 | |
| All normal C operators apply to integers,
 | |
| the + operator on addresses behaves as you would expect
 | |
| and the only operators allowed on register expressions
 | |
| are == and != .
 | |
| Furthermore there are some special `functions':
 | |
| .IP defined(e) 16
 | |
| Returns 1 if expression 
 | |
| .I e
 | |
| is defined, 0 otherwise.
 | |
| .IP samesign(e1,e2)
 | |
| Returns 1 if integer expression 
 | |
| .I e1
 | |
| and 
 | |
| .I e2
 | |
| have the same sign.
 | |
| .IP sfit(e1,e2)
 | |
| Returns 1 if integer expression 
 | |
| .I e1
 | |
| fits as a signed integer
 | |
| into a field of 
 | |
| .I e2
 | |
| bits, 0 otherwise.
 | |
| .IP ufit(e1,e2)
 | |
| Same as above but now for unsigned 
 | |
| .I e1 .
 | |
| .IP rom($a,n)
 | |
| Integer expression giving word
 | |
| .I n
 | |
| from the \fBrom\fP descriptor
 | |
| pointed at by EM instruction
 | |
| number
 | |
| .I a
 | |
| in the EM-pattern.
 | |
| Undefined if that descriptor does not exist.
 | |
| .IP loww($a)
 | |
| Returns the lower half of the argument of EM instruction number
 | |
| .I a .
 | |
| This is used to split the arguments of a \fBldc\fP instruction.
 | |
| .IP highw($a)
 | |
| Same for upper half.
 | |
| .LP
 | |
| The next two `functions' are only needed in a table that
 | |
| implements register variables.
 | |
| .IP inreg(e) 16
 | |
| Returns the status of the local variable with offset
 | |
| .I e
 | |
| from the localbase.
 | |
| Value is an integer,
 | |
| negative if the local was not allowed as a register
 | |
| variable,
 | |
| zero if it was allowed but not assigned to a register,
 | |
| and the type of the register if it was assigned to a register.
 | |
| This makes it possible to write
 | |
| .DS
 | |
| inreg($1)==reg_pointer
 | |
| .DE
 | |
| and similar things.
 | |
| .IP regvar(e,t)
 | |
| Type of this is register.
 | |
| It returns the register the local with offset
 | |
| .I e
 | |
| is assigned to.
 | |
| The table writer guarantees the register is one of type
 | |
| .I t ,
 | |
| with
 | |
| .I t
 | |
| one of reg_any, reg_loop, reg_pointer or reg_float.
 | |
| If
 | |
| .I t
 | |
| is omitted reg_any is assumed.
 | |
| Undefined if inreg(\fIe\fP)<=0 .
 | |
| .NH 2
 | |
| Token descriptions
 | |
| .PP
 | |
| Throughout the rest of the table tokens must be described,
 | |
| be it as operands of instructions or as stack-replacements.
 | |
| In all those cases we will speak about a token description.
 | |
| The possibilities for these will be described here.
 | |
| .PP
 | |
| All expressions of type register are token descriptions.
 | |
| The construct %1 means the token matched first in the stack pattern.
 | |
| All other token descriptions are those that are built on the spot.
 | |
| They look like this:
 | |
| .DS
 | |
| { <tokenname> , <list of token attribute initializing expressions> }
 | |
| .DE
 | |
| All expressions are type-checked by
 | |
| .I cgg ,
 | |
| and the number of initializers is also checked.
 | |
| .PP
 | |
| A special case of the last token descriptions occurs when
 | |
| the token name is `LOCAL' or `DLOCAL' and the table uses register
 | |
| variables. The first token attribute then must be of type integer and
 | |
| the token description is automagically replaced by the register chosen
 | |
| if the LOCAL (wordsize) or DLOCAL (twice the wordsize) was assigned
 | |
| to a register.
 | |
| .NH 2
 | |
| Code rules
 | |
| .PP
 | |
| The largest section of the tables consists of the code generation rules.
 | |
| They specify EM patterns, stack patterns, code to be generated etc.
 | |
| Broadly the syntax is
 | |
| .DS L
 | |
| code rule : EM-part code-part
 | |
| EM-part : EM-pattern | procedure-heading
 | |
| code-part : code-description | procedure-call
 | |
| code-description : stackpattern kills allocates generates yields leaving
 | |
| .DE
 | |
| Ignoring the "procedure"-part for now, the description for the EM-pattern
 | |
| and the code-description follows.
 | |
| Almost everything here is optional, the minimum code rule
 | |
| is:
 | |
| .DS
 | |
| pat nop
 | |
| .DE
 | |
| that will simply throw away
 | |
| .I nop
 | |
| instructions.
 | |
| .NH 3
 | |
| The EM pattern
 | |
| .PP
 | |
| The EM pattern consists of a list of EM mnemonics
 | |
| preceded by the word
 | |
| .I pat
 | |
| optionally followed by a boolean expression.
 | |
| Examples:
 | |
| .DS
 | |
| pat \fBloe\fP
 | |
| .DE
 | |
| will match a single \fBloe\fP instruction,
 | |
| .DS
 | |
| pat \fBloc\fP \fBloc\fP \fBcif\fP $1==2 && $2==8
 | |
| .DE
 | |
| is a pattern that will match
 | |
| .DS
 | |
| \fBloc\fP 2
 | |
| \fBloc\fP 8
 | |
| \fBcif\fP
 | |
| .DE
 | |
| and
 | |
| .DS
 | |
| pat \fBlol\fP \fBinc\fP \fBstl\fP $1==$3
 | |
| .DE
 | |
| will match for example
 | |
| .DS
 | |
| .ta 10m 20m 30m 40m 50m 60m
 | |
| \fBlol\fP 6	\fBlol\fP -2		\fBlol\fP 4
 | |
| \fBinc\fP	\fBinc\fP	but \fInot\fP	\fBinc\fP
 | |
| \fBstl\fP 6	\fBstl\fP -2		\fBstl\fP -4
 | |
| .DE
 | |
| A missing boolean expression evaluates to TRUE.
 | |
| .PP
 | |
| The code generator will match the longest EM pattern on every occasion,
 | |
| if two patterns of the same length match the first in the table will be chosen,
 | |
| while all patterns of length greater than or equal to three are considered
 | |
| to be of the same length.
 | |
| This rule of three is an unfortunate implementation dependent restriction,
 | |
| but patterns longer than three EM instructions are luckily not needed
 | |
| too often.
 | |
| .PP
 | |
| Following the EM-pattern there may be more than one code
 | |
| rule,
 | |
| .I cg
 | |
| will choose using heuristics and the cost
 | |
| information provided with the instruction and token
 | |
| definitions.
 | |
| Owing to parsing reasons of the table, the word
 | |
| .I with
 | |
| (see below)
 | |
| is mandatory when there are more code rules attached to one
 | |
| EM-pattern.
 | |
| The stack pattern may be empty however.
 | |
| .NH 3
 | |
| The stack pattern
 | |
| .PP
 | |
| The optional stack pattern is a list of token sets preceded by the word
 | |
| .I with .
 | |
| The token sets are usually represented by set identifiers for clarity.
 | |
| No boolean expression is allowed here.
 | |
| The first expression is the one that matches the top of the stack.
 | |
| .PP
 | |
| If the pattern is followed by the word STACK
 | |
| it only matches if there is nothing
 | |
| else on the fake stack,
 | |
| and the code generator will stack everything not matched at the start
 | |
| of the rule.
 | |
| .PP
 | |
| The pattern can be preceded with the word
 | |
| .I exact
 | |
| following the
 | |
| .I with
 | |
| that tells the code generator not to try to coerce to the pattern
 | |
| but only to use it when it is already present on the fake stack.
 | |
| There are two reasons for this construction,
 | |
| correctness and speed.
 | |
| It is needed for correctness when the pattern contains a register
 | |
| that is not transparent when data is moved through it.
 | |
| .LP
 | |
| Example: on the PDP-11 the shortest code for
 | |
| .DS
 | |
| \fBlae\fP a
 | |
| \fBloi\fP 8
 | |
| \fBlae\fP b
 | |
| \fBsti\fP 8
 | |
| .DE
 | |
| is
 | |
| .DS
 | |
| movf _a,fr0
 | |
| movf fr0,_b
 | |
| .DE
 | |
| if the floating point processor is in double
 | |
| precision mode and fr0 is free.
 | |
| Unfortunately this is not correct since a trap can occur on certain
 | |
| kinds of data.
 | |
| This could happen if there was a stack pattern for \fBsti\fP\ 8
 | |
| like this:
 | |
| .DS
 | |
| with DBLREG
 | |
| .DE
 | |
| The code generator would then find that coercing the 8-byte global _a
 | |
| to a floating point register and then storing it to _b was the cheapest,
 | |
| if the space/time knob was turned far enough to space.
 | |
| This can be prevented by changing the stack pattern to
 | |
| .DS
 | |
| with exact DBLREG
 | |
| .DE
 | |
| It is unfortunate that the type information is no longer present,
 | |
| since if _a really is a floating point number the move could be
 | |
| made without error.
 | |
| .PP
 | |
| The second reason for the 
 | |
| .I exact
 | |
| construct is speed.
 | |
| When the code generator has a long list of possible stack patterns
 | |
| for one EM pattern it can waste much time trying to find coercions
 | |
| to all of them, while the mere presence of such a long list
 | |
| indicates that the table writer has given many special cases.
 | |
| Prepending all the special cases by
 | |
| .I exact
 | |
| will stop the code generator from trying to find things
 | |
| that either cannot be done,
 | |
| or are too expensive anyway.
 | |
| .PP
 | |
| So in general it is wise to prepend all stack patterns that
 | |
| cannot be made by coercions with
 | |
| .I exact .
 | |
| .PP
 | |
| Using both
 | |
| .I exact
 | |
| and STACK in the stack pattern has the effect that the rule will
 | |
| only be taken if there is nothing else on the fake stack.
 | |
| .NH 3
 | |
| The kills part
 | |
| .PP
 | |
| The optional kills part describes certain tokens 
 | |
| that should neither remain on
 | |
| the fake stack, nor remembered as contents of registers.
 | |
| This is usually only required with store operations.
 | |
| The entire fake stack, except for the part matched in the stack pattern,
 | |
| is searched for tokens matching the expression and they are copied
 | |
| to the real stack.
 | |
| Every register that contains the token is marked as empty.
 | |
| .PP
 | |
| Syntax is
 | |
| .DS
 | |
| kills <list of things to kill separated by commas>
 | |
| thing to kill : token set optionally followed by boolean expression
 | |
| .DE
 | |
| Example:
 | |
| .DS
 | |
| kills regind2 %reg != lb || %off == $1
 | |
| .DE
 | |
| is a kills part used for example in the \fBinl\fP or \fBstl\fP code rule.
 | |
| It removes all register offsetted tokens where the register is not the
 | |
| localbase plus the local in which the store is done.
 | |
| The necessity for this can be seen from the following example:
 | |
| .DS
 | |
| \fBlol\fP 4
 | |
| \fBinl\fP 4
 | |
| \fBstl\fP 6
 | |
| .DE
 | |
| Without a proper kills part in the rule for \fBinl\fP code would
 | |
| be generated as here
 | |
| .DS
 | |
| inc 4(r5)
 | |
| mov 4(r5),6(r5)
 | |
| .DE
 | |
| so local 6 would be given the new value of local 4 instead of the old
 | |
| as the EM code prescribed.
 | |
| .PP
 | |
| When generating code for an EM-instruction like
 | |
| .B sti
 | |
| it is necessary to write a line in the table like
 | |
| .DS
 | |
| kills all_except_constant_or_register
 | |
| .DE
 | |
| where the long identifier is a set containing all tokens
 | |
| that can be the destination of some random indirect store.
 | |
| These indirect stores are the main reason to prevent this
 | |
| .I kills
 | |
| line to be deduced automatically by
 | |
| .I cgg .
 | |
| .PP
 | |
| When generating something like a branch instruction it 
 | |
| might be needed to empty the fake stack completely.
 | |
| This can of course be done with
 | |
| .DS
 | |
| kills ALL
 | |
| .DE
 | |
| or by ending the stack pattern with the word STACK, which is equivalent,
 | |
| if the stack pattern does not start with
 | |
| .I exact .
 | |
| .PP
 | |
| It is unfortunate that this part is still present in the table
 | |
| but it is too much for now to let the
 | |
| .I cgg
 | |
| program discover what rules ruin what kind of tokens.
 | |
| Maybe some day .....
 | |
| .NH 3
 | |
| The allocates part
 | |
| .PP
 | |
| The optional register allocation part describes the registers needed.
 | |
| Syntax is
 | |
| .DS
 | |
| uses <list of use elements separated by commas>
 | |
| .DE
 | |
| where itemlist is a list of three kinds of things:
 | |
| .IP 1)
 | |
| .I reusing
 | |
| < a token description >, for example %1.
 | |
| .br
 | |
| This will instruct the code generator that all registers
 | |
| contained in this token can be reused if they are not used
 | |
| in another token on the fakestack,
 | |
| so that they are available for allocation in this 
 | |
| .I uses
 | |
| line
 | |
| if they were only used in that token.
 | |
| See example below.
 | |
| .IP 2)
 | |
| a register property.
 | |
| .br
 | |
| This will allocate a register with that property,
 | |
| that is marked as empty at this point.
 | |
| Look ahead can be performed if there is more than one register available.
 | |
| .IP 3)
 | |
| a register property with initialization.
 | |
| .br
 | |
| This will allocate the register as in 2) but will also
 | |
| initialize it.
 | |
| This eases the task of the code generator because it can
 | |
| find a register already filled with the right value
 | |
| if it exists.
 | |
| .LP
 | |
| Examples:
 | |
| .DS
 | |
| uses ODDREG
 | |
| .DE
 | |
| will allocate an odd register, while 
 | |
| .DS
 | |
| uses REG={regind2,lb,$1}
 | |
| .DE
 | |
| will allocate a register while simultaneously filling it with
 | |
| the asked value.
 | |
| .br
 | |
| Inside the coercion from xsrc2 to REG in the PDP-11 table
 | |
| the following line can be found.
 | |
| .DS
 | |
| uses reusing %1, REG=%1
 | |
| .DE
 | |
| This tells the code generator that registers contained in %1 can be used
 | |
| again and asks to fill the register allocated with %1.
 | |
| So if %1={regind2,r3,"4"} and r3 is not in use elsewhere on the fake stack
 | |
| the following code might be generated.
 | |
| .DS
 | |
| mov 4(r3),r3
 | |
| .DE
 | |
| In the rest of the line the registers allocated can be named by
 | |
| %a and %b.1,%b.2, i.e. with lower case letters
 | |
| in order of allocation.
 | |
| .NH 3
 | |
| The generates part
 | |
| .PP
 | |
| Code to be generated, also optionally, is specified as
 | |
| the word
 | |
| .I gen
 | |
| followed by a list of items of the following kind:
 | |
| .IP 1)
 | |
| An instruction name followed by a comma-separated
 | |
| list of token descriptions.
 | |
| .I Cgg
 | |
| will search the instruction definitions for the machine to find a suitable
 | |
| instruction.
 | |
| At code generation time the assembler name of the
 | |
| instruction will be output followed by a space,
 | |
| followed by a comma separated list of tokens.
 | |
| .br
 | |
| In the table an instruction without operands must be
 | |
| followed by a period.
 | |
| The author of
 | |
| .I cgg
 | |
| could not get 
 | |
| .I yacc
 | |
| to be silent without it.
 | |
| Sorry about this.
 | |
| .IP 2)
 | |
| a 
 | |
| .I move
 | |
| call.
 | |
| This has the following syntax:
 | |
| .DS
 | |
| move <token description>,<token description>
 | |
| .DE
 | |
| Moves are handled specially since that enables the code generator
 | |
| to keep track of register contents.
 | |
| Example:
 | |
| .DS
 | |
| move r3,{regind2,lb,$1}
 | |
| .DE
 | |
| will generate code to move r3 to $1(r5) except when
 | |
| r3 already was a copy of $1(r5).
 | |
| Then the code will be omitted.
 | |
| The rules describing how to move things to each other
 | |
| can be found in the move definitions section described below.
 | |
| .IP 3)
 | |
| For machines that have condition codes,
 | |
| which alas most of them do,
 | |
| there are provisions to remember condition code settings
 | |
| and prevent needless testing.
 | |
| To set the condition code to a token put in the code the following call:
 | |
| .DS
 | |
| test <token description>
 | |
| .DE
 | |
| This will generate a test if the condition codes 
 | |
| were not already set to that token.
 | |
| The rules describing how to test things
 | |
| can be found in the test definitions section described below.
 | |
| See also the :cc qualifier that can be used at instruction
 | |
| definition time.
 | |
| .IP 4)
 | |
| The
 | |
| .I return
 | |
| statement.
 | |
| Only used when register variables are in use.
 | |
| This statement causes a call to the machine dependent
 | |
| C-routine 
 | |
| .I regreturn .
 | |
| Explanation of this must wait for the description of the
 | |
| file mach.c below.
 | |
| .IP 5)
 | |
| A temporary label of the form <digit>: may be placed here.
 | |
| Expressions of the form [0-9][bf] in this code rule
 | |
| generate the same string as is used for this label.
 | |
| The code generator system could probably easily be changed
 | |
| to make this work for assemblers that do not support this
 | |
| type of label by generating unique labels itself.
 | |
| Implementation of this is not contemplated at the moment,
 | |
| bad luck if your assembler cannot do it.
 | |
| .NH 3
 | |
| Stack replacement
 | |
| .PP
 | |
| The optional stack replacement is a possibly empty list 
 | |
| of tokens to be pushed onto the fake stack.
 | |
| It start with the word
 | |
| .I yields ,
 | |
| and is followed by a list of token descriptions.
 | |
| .PP
 | |
| All tokens matched by the stack pattern at the beginning of the code rule
 | |
| are first removed and their registers deallocated.
 | |
| Items are pushed in the order of appearance.
 | |
| This means that the last item will be on the top of the
 | |
| stack after the push.
 | |
| So if the stack pattern contained two sets
 | |
| and you want to push them back unchanged,
 | |
| you have to specify as stack replacement
 | |
| .DS
 | |
| yields %2 %1
 | |
| .DE
 | |
| and not the other way around.
 | |
| This is known to cause errors in tables so watch out for
 | |
| this!
 | |
| .NH 3
 | |
| EM replacement
 | |
| .PP
 | |
| In exceptional cases it might be useful to leave part of an EM-pattern
 | |
| undone.
 | |
| For example, a \fBsdl\fP instruction might 
 | |
| be split into two \fBstl\fP instructions
 | |
| when there is no 4-byte quantity on the stack.
 | |
| The EM replacement part allows
 | |
| one to express this.
 | |
| It is activated by the word
 | |
| .I leaving .
 | |
| .LP
 | |
| Example:
 | |
| .DS
 | |
| leaving \fBstl\fP $1 \fBstl\fP $1+2
 | |
| .DE
 | |
| The instructions are inserted in the stream so that they can match
 | |
| the first part of a pattern in the next step.
 | |
| Note that since the code generator traverses the EM instructions in a strict
 | |
| linear fashion,
 | |
| it is impossible to let the EM replacement match later parts of a pattern.
 | |
| So if there is a pattern
 | |
| .DS
 | |
| \fBloc\fP \fBstl\fP $1==0
 | |
| .DE
 | |
| and the input is
 | |
| .DS
 | |
| \fBloc\fP 0 \fBsdl\fP 4
 | |
| .DE
 | |
| the \fBloc\fP\ 0 will be processed first,
 | |
| then the \fBsdl\fP might be split into two \fBstl\fP's but the pattern
 | |
| cannot match now.
 | |
| .NH 3
 | |
| Examples
 | |
| .PP
 | |
| A list of examples for the PDP-11 is given here.
 | |
| Far from being complete it gives examples of most kinds
 | |
| of instructions.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat loc					yields {const2, $1}
 | |
| 
 | |
| pat ldc					yields {const2, loww($1)}
 | |
| 					       {const2, highw($1)}
 | |
| .DE
 | |
| These simple patterns just push one or more tokens onto the fake stack.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat lof
 | |
| with REG				yields {regind2,%1,$1}
 | |
| with exact regconst2 			yields {regind2,%1.reg,$1+%1.off}
 | |
| with exact addr_external		yields {relative2,$1+%1.off}
 | |
| with exact addr_local			yields {LOCAL, %1.ind + $1,2}
 | |
| .DE
 | |
| This pattern shows the possibility to do different things
 | |
| depending on the fake stack contents,
 | |
| there are some rules for some specific cases plus a general rule,
 | |
| not preceded by
 | |
| .I exact
 | |
| that can always be taken after a coercion,
 | |
| if necessary.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat lxl $1>3
 | |
| uses REG={LOCAL, SL, 2},
 | |
|      REG={const2,$1-1}
 | |
| gen 1:
 | |
|     move {regind2,%a, SL},%a
 | |
|     sob %b,{label,1b}			yields %a
 | |
| .DE
 | |
| This rule shows register allocation with initialisation,
 | |
| and the use of a temporary label.
 | |
| The constant SL used here is defined to be the offset from lb
 | |
| of the static link,
 | |
| that is pushed by the Pascal compiler as the last argument of
 | |
| a function.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat stf
 | |
| with regconst2 xsrc2
 | |
|   kills allexeptcon
 | |
|   gen move %2,{regind2,%1.reg,$1+%1.off}
 | |
| with addr_external xsrc2
 | |
|   kills allexeptcon
 | |
|   gen move %2,{relative2,$1+%1.off}
 | |
| .DE
 | |
| This rule shows the use of a
 | |
| .I kills
 | |
| part in a store instruction.
 | |
| The set allexeptcon contains all tokens that can be the destination
 | |
| of an indirect store.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat sde
 | |
| with exact FLTREG
 | |
|   kills posextern
 | |
|   gen move %1,{relative4,$1}
 | |
| with exact ftolong
 | |
|   kills posextern
 | |
|   gen setl.
 | |
|       movfi %1.reg,{relative4,$1}
 | |
|       seti.
 | |
| with src2 src2
 | |
|   kills posextern
 | |
|   gen move %1, {relative2, $1 }
 | |
|       move %2, {relative2, $1+2}
 | |
| .DE
 | |
| The rule for
 | |
| .B sde
 | |
| shows the use of the
 | |
| .I exact
 | |
| clause in both qualities,
 | |
| the first is for correctness,
 | |
| the second for efficiency.
 | |
| The third rule is taken by default,
 | |
| resulting in two separate stores,
 | |
| nothing better exists on the PDP-11.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat sbi $1==2
 | |
| with src2 REG
 | |
|   gen sub %1,%2				yields %2
 | |
| with exact REG src2-REG
 | |
|   gen sub %2,%1
 | |
|       neg %1				yields %1
 | |
| .DE
 | |
| This rule for
 | |
| .I sbi
 | |
| has a normal first part,
 | |
| and a hand optimized special case as it's second part.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat mli $1==2
 | |
| with ODDREG src2
 | |
|   gen mul %2,%1				yields %1
 | |
| with src2 ODDREG
 | |
|   gen mul %1,%2				yields %2
 | |
| .DE
 | |
| This shows the general property for rules with commutative
 | |
| operators,
 | |
| heuristics or look ahead will have to decide which rule is the best.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat loc sli $1==1 && $2==2
 | |
| with REG
 | |
| gen asl %1				yields %1
 | |
| .DE
 | |
| A simple rule involving a longer EM-pattern,
 | |
| to make use of a specialized instruction available.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat loc loc cii $1==1 && $2==2
 | |
| with src1or2
 | |
| uses reusing %1,REG
 | |
| gen movb %1,%a				yields %a
 | |
| .DE
 | |
| A somewhat more complicated example of the same.
 | |
| Note the
 | |
| .I reusing
 | |
| clause.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat loc loc loc cii $1>=0 && $2==2 && $3==4	leaving loc $1 loc 0
 | |
| .DE
 | |
| Shows a trivial example of EM-replacement.
 | |
| This is a rule that could be done by the
 | |
| peephole optimizer,
 | |
| if word order in longs was defined in EM.
 | |
| On a `big-endian' machine the two replacement
 | |
| instructions would be the other way around.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat and $1==2
 | |
| with const2 REG
 | |
|   gen bic {const2,~%1.num},%2		yields %2
 | |
| with REG const2
 | |
|   gen bic {const2,~%2.num},%1		yields %1
 | |
| with REG REG
 | |
|   gen com %1
 | |
|       bic %1,%2				yields %2
 | |
| .DE
 | |
| Shows the way you have to twist the table,
 | |
| if an
 | |
| .I and -instruction
 | |
| is not available on your machine.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat set $1==2
 | |
| with REG
 | |
| uses REG={const2,1}
 | |
| gen ash %1,%a				yields %a
 | |
| .DE
 | |
| Shows the building of a word-size set.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat lae aar $2==2 && rom($1,3)==1 && rom($1,1)==0 
 | |
| 					leaving adi 2
 | |
| 
 | |
| pat lae aar $2==2 && rom($1,3)==1 && rom($1,1)!=0 
 | |
| 					leaving adi 2 adp 0-rom($1,1)
 | |
| .DE
 | |
| Two rules showing the use of the rom pseudo function,
 | |
| and some array optimalisation.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat bra
 | |
| with STACK
 | |
| gen jbr {label, $1}
 | |
| .DE
 | |
| A simple jump.
 | |
| The stack pattern guarantees that everything will be stacked
 | |
| before the jump is taken.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat cal
 | |
| with STACK
 | |
| gen jsr pc,{label, $1}
 | |
| .DE
 | |
| A simple call.
 | |
| Same comments as previous rule.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat lfr $1==2				yields r0
 | |
| pat lfr $1==4				yields r1 r0
 | |
| .DE
 | |
| Shows the return area conventions of the PDP-11 table.
 | |
| At this point a reminder:
 | |
| the
 | |
| .B asp
 | |
| instruction, and some other instructions must leave
 | |
| the function return area intact.
 | |
| See the defining document for EM for exact information.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat ret $1==0
 | |
| with STACK
 | |
| gen mov lb,sp
 | |
|     rts pc
 | |
| .DE
 | |
| This shows a rule for 
 | |
| .B ret
 | |
| in a table not using register variables.
 | |
| In a table with register variables the 
 | |
| .I gen
 | |
| part would just contain
 | |
| .I return .
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat blm
 | |
| with REG REG
 | |
| uses REG={const2,$1/2}
 | |
| gen 1:
 | |
|     mov {autoinc,%2},{autoinc,%1}
 | |
|     sob %a,{label,1b}
 | |
| .DE
 | |
| This rule for 
 | |
| .B blm
 | |
| already uses three registers of the same type.
 | |
| .I Cgg
 | |
| contains code to check all your rules
 | |
| to see if they can be applied from an empty fakestack.
 | |
| It uses the marriage thesis from Hall,
 | |
| a thesis from combinatorial mathematics,
 | |
| to accomplish this.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| pat exg $1==2
 | |
| with src2 src2				yields %1 %2
 | |
| .DE
 | |
| This rule shows the exchanging of two elements on the fake stack.
 | |
| .NH 2
 | |
| Code rules using procedures
 | |
| .PP
 | |
| To start this chapter it must be admitted at once that the
 | |
| word procedure is chosen here mainly for it's advertising
 | |
| value.
 | |
| It more resembles a glorified goto but this of course can
 | |
| not be admitted in the glossy brochures.
 | |
| This document will continue to use the word
 | |
| procedure.
 | |
| .PP
 | |
| The need for procedures was felt after the first version of
 | |
| the code generator system was made,
 | |
| mainly because of conditional instructions.
 | |
| Often the code sequences for
 | |
| .B tlt ,
 | |
| .B tle ,
 | |
| .B teq ,
 | |
| .B tne ,
 | |
| .B tge
 | |
| and
 | |
| .B tgt
 | |
| were identical apart from one opcode in the code rule.
 | |
| The code sequence had to be written out six times however.
 | |
| Not only did this increase the table size and bore the
 | |
| table writer, it also led to errors when changing the table
 | |
| since it happened now and then that five out of six
 | |
| rules were changed.
 | |
| .PP
 | |
| In general the procedures in this table format are used to
 | |
| keep one copy instead of six of the code rules for all
 | |
| sorts of conditionals and one out of two for things like
 | |
| increment/decrement.
 | |
| .PP
 | |
| And now the syntax, first the procedure definition,
 | |
| which must indeed be defined before the call because
 | |
| .I cgg
 | |
| is one-pass.
 | |
| The procedure heading replaces the EM-pattern in a code rule
 | |
| and looks like this:
 | |
| .DS
 | |
| proc <identifier> <optional example>
 | |
| .DE
 | |
| The identifier is used in later calls and the example must
 | |
| be used if expressions like $1 are used in the code rule.
 | |
| .DS
 | |
| <optional example> : example <list of EM-instructions>
 | |
| .DE
 | |
| so an example looks just like an EM-pattern, but without
 | |
| the optional boolean expression.
 | |
| The example is needed to know the types of $1 expressions.
 | |
| The current version of
 | |
| .I cgg
 | |
| does not check correctness of the example, so be careful.
 | |
| .PP
 | |
| A procedure is called with one or two string-parameters,
 | |
| that are assembler opcodes.
 | |
| They can be accessed by appending the strings `[1]' or `[2]'
 | |
| to a table opcode.
 | |
| The string `*' can be used as an equivalent for `[1]'.
 | |
| Just in case this is not clear, here is an example for
 | |
| a procedure to increment/decrement a register.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| incop REG:rw:cc .	/* in the INSTRUCTIONS part of course */
 | |
| 
 | |
| proc incdec
 | |
| with REG
 | |
| gen incop* %1				yields %1
 | |
| .DE
 | |
| The procedure is called with parameter "inc" or "dec".
 | |
| .PP
 | |
| The procedure call is given instead of the code-part of the
 | |
| code rule and looks like this
 | |
| .DS
 | |
| call <identifier> '(' string [ ',' string ] ')'
 | |
| .DE
 | |
| which leads to the following large example:
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| proc bxx example beq
 | |
| with src2 src2 STACK
 | |
| gen cmp %2,%1
 | |
|     jxx* {label, $1}
 | |
| 
 | |
| pat blt				call bxx("jlt")
 | |
| pat ble				call bxx("jle")
 | |
| pat beq				call bxx("jeq")
 | |
| pat bne				call bxx("jne")
 | |
| pat bgt				call bxx("jgt")
 | |
| pat bge				call bxx("jge")
 | |
| .DE
 | |
| .NH 2
 | |
| Move definitions
 | |
| .PP
 | |
| We now jump back to near the beginning of the table
 | |
| where the move definitions are found.
 | |
| The move definitions directly follow the instruction
 | |
| definitions.
 | |
| .PP
 | |
| In certain cases a move is called for,
 | |
| either explicitly when a
 | |
| .I move
 | |
| instruction is used in a code rule,
 | |
| or implicitly in a register initialization.
 | |
| The different code rules possible to move data from one
 | |
| spot to another are described here.
 | |
| Example for the PDP-11:
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| MOVES
 | |
| 
 | |
| from const2 %num==0 to dst2
 | |
| gen clr %2
 | |
| 
 | |
| from src2 to dst2
 | |
| gen mov %1,%2
 | |
| 
 | |
| from FLTREG to longf4-FLTREG
 | |
| gen movfo %1,%2
 | |
| 
 | |
| from longf4-FLTREG to FLTREG
 | |
| gen movof %1,%2
 | |
| .DE
 | |
| The example shows that the syntax is just
 | |
| .DS
 | |
| from <source> to <destination> gen <list of instructions>
 | |
| .DE
 | |
| Source and destination are a token set, optionally followed by
 | |
| a boolean expression.
 | |
| The code generator will take the first move that matches,
 | |
| whenever a move is necessary.
 | |
| .I Cgg
 | |
| checks whether all moves called for in the table are present.
 | |
| .NH 2
 | |
| Test definitions
 | |
| .PP
 | |
| This part describes the instructions necessary to set the condition codes
 | |
| to a certain token.
 | |
| These rules are needed when the
 | |
| .I test
 | |
| instruction is used in code rules.
 | |
| Example for the PDP-11:
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| TESTS
 | |
| 
 | |
| to test src2
 | |
| gen tst %1
 | |
| .DE
 | |
| So syntax is just
 | |
| .DS
 | |
| to test <source> gen <instruction list>
 | |
| .DE
 | |
| Source is the same thing as in the move definition.
 | |
| .I Cgg
 | |
| checks whether all tests called for in the table are present.
 | |
| .NH 2
 | |
| Some explanation about the rules behind coercions
 | |
| .PP
 | |
| A central part in code generation is taken by the
 | |
| .I coercions .
 | |
| It is the responsibility of the table writer to provide
 | |
| all necessary coercions so that code generation can continue.
 | |
| The minimal set of coercions are
 | |
| the coercions to unstack every token expression,
 | |
| in combination with the rules to stack every token.
 | |
| It should not be possible to smuggle a table through
 | |
| .I cgg
 | |
| without these basic set available.
 | |
| .PP
 | |
| If these are present the code generator can always make the necessary
 | |
| transformations by stacking and unstacking.
 | |
| Of course for code quality it is usually best to provide extra coercions
 | |
| to prevent this stacking to take place.
 | |
| .I Cg
 | |
| discriminates three types of coercions:
 | |
| .IP 1)
 | |
| Unstacking coercions.
 | |
| This category can use the
 | |
| .I uses
 | |
| clause in its code.
 | |
| .IP 2)
 | |
| Splitting coercions, these are the coercions that split
 | |
| larger tokens into smaller ones.
 | |
| .IP 3)
 | |
| Transforming coercions, these are the coercions that transform
 | |
| a token into another of the same size.
 | |
| This category can use the
 | |
| .I uses
 | |
| clause in its code.
 | |
| .PP
 | |
| When a stack configuration does not match the stack pattern
 | |
| .I coercions
 | |
| are searched for in the following order:
 | |
| .IP 1)
 | |
| First tokens are split if necessary to get their sizes right.
 | |
| .IP 2)
 | |
| Then transforming coercions are found that will make the pattern match.
 | |
| .IP 3)
 | |
| Finally if the stack pattern is longer than the fake stack contents
 | |
| unstacking coercions will be used to fill up the pattern.
 | |
| .PP
 | |
| At any point, when coercions are missing so code generation could not
 | |
| continue, the offending tokens are stacked.
 | |
| .NH 2
 | |
| Stack definitions
 | |
| .PP
 | |
| The next part of the table defines the stacking rules for the machine.
 | |
| Each token that may reside on the fake stack must have a rule attached
 | |
| to put it on the real stack.
 | |
| Example for the PDP-11:
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| STACKINGRULES
 | |
| 
 | |
| from const2 %num==0 to STACK
 | |
| gen clr {autodec,sp}
 | |
| 
 | |
| from src2 to STACK
 | |
| gen mov %1,{autodec,sp}
 | |
| 
 | |
| from regconst2 to STACK
 | |
| gen mov %1.reg,{autodec,sp}
 | |
|     add {addr_external, %1.off},{regdef2,sp}
 | |
| 
 | |
| from DBLREG to STACK
 | |
| gen movf %1,{autodec,sp}
 | |
| 
 | |
| from FLTREG  to STACK
 | |
| gen movfo %1,{autodec,sp}
 | |
| 
 | |
| from regind8 to STACK
 | |
| uses REG
 | |
| gen move %1.reg,%a
 | |
|     add {addr_external, 8+%1.off},%a
 | |
|     mov {autodec, %a},{autodec,sp}
 | |
|     mov {autodec, %a},{autodec,sp}
 | |
|     mov {autodec, %a},{autodec,sp}
 | |
|     mov {autodec, %a},{autodec,sp}
 | |
| .DE
 | |
| .PP
 | |
| These examples should be self-explanatory, except maybe for the last one.
 | |
| It is possible inside a stacking-rule to use a register.
 | |
| Since however the stacking might also take place at a moment
 | |
| when no registers are free, it is mandatory that for each token
 | |
| there is one stackingrule that does not use a register.
 | |
| The code generator uses the first rule possible.
 | |
| .NH 2
 | |
| Coercions
 | |
| .PP
 | |
| The next part of the table defines the coercions that are possible
 | |
| on the defined tokens.
 | |
| Example for the PDP-11:
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| COERCIONS
 | |
| 
 | |
| from STACK
 | |
| uses REG
 | |
| gen mov {autoinc,sp},%a			yields %a
 | |
| 
 | |
| from STACK
 | |
| uses DBLREG
 | |
| gen movf {autoinc,sp},%a		yields %a
 | |
| 
 | |
| from STACK
 | |
| uses REGPAIR
 | |
| gen mov {autoinc,sp},%a.1
 | |
|     mov {autoinc,sp},%a.2		yields %a
 | |
| .DE
 | |
| These three coercions just deliver a certain type
 | |
| of register by popping it from the real stack.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| from LOCAL				yields {regind2,lb,%1.ind}
 | |
| 
 | |
| from DLOCAL				yields {regind4,lb,%1.ind}
 | |
| 
 | |
| from REG				yields {regconst2, %1, 0}
 | |
| .DE
 | |
| These three are zero-cost rewriting rules.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| from regconst2 %1.off==1
 | |
| uses reusing %1,REG=%1.reg
 | |
| gen inc %a				yields %a
 | |
| 
 | |
| from regconst2
 | |
| uses reusing %1,REG=%1.reg
 | |
| gen add {addr_external, %1.off},%a	yields %a
 | |
| 
 | |
| from addr_local
 | |
| uses REG
 | |
| gen mov lb,%a
 | |
|     add {const2, %1.ind},%a		yields %a
 | |
| .DE
 | |
| The last three are three different cases of the coercion
 | |
| register+constant to register.
 | |
| Only in the last case is it always necessary to allocate
 | |
| an extra register,
 | |
| since arithmetic on the localbase is unthinkable.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| from xsrc2
 | |
| uses reusing %1, REG=%1			yields %a
 | |
| 
 | |
| from longf4
 | |
| uses FLTREG=%1				yields %a
 | |
| 
 | |
| from double8
 | |
| uses DBLREG=%1				yields %a
 | |
| 
 | |
| from src1
 | |
| uses REG={const2,0}
 | |
| gen bisb %1,%a				yields %a
 | |
| .DE
 | |
| These examples show the coercion of different
 | |
| tokens to a register of the needed type.
 | |
| The last one shows the trouble needed on a PDP-11 to
 | |
| ensure bytes are not sign-extended.
 | |
| In EM it is defined that the result of a \fBloi\fP\ 1
 | |
| instruction is an integer in the range 0..255.
 | |
| .DS
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| from REGPAIR				yields %1.2 %1.1
 | |
| 
 | |
| from regind4				yields {regind2,%1.reg,2+%1.off}
 | |
| 					       {regind2,%1.reg,%1.off}
 | |
| 
 | |
| from relative4				yields {relative2,2+%1.off}
 | |
| 					       {relative2,%1.off}
 | |
| .DE
 | |
| The last examples are splitting rules.
 | |
| .PP
 | |
| The examples show that
 | |
| all coercions change one token on the fake stack into one or more others,
 | |
| possibly generating code.
 | |
| The STACK token is supposed to be on the fake stack when it is
 | |
| really empty, and can only be changed into one other token.
 | |
| .NH 1
 | |
| The files mach.h and mach.c
 | |
| .PP
 | |
| The table writer must also supply two files containing
 | |
| machine dependent declarations and C code.
 | |
| These files are mach.h and mach.c.
 | |
| .NH 2
 | |
| Types in the code generator
 | |
| .PP
 | |
| Three different types of integer coexist in the code generator
 | |
| and their range depends on the machine at hand.
 | |
| They are defined depending on the Target EM_WSIZE, or TEM_WSIZE,
 | |
| and TEM_PSIZE.
 | |
| The type 'int' is used for things like counters that won't require
 | |
| more than 16 bits precision.
 | |
| The type 'word' is used among others to assemble datawords and
 | |
| is of type 'long' if TEM_WSIZE>2.
 | |
| The type 'full' is used for addresses and is of type 'long' if
 | |
| TEM_WSIZE>2 or TEM_PSIZE>2.
 | |
| .PP
 | |
| In macro and function definitions in later paragraphs implicit typing
 | |
| will be used for parameters, that is parameters starting with an 's'
 | |
| will be of type string, and the letters 'i','w','f' will stand for
 | |
| int, word and full respectively.
 | |
| .NH 2
 | |
| Global variables to work with
 | |
| .PP
 | |
| Some global variables are present in the code generator
 | |
| that can be manipulated by the routines in mach.h and mach.c.
 | |
| .LP
 | |
| The declarations are:
 | |
| .DS L
 | |
| .ta 20
 | |
| FILE *codefile;	/* code is emitted on this stream */
 | |
| word part_word;	/* words to be output are put together here */
 | |
| int part_size;	/* number of bytes already put in part_word */
 | |
| char str[];	/* Last string read in */
 | |
| long argval;	/* Last int read and kept */
 | |
| .DE
 | |
| .NH 2
 | |
| Macros in mach.h
 | |
| .PP
 | |
| In the file mach.h a collection of macros is defined that have
 | |
| to do with formatting of assembly code for the machine at hand.
 | |
| Some of these macros can of course be left undefined in which case the
 | |
| macro calls are left in the source and will be treated as 
 | |
| function calls.
 | |
| These functions can then be defined in \fImach.c\fR.
 | |
| .PP
 | |
| The macros to be defined are:
 | |
| .IP ex_ap(s) 16
 | |
| Must print the magic incantations that will mark the symbol \fI\fR
 | |
| to be exported to other modules.
 | |
| This is the translation of the EM \fBexa\fP and \fBexp\fP instructions.
 | |
| .IP in_ap(s)
 | |
| Same to import the symbol.
 | |
| Translation of \fBina\fP and \fBinp\fP.
 | |
| .IP newplb(s)
 | |
| Must print the definition of procedure label \fIs\fR.
 | |
| If left undefined the newilb() macro is used instead.
 | |
| .IP newilb(s)
 | |
| Must print the definition of instruction label \fIs\fR.
 | |
| .IP newdlb(s)
 | |
| Must print the definition of data label \fIs\fR.
 | |
| .IP dlbdlb(s1,s2)
 | |
| Must define data label
 | |
| .I s1
 | |
| to be equal to
 | |
| .I s2 .
 | |
| .IP newlbss(s,f)
 | |
| Must declare a piece of memory initialized to BSS_INIT(see below)
 | |
| of length 
 | |
| .I f
 | |
| and with label
 | |
| .I s .
 | |
| .IP cst_fmt
 | |
| Format to be used when converting constant arguments of
 | |
| EM instructions to string.
 | |
| Argument to be formatted will be 'full'.
 | |
| .IP off_fmt
 | |
| Format to be used for integer part of label+constant,
 | |
| argument will be 'full'.
 | |
| .IP fmt_ilb(ip,il,s)
 | |
| Must use the numbers 
 | |
| .I ip
 | |
| and 
 | |
| .I il
 | |
| that are a procedure number
 | |
| and a label number respectively and copy a string to
 | |
| .I s
 | |
| that must be unique for that combination.
 | |
| This procedure is optional, if it is not given ilb_fmt
 | |
| must be defined as below.
 | |
| .IP ilb_fmt
 | |
| Format to be used for creation of unique instruction labels.
 | |
| Arguments will be a unique procedure number (int) and the label
 | |
| number (int).
 | |
| .IP dlb_fmt
 | |
| Format to be used for printing numeric data labels.
 | |
| Argument will be 'int'.
 | |
| .IP hol_fmt
 | |
| Format to be used for generation of labels for
 | |
| space generated by a
 | |
| .B hol
 | |
| pseudo.
 | |
| Argument will be 'int'.
 | |
| .IP hol_off
 | |
| Format to be used for printing of the address of an element in
 | |
| .B hol
 | |
| space.
 | |
| Arguments will be the offset in the
 | |
| .B hol
 | |
| block (word) and the number of the
 | |
| .B hol
 | |
| (int).
 | |
| .IP con_cst(w)
 | |
| Must generate output that will assemble into one machine word.
 | |
| .IP con_ilb(s)
 | |
| Must generate output that will put the address of the instruction label
 | |
| into the datastream.
 | |
| .IP con_dlb(s)
 | |
| Must generate output that will put the address of the data label
 | |
| into the datastream.
 | |
| .IP fmt_id(sf,st)
 | |
| Must take the string in
 | |
| .I sf
 | |
| that is a nonnumeric global label, and transform it into a copy made to
 | |
| .I st
 | |
| that will not collide with reserved assembler words and system labels.
 | |
| This procedure is optional, if it is not given the id_first macro is used
 | |
| as defined below.
 | |
| .IP id_first
 | |
| Must be a character.
 | |
| This is prepended to all nonnumeric global labels if their length
 | |
| is shorter than the maximum allowed(currently 8) or if they already
 | |
| start with that character.
 | |
| This is to avoid conflicts of user labels with system labels.
 | |
| .IP BSS_INIT
 | |
| Must be a constant.
 | |
| This is the value filled in all the words not initialized explicitly.
 | |
| This is loader and system dependent.
 | |
| If omitted no initialization is assumed.
 | |
| .NH 3
 | |
| Example mach.h for the PDP-11
 | |
| .DS L
 | |
| .ta 8 16 24 32 40 48 56
 | |
| #define ex_ap(y)	fprintf(codefile,"\et.globl %s\en",y)
 | |
| #define in_ap(y)	/* nothing */
 | |
| 
 | |
| #define newplb(x)	fprintf(codefile,"%s:\en",x)
 | |
| #define newilb(x)	fprintf(codefile,"%s:\en",x)
 | |
| #define newdlb(x)	fprintf(codefile,"%s:\en",x)
 | |
| #define	dlbdlb(x,y)	fprintf(codefile,"%s=%s\en",x,y)
 | |
| #define newlbss(l,x)	fprintf(codefile,"%s:.=.+%d.\en",l,x);
 | |
| 
 | |
| #define cst_fmt		"$%d."
 | |
| #define off_fmt		"%d."
 | |
| #define ilb_fmt		"I%02x%x"
 | |
| #define dlb_fmt		"_%d"
 | |
| #define	hol_fmt		"hol%d"
 | |
| 
 | |
| #define hol_off		"%d.+hol%d"
 | |
| 
 | |
| #define con_cst(x)	fprintf(codefile,"%d.\en",x)
 | |
| #define con_ilb(x)	fprintf(codefile,"%s\en",x)
 | |
| #define con_dlb(x)	fprintf(codefile,"%s\en",x)
 | |
| 
 | |
| #define id_first	'_'
 | |
| #define BSS_INIT	0
 | |
| .DE
 | |
| .NH 2
 | |
| Functions in mach.c
 | |
| .PP
 | |
| In mach.c some functions must be supplied,
 | |
| mostly manipulating data resulting from pseudoinstructions.
 | |
| The specifications are given here,
 | |
| implicit typing of parameters as above.
 | |
| .IP -
 | |
| con_part(isz,word)
 | |
| .br
 | |
| This function must manipulate the globals 
 | |
| part_word and part_size to append the isz bytes
 | |
| contained in word to the output stream.
 | |
| If part_word is full, i.e. part_size==TEM_WSIZE
 | |
| the function part_flush() may be called to empty the buffer.
 | |
| This is the function that must go through the trouble of
 | |
| doing byte order in words correct.
 | |
| .IP -
 | |
| con_mult(w_size)
 | |
| .br
 | |
| This function must take the string str[] and create an integer
 | |
| from the string of size w_size and generate code to assemble global
 | |
| data for that integer.
 | |
| Only the sizes for which arithmetic is implemented need be
 | |
| handled,
 | |
| so if you didn't implement 200-byte integer division
 | |
| you don't have to implement 200-byte integer global data.
 | |
| Here one must take care of word order in long integers.
 | |
| .IP -
 | |
| con_float()
 | |
| .br
 | |
| This function must generate code to assemble a floating
 | |
| point number of which the size is contained in argval
 | |
| and the ASCII representation in str[].
 | |
| .IP -
 | |
| prolog(f_nlocals)
 | |
| .br
 | |
| This function is called at the start of every procedure.
 | |
| Function prolog code must be generated,
 | |
| and room made for local variables for a total of f_nlocals bytes.
 | |
| .IP -
 | |
| mes(w_mesno)
 | |
| .br
 | |
| This function is called when a
 | |
| .B mes
 | |
| pseudo is seen that is not handled by the machine independent part.
 | |
| Example below shows all you probably have to know about that.
 | |
| .IP -
 | |
| segname[]
 | |
| .br
 | |
| This is not a function,
 | |
| but an array of four strings.
 | |
| These strings are put out whenever the code generator
 | |
| switches segments.
 | |
| Segments are SEGTXT, SEGCON, SEGROM and SEGBSS in that order.
 | |
| .PP
 | |
| If register variables are used in a table, the program
 | |
| .I cgg
 | |
| will define the word REGVARS during compilation of the sources.
 | |
| So the following functions described here should be bracketed
 | |
| by #ifdef REGVARS and #endif.
 | |
| .IP -
 | |
| regscore(off,size,typ,freq,totyp) long off;
 | |
| .br
 | |
| This function should assign a score to a register variable,
 | |
| the score should preferably be the estimated number of bytes
 | |
| gained when it is put in a register.
 | |
| Off and size are the offset and size of the variable,
 | |
| typ is the type, that is reg_any, reg_pointer, reg_loop or reg_float.
 | |
| Freq is the count of static occurrences, and totyp
 | |
| is the type of the register it is planned to go into.
 | |
| .br
 | |
| Keep in mind that the gain should be net, that is the cost for
 | |
| register save/restore sequences and the cost of initialisation
 | |
| in the case of parameters should already be included.
 | |
| .IP -
 | |
| i_regsave()
 | |
| .br
 | |
| This function is called at the start of a procedure, just before
 | |
| register saves are done.
 | |
| It can be used to initialise some variables if needed.
 | |
| .IP -
 | |
| f_regsave()
 | |
| .br
 | |
| This function is called at end of the register save sequence.
 | |
| It can be used to do the real saving if multiple register move
 | |
| instructions are available.
 | |
| .IP -
 | |
| regsave(regstr,off,size) char *regstr; long off;
 | |
| .br
 | |
| Should either do the real saving or set up a table to have
 | |
| it done by f_regsave.
 | |
| Note that initialisation of parameters should also be done,
 | |
| or planned here.
 | |
| .IP -
 | |
| regreturn()
 | |
| .br
 | |
| Should restore saved registers and return.
 | |
| The function result is already in the function return area by now.
 | |
| .NH 3
 | |
| Example mach.c for the PDP-11
 | |
| .PP
 | |
| As an example of the sort of code expected,
 | |
| the mach.c for the PDP-11 is presented here.
 | |
| .DS L
 | |
| .ta 8 16 24 32 40 48 56 64
 | |
| /*
 | |
|  * machine dependent back end routines for the PDP-11
 | |
|  */
 | |
| 
 | |
| con_part(sz,w) register sz; word w; {
 | |
| 
 | |
| 	while (part_size % sz)
 | |
| 		part_size++;
 | |
| 	if (part_size == 2)
 | |
| 		part_flush();
 | |
| 	if (sz == 1) {
 | |
| 		w &= 0xFF;
 | |
| 		if (part_size)
 | |
| 			w <<= 8;
 | |
| 		part_word |= w;
 | |
| 	} else {
 | |
| 		assert(sz == 2);
 | |
| 		part_word = w;
 | |
| 	}
 | |
| 	part_size += sz;
 | |
| }
 | |
| 
 | |
| con_mult(sz) word sz; {
 | |
| 	long l;
 | |
| 
 | |
| 	if (sz != 4)
 | |
| 		fatal("bad icon/ucon size");
 | |
| 	l = atol(str);
 | |
| 	fprintf(codefile,"\et%o;%o\en",(int)(l>>16),(int)l);
 | |
| }
 | |
| 
 | |
| con_float() {
 | |
| 	double f;
 | |
| 	register short *p,i;
 | |
| 
 | |
| 	/*
 | |
| 	 * This code is correct only when the code generator is
 | |
| 	 * run on a PDP-11 or VAX-11 since it assumes native
 | |
| 	 * floating point format is PDP-11 format.
 | |
| 	 */
 | |
| 
 | |
| 	if (argval != 4 && argval != 8)
 | |
| 		fatal("bad fcon size");
 | |
| 	f = atof(str);
 | |
| 	p = (short *) &f;
 | |
| 	i = *p++;
 | |
| 	if (argval == 8) {
 | |
| 		fprintf(codefile,"\et%o;%o;",i,*p++);
 | |
| 		i = *p++;
 | |
| 	}
 | |
| 	fprintf(codefile,"\et%o;%o\en",i,*p++);
 | |
| }
 | |
| 
 | |
| #ifdef REGVARS
 | |
| 
 | |
| char Rstring[10];
 | |
| full lbytes;
 | |
| struct regadm {
 | |
| 	char *ra_str;
 | |
| 	long  ra_off;
 | |
| } regadm[2];
 | |
| int n_regvars;
 | |
| 
 | |
| regscore(off,size,typ,score,totyp) long off; {
 | |
| 
 | |
| 	/*
 | |
| 	 * This function is full of magic constants.
 | |
| 	 * They are a result of experimentation.
 | |
| 	 */
 | |
| 
 | |
| 	if (size != 2)
 | |
| 		return(-1);
 | |
| 	score -= 1;	/* allow for save/restore */
 | |
| 	if (off>=0)
 | |
| 		score -= 2;
 | |
| 	if (typ==reg_pointer)
 | |
| 		score *= 17;
 | |
| 	else if (typ==reg_loop)
 | |
| 		score = 10*score+50;	/* Guestimate */
 | |
| 	else
 | |
| 		score *= 10;
 | |
| 	return(score);	/* 10 * estimated # of words of profit */
 | |
| }
 | |
| 
 | |
| i_regsave() {
 | |
| 
 | |
| 	Rstring[0] = 0;
 | |
| 	n_regvars=0;
 | |
| }
 | |
| 
 | |
| f_regsave() {
 | |
| 	register i;
 | |
| 
 | |
| 	if (n_regvars==0 || lbytes==0) {
 | |
| 		fprintf(codefile,"mov r5,-(sp)\enmov sp,r5\en");
 | |
| 		if (lbytes == 2)
 | |
| 			fprintf(codefile,"tst -(sp)\en");
 | |
| 		else if (lbytes!=0)
 | |
| 			fprintf(codefile,"sub $0%o,sp\en",lbytes);
 | |
| 		for (i=0;i<n_regvars;i++)
 | |
| 			fprintf(codefile,"mov %s,-(sp)\en",regadm[i].ra_str);
 | |
| 	} else {
 | |
| 		if (lbytes>6) {
 | |
| 			fprintf(codefile,"mov $0%o,r0\en",lbytes);
 | |
| 			fprintf(codefile,"jsr r5,PR%s\en",Rstring);
 | |
| 		} else {
 | |
| 			fprintf(codefile,"jsr r5,PR%d%s\en",lbytes,Rstring);
 | |
| 		}
 | |
| 	}
 | |
| 	for (i=0;i<n_regvars;i++)
 | |
| 		if (regadm[i].ra_off>=0)
 | |
| 			fprintf(codefile,"mov 0%lo(r5),%s\en",regadm[i].ra_off,
 | |
| 						regadm[i].ra_str);
 | |
| }
 | |
| 
 | |
| regsave(regstr,off,size) char *regstr; long off; {
 | |
| 
 | |
| 	fprintf(codefile,"/ Local %ld into %s\en",off,regstr);
 | |
| 	strcat(Rstring,regstr);
 | |
| 	regadm[n_regvars].ra_str = regstr;
 | |
| 	regadm[n_regvars].ra_off = off;
 | |
| 	n_regvars++;
 | |
| }
 | |
| 
 | |
| regreturn() {
 | |
| 
 | |
| 	fprintf(codefile,"jmp RT%s\en",Rstring);
 | |
| }
 | |
| 
 | |
| #endif
 | |
| 
 | |
| prolog(nlocals) full nlocals; {
 | |
| 
 | |
| #ifndef REGVARS
 | |
| 	fprintf(codefile,"mov r5,-(sp)\enmov sp,r5\en");
 | |
| 	if (nlocals == 0)
 | |
| 		return;
 | |
| 	if (nlocals == 2)
 | |
| 		fprintf(codefile,"tst -(sp)\en");
 | |
| 	else
 | |
| 		fprintf(codefile,"sub $0%o,sp\en",nlocals);
 | |
| #else
 | |
| 	lbytes = nlocals;
 | |
| #endif
 | |
| }
 | |
| 
 | |
| mes(type) word type; {
 | |
| 	int argt ;
 | |
| 
 | |
| 	switch ( (int)type ) {
 | |
| 	case ms_ext :
 | |
| 		for (;;) {
 | |
| 			switch ( argt=getarg(
 | |
| 			    ptyp(sp_cend)|ptyp(sp_pnam)|sym_ptyp) ) {
 | |
| 			case sp_cend :
 | |
| 				return ;
 | |
| 			default:
 | |
| 				strarg(argt) ;
 | |
| 				fprintf(codefile,".globl %s\en",argstr) ;
 | |
| 				break ;
 | |
| 			}
 | |
| 		}
 | |
| 	default :
 | |
| 		while ( getarg(any_ptyp) != sp_cend ) ;
 | |
| 		break ;
 | |
| 	}
 | |
| }
 | |
| 
 | |
| char    *segname[] = {
 | |
| 	".text",        /* SEGTXT */
 | |
| 	".data",        /* SEGCON */
 | |
| 	".data",        /* SEGROM */
 | |
| 	".bss"          /* SEGBSS */
 | |
| };
 | |
| .DE
 | |
| .NH 1
 | |
| Internal workings of the code generator.
 | |
| .NH 2
 | |
| Description of tables.c and tables.h contents
 | |
| .PP
 | |
| In this section the intermediate files will be described 
 | |
| that are produced by
 | |
| .I cgg
 | |
| and compiled with machine independent code to produce a code generator.
 | |
| .NH 3
 | |
| Tables.c
 | |
| .PP
 | |
| Tables.c contains a large number of initialized array's of all sorts.
 | |
| Description of each follows:
 | |
| .br
 | |
| .in 1i
 | |
| .ti -0.5i
 | |
| byte coderules[]
 | |
| .br
 | |
| Pseudo code interpreted by the code generator.
 | |
| Always starts with some opcode followed by operands depending
 | |
| on the opcode.
 | |
| Some of the opcodes have an argument encoded in the upper three
 | |
| bits of the opcode byte.
 | |
| Integers in this table are between 0 and 32767 and have a one byte
 | |
| encoding if between 0 and 127.
 | |
| .ti -0.5i
 | |
| char wrd_fmt[]
 | |
| .br
 | |
| The format used for output of words.
 | |
| .ti -0.5i
 | |
| char stregclass[]
 | |
| .br
 | |
| Number of computed static register class per register.
 | |
| Two registers are in the same class if they have the same properties
 | |
| and don't share a common subregister.
 | |
| .ti -0.5i
 | |
| struct reginfo machregs[]
 | |
| .br
 | |
| Info per register.
 | |
| Initialized with representation string, size,
 | |
| members of the register and set of registers affected when this
 | |
| one is changed.
 | |
| Also contains room for run time information,
 | |
| like contents and reference count.
 | |
| .ti -0.5i
 | |
| tkdef_t tokens[]
 | |
| .br
 | |
| Information per tokentype.
 | |
| Initialized with size, cost, type of operands and formatstring.
 | |
| .ti -0.5i
 | |
| node_t enodes[]
 | |
| .br
 | |
| List of triples representing expressions for the code generator.
 | |
| .ti -0.5i
 | |
| string codestrings[]
 | |
| .br
 | |
| List of strings.
 | |
| All strings are put in a list and checked for duplication,
 | |
| so only one copy per string will reside here.
 | |
| .ti -0.5i
 | |
| set_t machsets[]
 | |
| .br
 | |
| List of token expression sets.
 | |
| Bit 0 of the set is used for the SCRATCH property of registers,
 | |
| bit 1 upto NREG are for the corresponding registers
 | |
| and bit NREG+1 upto the end are for corresponding tokens.
 | |
| .ti -0.5i
 | |
| inst_t tokeninstances[]
 | |
| .br
 | |
| List of descriptions for building tokens.
 | |
| Contains type of rule for building one,
 | |
| plus operands depending on the type.
 | |
| .ti -0.5i
 | |
| move_t moves[]
 | |
| .br
 | |
| List of move rules.
 | |
| Contains token expressions for source and destination
 | |
| plus index for code rule.
 | |
| .ti -0.5i
 | |
| test_t tests[]
 | |
| .br
 | |
| List of test rules.
 | |
| Contains token expressions for source
 | |
| plus index for code rule.
 | |
| .ti -0.5i
 | |
| byte pattern[]
 | |
| .br
 | |
| EM patterns.
 | |
| This is structured internally as chains of patterns,
 | |
| each chain pointed at by pathash[].
 | |
| After each pattern the list of possible code rules is given.
 | |
| .ti -0.5i
 | |
| int pathash[256]
 | |
| .br
 | |
| Indices into pattern[] for all patterns with a certain low order
 | |
| byte of the hashing function.
 | |
| .ti -0.5i
 | |
| c1_t c1coercs[]
 | |
| .br
 | |
| List of rules to stack tokens.
 | |
| Contains token expressions,
 | |
| register needed,
 | |
| cost
 | |
| and code rule.
 | |
| .ti -0.5i
 | |
| c2_t c2coercs[]
 | |
| .br
 | |
| List of splitting coercions.
 | |
| Token expressions,
 | |
| split factor,
 | |
| replacements
 | |
| and code rule.
 | |
| .ti -0.5i
 | |
| c3_t c3coercs[]
 | |
| .br
 | |
| List of one to one coercions.
 | |
| Token expressions,
 | |
| register needed,
 | |
| replacement
 | |
| and code rule.
 | |
| .ti -0.5i
 | |
| struct reginfo **reglist[]
 | |
| .br
 | |
| List of lists of pointers to register information.
 | |
| For every property the list is here
 | |
| to find the registers corresponding to it.
 | |
| .in 0
 | |
| .NH 3
 | |
| tables.h
 | |
| .PP
 | |
| In tables.h various derived constants for the tables are
 | |
| given.
 | |
| They are then used to determine array sizes in the actual code generator,
 | |
| plus loop termination in some cases.
 | |
| .NH 2
 | |
| Other important data structures
 | |
| .PP
 | |
| During code generation some other data structures are used
 | |
| and here is a short description of some of the important ones.
 | |
| .PP
 | |
| Tokens are kept in the code generator as a struct consisting of
 | |
| one integer
 | |
| .I t_token
 | |
| which is -1 if the token is a register,
 | |
| and the number of the token otherwise,
 | |
| plus an array of
 | |
| .I TOKENSIZE
 | |
| unions
 | |
| .I t_att
 | |
| of which the first is the register number in case of a register.
 | |
| .PP
 | |
| The fakestack is an array of these tokens,
 | |
| there is a global variable
 | |
| .I stackheight .
 | |
| .PP
 | |
| The results of expressions are kept in a struct
 | |
| .I result
 | |
| with elements
 | |
| .I e_typ ,
 | |
| giving the type of the expression:
 | |
| .I EV_INT ,
 | |
| .I EV_REG
 | |
| or
 | |
| .I EV_ADDR ,
 | |
| and a union
 | |
| .I e_v
 | |
| which contains the real result.
 | |
| .NH 2
 | |
| A tour through the sources
 | |
| .NH 3
 | |
| codegen.c
 | |
| .PP
 | |
| The file codegen.c contains one large function consisting
 | |
| of one giant switch statement.
 | |
| It is the interpreter for the code generator pseudo code
 | |
| as contained in code rules[].
 | |
| This function can call itself recursively when doing look ahead.
 | |
| Arguments are:
 | |
| .IP codep 10
 | |
| Pointer into code rules, pseudo program counter.
 | |
| .IP ply
 | |
| Number of EM pattern look ahead allowed.
 | |
| .IP toplevel
 | |
| Boolean telling whether this is the toplevel codegen() or
 | |
| a deeper incarnation.
 | |
| .IP costlimit
 | |
| A cutoff value to limit searches.
 | |
| If the cost crosses costlimit the incarnation can terminate.
 | |
| .IP forced
 | |
| A register number if nonzero.
 | |
| This is used inside coercions to force the allocate() call to allocate
 | |
| a register determined by earlier look ahead.
 | |
| .PP
 | |
| The instructions inplemented in the switch:
 | |
| .NH 4
 | |
| DO_DLINE
 | |
| .PP
 | |
| Prints debugging information if the code generator runs in debug mode.
 | |
| This information is only generated if
 | |
| .I cgg
 | |
| was called with the -d flag.
 | |
| .NH 4
 | |
| DO_NEXTEM
 | |
| .PP
 | |
| Matches the next EM pattern and does look ahead if necessary to find the best
 | |
| code rule associated with this pattern.
 | |
| Heuristics are used to determine best code rule when possible.
 | |
| This is done by calling the distance() function.
 | |
| It can also handle the procedure mechanism.
 | |
| .NH 4
 | |
| DO_COERC
 | |
| .PP
 | |
| This sets the code generator in the state to do a from stack coercion.
 | |
| .NH 4
 | |
| DO_XMATCH
 | |
| .PP
 | |
| This is done when a match no longer has to be checked.
 | |
| Used when the nocoercions: trick is used in the table.
 | |
| .NH 4
 | |
| DO_MATCH
 | |
| .PP
 | |
| This is the big one inside this function.
 | |
| It has the task to transform the contents of the current
 | |
| fake stack to match the pattern given after it.
 | |
| .PP
 | |
| Since the code generator does not know combining coercions,
 | |
| i.e. there is no way to make a big token out of two smaller ones,
 | |
| the first thing done is to stack every token that is too small.
 | |
| After that all tokens too big are split if possible to the right size.
 | |
| .PP
 | |
| Next the coercions are sought that would transform tokens in place to
 | |
| the right one, plus the coercions that would pop tokens of the stack.
 | |
| Each of those might need a register, so a list of registers is generated
 | |
| and at the end of looking for coercions the function 
 | |
| .I tuples()
 | |
| is called to generate the list of all possible \fIn\fP-tuples,
 | |
| where 
 | |
| .I n
 | |
| equals the number of registers needed.
 | |
| .PP
 | |
| Look ahead is now performed if the number of tuples is greater than one.
 | |
| If no possibility is found within the costlimit,
 | |
| the fake stack is made smaller by pushing the bottom token,
 | |
| and this process is repeated until either a way is found or
 | |
| the fake stack is completely empty and there is still no way
 | |
| to make the match.
 | |
| .PP
 | |
| If there is a way the corresponding coercions are executed
 | |
| and the code is finished.
 | |
| .NH 4
 | |
| DO_REMOVE
 | |
| .PP
 | |
| Here the kills clause is executed, all tokens matched by the 
 | |
| token expression plus boolean expression are pushed.
 | |
| In the current implementation there is no attempt to move those
 | |
| tokens to registers, but that is a possible future extension.
 | |
| .NH 4
 | |
| DO_DEALLOCATE
 | |
| .PP
 | |
| This one temporarily decrements by one the reference count of all registers
 | |
| contained in the token given as argument.
 | |
| .NH 4
 | |
| DO_REALLOCATE
 | |
| .PP
 | |
| Here all temporary deallocates are made undone.
 | |
| .NH 4
 | |
| DO_ALLOCATE
 | |
| .PP
 | |
| This is the part that allocates a register and decides which one to use.
 | |
| If the
 | |
| .I forced
 | |
| argument was given its task is simple,
 | |
| otherwise some work must be done.
 | |
| First the list of possible registers is scanned,
 | |
| all free registers noted and it is noted whether any of those
 | |
| registers is already
 | |
| containing the initialization.
 | |
| If no registers are available some fakestack token is stacked and the
 | |
| process is repeated.
 | |
| .PP
 | |
| After that if an exact match was found, 
 | |
| the list of registers is reduced to one register matching exactly
 | |
| out of every register class.
 | |
| Now look ahead is performed if necessary and the register chosen.
 | |
| If an initialization was given the corresponding move is performed,
 | |
| otherwise the register is marked empty.
 | |
| .NH 4
 | |
| DO_INSTR
 | |
| .PP
 | |
| This prints an instruction and it's operands.
 | |
| Only done on toplevel.
 | |
| .NH 4
 | |
| DO_MOVE
 | |
| .PP
 | |
| Calls the move() function in the code generator to implement the move
 | |
| instruction in the table.
 | |
| .NH 4
 | |
| DO_TEST
 | |
| .PP
 | |
| Calls the test() function in the code generator to implement the test
 | |
| instruction in the table.
 | |
| .NH 4
 | |
| DO_ERASE
 | |
| .PP
 | |
| Marks the register that is its argument as empty.
 | |
| .NH 4
 | |
| DO_TOKREPLACE
 | |
| .PP
 | |
| This is the token replacement part.
 | |
| It is also called if there is no token replacement because it has
 | |
| some other functions as well.
 | |
| .PP
 | |
| First the tokens that will be pushed on the fake stack are computed
 | |
| and stored in a temporary array.
 | |
| Then the tokens that were matched in this rule are popped
 | |
| and their embedded registers have their reference count
 | |
| decremented.
 | |
| After that the replacement tokens are pushed.
 | |
| .PP
 | |
| Finally all registers allocated in this rule have their reference count
 | |
| decremented.
 | |
| If they were not pushed on the fake stack they will be available again
 | |
| in the next code rule.
 | |
| .NH 4
 | |
| DO_EMREPLACE
 | |
| .PP
 | |
| Places replacement EM instructions back into the instruction stream.
 | |
| .NH 4
 | |
| DO_COST
 | |
| .PP
 | |
| Accounts for cost as given in the code rule.
 | |
| .NH 4
 | |
| DO_RETURN
 | |
| .PP
 | |
| Returns from this level of codegen().
 | |
| Is used at the end of coercions,
 | |
| move rules etc..
 | |
| .NH 3
 | |
| compute.c
 | |
| .PP
 | |
| This module computes the various expressions as given
 | |
| in the enodes[] array.
 | |
| Nothing very special happens here,
 | |
| it is just a recursive function computing leaves
 | |
| of expressions and applying the operator.
 | |
| .NH 3
 | |
| equiv.c
 | |
| .PP
 | |
| In this module the tuples() function is implemented.
 | |
| It is given the number of registers needed and
 | |
| a list of register lists and it constructs a list of tuples
 | |
| where the \fIn\fP'th register comes from the \fIn\fP'th list.
 | |
| Before the list is constructed however 
 | |
| the dynamic register classes are computed.
 | |
| Two registers are in the same dynamic class if they are in the
 | |
| same static class and their contents is the same.
 | |
| .PP
 | |
| After that the permute() recursive function is called to
 | |
| generate the list of tuples.
 | |
| After construction a generated tuple is added to the list
 | |
| if it is not already pairwise in the same class
 | |
| or if the register relations are not the same,
 | |
| i.e. if the first and second register share a common
 | |
| subregister in one tuple and not in the other they are considered different.
 | |
| .NH 3
 | |
| fillem.c
 | |
| .PP
 | |
| This is the routine that does the reading of EM instructions
 | |
| and the handling of pseudos.
 | |
| The mach.c module provided by the table writer is included
 | |
| at the end of this module.
 | |
| The routine fillemlines() is called by nextem() at toplevel
 | |
| to make sure there are enough instruction to match.
 | |
| It fills the EM instruction buffer up to 5 places from the end to
 | |
| keep room for EM replacement instructions,
 | |
| or up to a pseudo.
 | |
| .PP
 | |
| The dopseudo() function performs the function of the pseudo last
 | |
| encountered.
 | |
| If the pseudo is a 
 | |
| .B rom
 | |
| the corresponding label is saved with the contents of the
 | |
| .B rom
 | |
| to be available to the code generator later.
 | |
| The rest of the routines are small service routines for either
 | |
| input or data output.
 | |
| .NH 3
 | |
| gencode.c
 | |
| .PP
 | |
| This module contains routines called by codegen() to generate the real
 | |
| code to the codefile.
 | |
| The function genstr() gets a string as argument and copies it to codefile.
 | |
| The prtoken() function interprets the tokenformat as given in
 | |
| the tokens[] array.
 | |
| .NH 3
 | |
| glosym.c
 | |
| .PP
 | |
| This module maintains a list of global symbols that have a 
 | |
| .B rom
 | |
| pseudo associated.
 | |
| There are functions to enter a symbol and to find a symbol.
 | |
| .NH 3
 | |
| main.c
 | |
| .PP
 | |
| Main routine of the code generator.
 | |
| Processes arguments and flags.
 | |
| Flags available are:
 | |
| .IP -d
 | |
| Sets debug mode if the code generator was not compiled with
 | |
| the NDEBUG macro defined.
 | |
| The flag can be followed by a digit specifying the amount of debugging
 | |
| wanted,
 | |
| and by @labelname giving the start of debugging.
 | |
| Debug mode gives very long output on stderr indicating
 | |
| all steps of the code generation process including nesting
 | |
| of the codegen() function.
 | |
| .IP -p\fIn\fP
 | |
| Sets the look ahead depth to
 | |
| .I n ,
 | |
| the
 | |
| .I p
 | |
| stands for ply,
 | |
| a well known word in chess playing programs.
 | |
| .IP -w\fIn\fP
 | |
| Sets the weight percentage for size in the cost function to
 | |
| .I n
 | |
| percent.
 | |
| Uses Euclides algorithm to simplify rationals.
 | |
| .NH 3
 | |
| move.c
 | |
| .PP
 | |
| Function to implement the move instruction in the tables,
 | |
| register initialization and the test instruction and associated bookkeeping.
 | |
| First tests are made to try to prevent the move from really happening.
 | |
| After that, if there is an after that,
 | |
| the move rule is found and the code executed.
 | |
| .NH 3
 | |
| nextem.c
 | |
| .PP
 | |
| The entry point of this module is nextem().
 | |
| It hashes the next three EM instructions,
 | |
| and uses the low order byte of the hash
 | |
| as an index into the array pathash[],
 | |
| to find a chain of patterns in the array
 | |
| pattern[],
 | |
| that are all tried for a match.
 | |
| .PP
 | |
| The function trypat() does most of the work
 | |
| checking patterns.
 | |
| When a pattern is found to match all instructions
 | |
| the operands of the instruction are placed into the dollar[] array.
 | |
| Then the boolean expression is tried.
 | |
| If it matches the function can return,
 | |
| leaving the operands still in the dollar[] array,
 | |
| so later in the code rule they can still be used.
 | |
| .NH 3
 | |
| reg.c
 | |
| .PP
 | |
| Collection of routines to handle registers.
 | |
| Reference count routines are here,
 | |
| chrefcount() and getrefcount(),
 | |
| plus routines to erase a single register or all of them,
 | |
| erasereg() and cleanregs().
 | |
| .PP
 | |
| If NDEBUG hasn't been defined, here is also the routine that checks
 | |
| if the reference count kept with the register information is in
 | |
| agreement with the number of times it occurs on the fake stack.
 | |
| .NH 3
 | |
| salloc.c
 | |
| .PP
 | |
| Module for string allocation and garbage collection.
 | |
| Contains entry points myalloc(),
 | |
| a routine calling malloc() and checking whether room is left,
 | |
| myfree(), just free(),
 | |
| popstr() a function called from state.c to free all strings
 | |
| made since the last saved status.
 | |
| Furthermore there is salloc() which has the size of the string as parameter
 | |
| and returns a pointer to the allocated space,
 | |
| while keeping a copy of the pointer for garbage allocation purposes.
 | |
| .PP
 | |
| The function garbage_collect is called from codegen() at toplevel
 | |
| every now and then,
 | |
| and checks all places where strings may reside to mark strings
 | |
| as being in use.
 | |
| Strings not in use are returned to the pool of free space.
 | |
| .NH 3
 | |
| state.c
 | |
| .PP
 | |
| Set of routines called to save current status and
 | |
| restore a previous saved state.
 | |
| .NH 3
 | |
| subr.c
 | |
| .PP
 | |
| Random set of leftover routines.
 | |
| .NH 4
 | |
| match
 | |
| .PP
 | |
| Computes whether a certain token matches a certain token expression.
 | |
| Just computes a bitnumber according to the algorithm explained with
 | |
| machsets[],
 | |
| and tests the bit and the boolean expression if it is there.
 | |
| .NH 4
 | |
| instance,cinstance
 | |
| .PP
 | |
| These two functions compute a token from a description.
 | |
| They differ very slight, cinstance() is used to compute
 | |
| the result of a coercion in a certain context
 | |
| and therefore has more arguments, which it uses instead of
 | |
| the global information instance() works on.
 | |
| .NH 4
 | |
| eqtoken
 | |
| .PP
 | |
| eqtoken computes whether two tokens can be considered identical.
 | |
| Used to check register contents during moves mainly.
 | |
| .NH 4
 | |
| distance
 | |
| .PP
 | |
| This is the heuristic function that computes a distance from
 | |
| the current fake stack contents to the token pattern in the table.
 | |
| It likes exact matches most, then matches where at least the sizes are correct
 | |
| and if the sizes are not correct it likes too large sizes more than too
 | |
| small, since splitting a token is easier than combining one.
 | |
| .NH 4
 | |
| split
 | |
| .PP
 | |
| This function tries to find a splitting coercion
 | |
| and executes it immediately when found.
 | |
| The fake stack is shuffled thoroughly when this happens,
 | |
| so pieces below the token that must be split are saved first.
 | |
| .NH 4
 | |
| docoerc
 | |
| .PP
 | |
| This function executes a coercion that was found.
 | |
| The same shuffling is done, so the top of the stack is again saved.
 | |
| .NH 4
 | |
| stackupto
 | |
| .PP
 | |
| This function gets a pointer into the fake stack and must stack
 | |
| every token including the one pointed at up to the bottom of the fake stack.
 | |
| The first stacking rule possible is used,
 | |
| so rules using registers must come first.
 | |
| .NH 4
 | |
| findcoerc
 | |
| .PP
 | |
| Looks for a one to one coercion, if found it returns a pointer
 | |
| to it and leaves a list of possible registers to use in the global
 | |
| variable curreglist.
 | |
| This is used by codegen().
 | |
| .NH 3
 | |
| var.c
 | |
| .PP
 | |
| Global variables used by more than one module.
 | |
| External definitions are in extern.h.
 |