|
@@ -0,0 +1,305 @@
|
|
|
+.NH 2
|
|
|
+Implementation.
|
|
|
+.PP
|
|
|
+In this section we will discuss the implementation of the CS phase.
|
|
|
+We will first describe the basic actions that are undertaken
|
|
|
+by the algorithm, than the algorithm itself.
|
|
|
+.NH 3
|
|
|
+Partioning the EM instructions
|
|
|
+.PP
|
|
|
+There are over 100 EM instructions.
|
|
|
+For our purpose we partition this huge set into groups of
|
|
|
+instructions which can be more or less conveniently handled together.
|
|
|
+.PP
|
|
|
+There are groups for all sorts of load instructions:
|
|
|
+simple loads, expensive loads, loads of an array element.
|
|
|
+A load is considered \fIexpensive\fP when more than one EM instructions
|
|
|
+are involved in loading it.
|
|
|
+The load of a lexical entity is also considered expensive.
|
|
|
+For instance: LOF is expensive, LAL is not.
|
|
|
+LAR forms a group on its own,
|
|
|
+because it is not only an expensive load,
|
|
|
+but also implicitly includes the ternary operator AAR,
|
|
|
+which computes the address of the array element.
|
|
|
+.PP
|
|
|
+There are groups for all sorts of operators:
|
|
|
+unary, binary, and ternary.
|
|
|
+The groups of operators are further partitioned according to the size
|
|
|
+of their operand(s) and result.
|
|
|
+\" .PP
|
|
|
+\" The distinction between operators and expensive loads is not always clear.
|
|
|
+\" The ADP instruction for example,
|
|
|
+\" might seem a unary operator because it pops one item
|
|
|
+\" (a pointer) from the stack.
|
|
|
+\" However, two ADP-instructions which pop an item with the same value number
|
|
|
+\" need not have the same result,
|
|
|
+\" because the attributes (an offset, to be added to the pointer)
|
|
|
+\" can be different.
|
|
|
+\" Is it then a binary operator?
|
|
|
+\" That would give rise to the strange, and undesirable,
|
|
|
+\" situation that some binary operators pop two operands
|
|
|
+\" and others pop one.
|
|
|
+\" The conclusion is inevitable:
|
|
|
+\" we have been fooled by the name (ADd Pointer).
|
|
|
+\" The ADP-instruction is an expensive load.
|
|
|
+\" In this context LAF, meaning Load Address of oFfsetted,
|
|
|
+\" would have been a better name,
|
|
|
+\" corresponding to LOF, like LAL,
|
|
|
+\" Load Address of Local, corresponds to LOL.
|
|
|
+.PP
|
|
|
+There are groups for all sorts of stores:
|
|
|
+direct, indirect, array element.
|
|
|
+The SAR forms a group on its own for the same reason
|
|
|
+as appeared with LAR.
|
|
|
+.PP
|
|
|
+The effect of the remaining instructions is less clear.
|
|
|
+They do not help very much in parsing expressions or
|
|
|
+in constructing our pseudo symboltable.
|
|
|
+They are partitioned according to the following criteria:
|
|
|
+.RS
|
|
|
+.IP "-"
|
|
|
+They change the value of an entity without using the stack
|
|
|
+(e.g. ZRL, DEE).
|
|
|
+.IP "-"
|
|
|
+They are subroutine calls (CAI, CAL).
|
|
|
+.IP "-"
|
|
|
+They change the stack in some irreproduceable way (e.g. ASP, LFR, DUP).
|
|
|
+.IP "-"
|
|
|
+They have no effect whatever on the stack or on the entities.
|
|
|
+This does not mean they can be deleted,
|
|
|
+but they can be ignored for the moment
|
|
|
+(e.g. MES, LIN, NOP).
|
|
|
+.IP "-"
|
|
|
+Their effect is too complicate too compute,
|
|
|
+so we just assume worst case behaviour.
|
|
|
+Hopefully, they do not occur very often.
|
|
|
+(e.g. MON, STR, BLM).
|
|
|
+.IP "-"
|
|
|
+They signal the end of the basic block (e.g. BLT, RET, TRP).
|
|
|
+.RE
|
|
|
+.NH 3
|
|
|
+Parsing expressions
|
|
|
+.PP
|
|
|
+To recognize expressions,
|
|
|
+we simulate the behaviour of the EM machine,
|
|
|
+by means of a fake-stack.
|
|
|
+When we scan the instructions in sequential order,
|
|
|
+we first encounter the instructions that load
|
|
|
+the operands on the stack,
|
|
|
+and then the instruction that indicates the operator,
|
|
|
+because EM expressions are postfix.
|
|
|
+When we find an instruction to load an operand,
|
|
|
+we load on the fake-stack a struct with the following information:
|
|
|
+.DS
|
|
|
+(1) the value number of the operand
|
|
|
+(2) the size of the operand
|
|
|
+(3) a pointer to the first line of EM-code
|
|
|
+ that constitutes the operand
|
|
|
+.DE
|
|
|
+In most cases, (3) will point to the line
|
|
|
+that loaded the operand (e.g. LOL, LOC),
|
|
|
+i.e. there is only one line that refers to this operand,
|
|
|
+but sometimes some information must be popped
|
|
|
+to load the operand (e.g. LOI, LAR).
|
|
|
+This information must have been pushed before,
|
|
|
+so we also pop a pointer to the first line that pushed
|
|
|
+the information.
|
|
|
+This line is now the first line that defines the operand.
|
|
|
+.PP
|
|
|
+When we find the operator instruction,
|
|
|
+we pop its operand(s) from the fake-stack.
|
|
|
+The first line that defines the first operand is
|
|
|
+now the first line of the expression.
|
|
|
+We now have all information to determine
|
|
|
+whether the just parsed expression has occurred before.
|
|
|
+We also know the first and last line of the expression;
|
|
|
+we need this when we decide to eliminate it.
|
|
|
+Associated with each available expression is a set of
|
|
|
+which the elements contains the first and last line of
|
|
|
+a recurrence of this expression.
|
|
|
+.PP
|
|
|
+Not only will the operand(s) be popped from the fake-stack,
|
|
|
+but the following will be pushed:
|
|
|
+.DS
|
|
|
+(1) the value number of the result
|
|
|
+(2) the size of the result
|
|
|
+(3) a pointer to the first line of the expression
|
|
|
+.DE
|
|
|
+In this way an item on the fake-stack always contains
|
|
|
+the necessary information.
|
|
|
+As you see, EM expressions are parsed bottum up.
|
|
|
+.NH 3
|
|
|
+Updating entities
|
|
|
+.PP
|
|
|
+As said before,
|
|
|
+we build our private "symboltable",
|
|
|
+while scanning the EM-instructions.
|
|
|
+The behaviour of the EM-machine is not only reflected
|
|
|
+in the fake-stack,
|
|
|
+but also in the entities.
|
|
|
+When an entity is created,
|
|
|
+we do not yet know its value,
|
|
|
+so we assign a brand new value number to it.
|
|
|
+Each time a store-instruction is encountered,
|
|
|
+we change the value number of the target entity of this store
|
|
|
+to the value number of the token that was popped
|
|
|
+from the fake-stack.
|
|
|
+Because entities may overlap,
|
|
|
+we must also "forget" the value numbers of entities
|
|
|
+that might be affected by this store.
|
|
|
+Each such entity will be \fIkilled\fP,
|
|
|
+i.e. assigned a brand new valuenumber.
|
|
|
+.PP
|
|
|
+Because we lose information when we forget
|
|
|
+the value number of an entity,
|
|
|
+we try to save as much entities as possible.
|
|
|
+When we store into an external,
|
|
|
+we don't have to kill locals and vice versa.
|
|
|
+Furthermore, we can see whether two locals or
|
|
|
+two externals overlap,
|
|
|
+because we know the offset from the local base,
|
|
|
+resp. the offset within the data block,
|
|
|
+and the size.
|
|
|
+The situation becomes more complicated when we have
|
|
|
+to consider indirection.
|
|
|
+The worst case is that we store through an unknown pointer.
|
|
|
+In that case we kill all entities except those locals
|
|
|
+for which a so-called \fIregister message\fP has been generated;
|
|
|
+this register message indicates that this local can never be
|
|
|
+accessed indirectly.
|
|
|
+If we know this pointer we can be more careful.
|
|
|
+If it points to a local then the entity that is accessed through
|
|
|
+this pointer can never overlap with an external.
|
|
|
+If it points to an external this entity can never overlap with a local.
|
|
|
+Furthermore, in the latter case,
|
|
|
+we can find the data block this entity belongs to.
|
|
|
+Since pointer arithmetic is only defined within a data block,
|
|
|
+this entity can never overlap with entities that are known to
|
|
|
+belong to another data block.
|
|
|
+.PP
|
|
|
+Not only after a store-instruction but also after a
|
|
|
+subroutine-call it may be necessary to kill entities;
|
|
|
+the subroutine may affect global variables or store
|
|
|
+through a pointer.
|
|
|
+If a subroutine is called that is not available as EM-text,
|
|
|
+we assume worst case behaviour,
|
|
|
+i.e. we kill all entities without register message.
|
|
|
+.NH 3
|
|
|
+Additions and replacements.
|
|
|
+.PP
|
|
|
+When a new expression comes available,
|
|
|
+we check whether the result is saved in a local
|
|
|
+that may go in a register.
|
|
|
+The last line of the expression must be followed
|
|
|
+by a STL or SDL instruction,
|
|
|
+depending on the size of the result
|
|
|
+(resp. WS and 2*WS),
|
|
|
+and a register message must be present for
|
|
|
+this local.
|
|
|
+If we have found such a local,
|
|
|
+we store a pointer to it with the available expression.
|
|
|
+Each time a new occurrence of this expression
|
|
|
+is found,
|
|
|
+we compare the value number of the local against
|
|
|
+the value number of the result.
|
|
|
+When they are different we remove the pointer to it,
|
|
|
+because we cannot use it.
|
|
|
+.PP
|
|
|
+The available expressions are singly linked in a list.
|
|
|
+When a new expression comes available,
|
|
|
+we link it at the head of the list.
|
|
|
+In this way expressions that are contained within other
|
|
|
+expressions appear later in the list,
|
|
|
+because EM-expressions are postfix.
|
|
|
+When we are going to eliminate expressions,
|
|
|
+we walk through the list,
|
|
|
+starting at the head, to find the largest expressions first.
|
|
|
+When we decide to eliminate an expression,
|
|
|
+we look at the expressions in the tail of the list,
|
|
|
+starting from where we are now,
|
|
|
+to delete expressions that are contained within
|
|
|
+the chosen one because
|
|
|
+we cannot eliminate an expression more than once.
|
|
|
+.PP
|
|
|
+When we are going to eliminate expressions,
|
|
|
+and we do not have a local that holds the result,
|
|
|
+we emit a STL or SDL after the line where the expression
|
|
|
+was first found.
|
|
|
+The other occurrences are simply removed,
|
|
|
+unless they contain instructions that not only have
|
|
|
+effect on the stack; e.g. messages, stores, calls.
|
|
|
+Before each instruction that needs the result on the stack,
|
|
|
+we emit a LOL or LDL.
|
|
|
+When the expression was an AAR,
|
|
|
+but the instruction was a LAR or a SAR,
|
|
|
+we append a LOI resp. a STI of the number of bytes
|
|
|
+in an array-element after each LOL/LDL.
|
|
|
+.NH 3
|
|
|
+Desirability analysis
|
|
|
+.PP
|
|
|
+Although the global optimizer works on EM code,
|
|
|
+the goal is to improve the quality of the object code.
|
|
|
+Therefore we need some machine dependent information
|
|
|
+to decide whether it is desirable to
|
|
|
+eliminate a given expression.
|
|
|
+Because it is impossible for the CS phase to know
|
|
|
+exactly what code will be generated,
|
|
|
+we use some heuristics.
|
|
|
+In most cases it will save time when we eliminate an
|
|
|
+operator, so we just do it.
|
|
|
+We only look for some special cases.
|
|
|
+.PP
|
|
|
+Some operators can in some cases be translated
|
|
|
+into an addressing mode for the machine at hand.
|
|
|
+We only eliminate such an operator,
|
|
|
+when its operand is itself "expensive",
|
|
|
+i.e. not just a simple load.
|
|
|
+The user of the CS phase has to supply
|
|
|
+a set of such operators.
|
|
|
+.PP
|
|
|
+Eliminating the loading of the Local Base or
|
|
|
+the Argument Base by the LXL resp. LXA instruction
|
|
|
+is only beneficial when the number of lexical levels
|
|
|
+we have to go back exceeds a certain threshold.
|
|
|
+This threshold will be different when registers
|
|
|
+are saved by the back end.
|
|
|
+The user must supply this threshold.
|
|
|
+.PP
|
|
|
+Replacing a SAR or a LAR by an AAR followed by a LOI
|
|
|
+may possibly increase the size of the object code.
|
|
|
+We assume that this is only possible when the
|
|
|
+size of the array element is greater than some
|
|
|
+(user-supplied) limit.
|
|
|
+.PP
|
|
|
+There are back ends that can very efficiently translate
|
|
|
+the index computing instruction sequence LOC SLI ADS.
|
|
|
+If this is the case,
|
|
|
+we do not eliminate the SLI instruction between a LOC
|
|
|
+and an ADS.
|
|
|
+.PP
|
|
|
+To handle unforeseen cases, the user may also supply
|
|
|
+a set of operators that should never be eliminated.
|
|
|
+.NH 3
|
|
|
+The algorithm
|
|
|
+.PP
|
|
|
+After these preparatory explanations,
|
|
|
+we can be short about the algorithm itself.
|
|
|
+For each instruction within our window,
|
|
|
+the following steps are performed in the order given:
|
|
|
+.IP 1.
|
|
|
+We check if this instructin defines an entity.
|
|
|
+If this is the case the set of entities is updated accordingly.
|
|
|
+.IP 2.
|
|
|
+We kill all entities that might be affected by this instruction.
|
|
|
+.IP 3.
|
|
|
+The instruction is simulated on the fake-stack.
|
|
|
+Copy propagation is done.
|
|
|
+If this instruction is an operator,
|
|
|
+we update the list of available expressions accordingly.
|
|
|
+.PP
|
|
|
+When we have processed all instructions this way,
|
|
|
+we have built a list of available expressions plus the information we
|
|
|
+need to eliminate them.
|
|
|
+Those expressions of which desirability analysis tells us so,
|
|
|
+we eliminate.
|
|
|
+The we shift our window and continue.
|