3.5.Dynamic Programming Optimization mode selection
In 1985 Aho and Ganapathi "6" showed a language called CGL, which provides a Glanville-graham-style notation to describe patterns. The description is sent to a preprocessor that produces an instruction selector that can be included in the compiler backend. The instruction selector is based on the Aho-corasick algorithm for pattern matching and includes a simplified version of the Dynamic Programming (DP) technology used by Aho and Johnson. The command selector executes three times on the input tree: two bottom-up times-the first node to mark pattern matching, the second for calculating the optimal selection, and the top-down of an outgoing code. Each pass execution shows the time complexity of O (n), thus producing the optimal command selection in linear time.
A summary of the DP algorithm (excluding the Pattern matching section) is given in Figure 3.11. Each node maintains a marker and two vectors--costs and matches. Terminator L is used as an index in the production "L←tree", Costs[l] gives the lowest-cost rule to generalize to L, Matches[l] gives the index of the rule. In this context rules and patterns hold the same meanings, and they are used interchangeably. For a given node n, the algorithm traverses all the patterns in the matching set of N. If the model is strictly reduced to a non-terminator l at a lower cost than the current best option, then update the vectors to reflect this better choice. The cost of applying a pattern p is the cost of the pattern itself plus the mode of the V node that matches p. Thus, an auxiliary function cost (t, N) is used to facilitate the calculation of this price. Because some rules may be the chain rule-that is, one substitution symbol is rewritten as another-the order in which the rules are traversed must be this: if some nodes are modified, the previously checked rules do not need to be re-examined. For example, if there are two rules in the match-set production "S←r" and "T←s", then the "S←r" should be checked first, because it may reduce the cost of "T←s". This practice was improved by Aho and other "7" and expanded into a well-known tree operation framework called twig (an early reference manual can be obtained in "224"). Figure 3.12 shows several addition rules expressed in twig.
This dynamic programming design has several advantages over linear parsing:
· The inductive conflict is automatically processed by the DP algorithm, thus eliminating the effect of the previous rule order on the code quality.
· It is no longer necessary to explicitly break the ring in the ruleset, which causes an infinite loop in the Glanville-graham-based directive selector.
· Machine descriptions are more concise because the rules can be more easily refactored into a single rule, with different costs and actions, only at the cost.
As a result, this leads to a simpler, smaller machine description. For example, the entire twig description of the report VAX machine, such as Aho, uses only 115 rules.
Several improvements in Twig were subsequently made by Yates and Schwartz "242" and Emmelmann, etc. "75". Yates and Schwartz the top-down version of the Twig's Hoffmann-o ' Donnell pattern matching algorithm, replacing it with a bottom-up version that matches faster and extended attribute support to allow more powerful predicates. Emmelmann implements a back-end generator called Beg, which includes an improved version of the DP algorithm that accompanies the IR tree build parallel operation. In addition, beg the auxiliary function code into the algorithm. Similar improvements are made by the Fraser, such as "98" when implementing Iburg, which is simpler (950 vs. 3,000 lines C code), 25 times times faster than Twig. Then Gough and Ledermann "114,115" to Iburg minor improvements, the implementation of Mburg, and Iburg has been implemented in various programming languages (i.e. Jburg "222" for Java, and Ocamlburg "225" for C + +) )。
Tjiang "223" [1] integrates twig and Iburg's ideas into olive (the name is a byproduct of twig). Tjiang also made several additional improvements, such as allowing rules to use arbitrary cost functions. Rather than a fixed value. By returning an infinite price, depending on the current context, the rule can be dynamically discontinued, which allows for more general instruction selection.
3.6.Estimated cost
In the dynamic programming approach shown previously, pattern matching algorithms are completely table-driven, while the cost calculation for optimal pattern selection is performed at code generation time. As we will see, these operations can also be pre-calculated and integrated into the table. We refer to this as the offline cost analysis.
The intuition is that you can parse the input tree using tags to find all matching patterns in the same way, or create states to parse the input tree to find the best choice. A state not only represents a matching set of a particular subtree, but also represents the optimal way to generalize the subtree to any given non-terminator set of patterns. The key to understanding here is that this does not mean that the state at the root node carries the information of this tree. In fact, such an attempt requires an infinite number of states. Conversely, a state only indicates which rule should be applied at the root node, so that subsequent rule selection for the subtree will collectively produce an optimal pattern selection for the entire tree. As we continue our discussion, it will be clearer.
From now on, suppose we have a set of table Statetablei, for a particular operator I, it gives the next state, and a table ruletable that gives the rules for a given state and goal. Then pattern matching and optimal mode selection can be fully driven, thus avoiding the computational cost of dynamic programming at runtime. For such an instruction selector, Figure 3.13 shows the pseudo-code.
According to the literature, Henry "128" [2] first discussed the idea in his doctoral dissertation, but the pioneers who actually tried it were Hatcher and Christopher "124". This approach seems quite unknown because it is rarely referenced, but from the information gathered-this is an extension of the bottom-up algorithm for Hoffmann and O ' Donnell-the algorithm works as follows. Initially, an additional lookup table is enforced to enhance the pattern-matching to handle swapping. After the pattern is matched, the top-down of a selection pattern is performed based on which tags are assigned to the node. This is done by querying another set of tables matchsettab--using the current node's markup and a non-terminator as the index. So this is similar to DP practice, how to choose a pattern after the cost is calculated.
So the question is how to calculate the table Matchsettab. First, because the preprocessor constructs the include diagram, it also collects the cost of converting the pattern p to another mode q that is included in P. This overrides p until it is equal to Q by recursively using other modes. This price is the sum of the costs of all the used patterns. We represent this cost as a function reducecost (P q). Now, the plan is to select a subtrees tree with the root node as the given tag at the lowest cost to generalize to a specific non-terminator rule. Hatcher and Christopher are implemented by first constructing the largest representation tree of the tag r--This is achieved by all patterns in the overlapping matching set--and then by selecting Make Reducecost (r x) = Reducecost (R z.rhs) + Z.cost's rule Z to start this problem. This will either select the largest mode, or, if present, a smaller, lower-cost pattern. However, if there are unrelated patterns, it is not always guaranteed to be optimal, requiring manual adjustment of the syntax.
[1] Based on the second-hand data from "159" and "38".
[2] Based on the second-hand data from "23".
Another approach to dealing with offline cost analysis is presented by Pelegrí-llopart and Graham "183". In their original paper, Pelegrí-llopart and Graham advocated a practice in which the input tree was gradually rewritten as a smaller tree, until only a single node was left. The author proves that the tree rewrite can be arranged so that it only occurs on the leaves of the tree, resulting in a bottom-up rewrite system (BURS). An example of a rewrite system is given in Figure 3.14 (a), which uses burs to represent most machine descriptions. Using the principle of burs, Pelegrí-llopart and Graham designed a table algorithm to calculate the optimal mode selection. The authors report that their implementations generate tables that are only a little larger than the tables generated by the Glanville-graham scheme, generating an almost twice-fold optimization code that is 5 times times faster than Twig.
The idea is as follows. For a given tree, a local rewrite diagram (LR diagram) makes the node represent the intermediate subtree, and the edge represents the application of a particular rewrite rule. An example of such a diagram is given in Figure 3.14 (b). Setting some nodes as targets (that is, the tree overrides the desired end node), selecting a sub-graph from the LR diagram makes the number of rewrite possibilities minimal. Because this is a np-complete problem, Pelegrí-llopart and Graham applied a heuristic to iteratively delete the nodes that were considered "useless". The resulting sub-graph is called a unique reversible LR diagram (UI LR diagram). Each UI LR diagram corresponds to a state, and all States can be computed by generating an LR graph of all possible input subtrees.
To include the optimal mode selection, the extended LR diagram makes each node no longer a pattern (i.e. a subtrees tree), but rather a (p,c) pair, where C represents the minimum cost of reaching the mode p. An earthy approach is to include the full cost of reaching a particular pattern in the state. However, depending on the rewrite system, this may require an unlimited number of states, although this is not a typical feature of the real machine, figure 3.15 (b) gives an example. A better approach is to use the relative cost of the selected pattern. That is, C is calculated as the price of P and the difference between the minimum cost of any other pattern in the LR graph. This produces the same optimal mode selection, but the number of required states is significantly reduced (see Figure 3.15 (c)). This price is called the Delta cost, and the extended LR diagram is called the Δ-LR graph. To limit the size of the data, Pelegrí-llopart and Graham use an extension of the chase algorithm to generate the Δ-LR graph.
Figure 3.14:burs Example (from "183")
Figure 3.15: Conversion cost into status (from "183")
Since its publication, many subsequent papers wrongly discuss the idea of offline cost analysis with burs theory. Indeed, Pelegrí-llopart and Graham were the first to propose an efficient and feasible method to make the offline cost analysis a feasible solution to the optimal command selection of the table driver. However, the offline cost analysis and burs theory are actually orthogonal; as we will see, there are other ways to generate a simpler and more efficient state table.
Such a method is proposed by Balachandran such as "23". Unlike Pelegrí-llopart and Graham, their approach relies on traditional production-rule syntax rather than rewriting the system. In addition, their table generators are simpler and more efficient because it generates the smallest set of States directly, rather than enumerating all possible states first, and then trying to crop them. A major contribution of Balachandran is the introduction of linear form syntax (Linear-form grammar). This requires that each rule fall into one of the following categories:
· N0→op (N1, ..., NK)-where NI is non-terminator, OP is an operator of the number of arguments K > 0,
· n→t--where n is a non-terminator, T is a terminator (which can be seen as a special version of the first category, where k=0,), or
· Both N→m--n and M are non-terminating characters.
The first two categories collectively refer to the basic rules, and the final category is called chain rules. By introducing new non-terminator and implementing the rules necessary for transformation, a nonlinear syntax can easily be rewritten as a linear form, namely:
Rule Cost Rule Cost
reg→? (+ (Reg,reg)) 2 reg→? (N1) 2
n1 →+ (N2,N2) 0
N2→reg 0
Primitive syntax è normal form syntax
The advantage of the linear form syntax is that each rule expands only one layer down in the input tree. This simplifies the algorithm because they do not need to consider the case where a rule might force certain nodes to be skipped.
Essentially, the table generation algorithm, such as Balachandran, runs by first generating state for all possible leaf nodes and then iteratively computing the new state from the existing state. This thought was also adopted by proebsting "187,188". Since the two approaches are essentially similar, we will continue our discussion with the latter, in addition to Proebsting, which provides a simpler and more detailed explanation. However, in this report, we will only give a summary of the algorithm, and it is recommended that interested readers review "188", which gives a detailed description.
Like Balachandran and others, the Proebsting table generator assumes that the syntax is linear, because it simplifies the algorithm. The algorithm revolves around a task force column that contains a considered state. Initially, this queue is empty and initialized with the state generated from all possible leaf nodes. Each state normalizes its cost so that the minimum cost of any applicable rule in that State is 0, and then all applicable chain rules are added to the state (this is called computational migration closures). The two states are the same, if each non-terminator the selected cost and the rule is the same. Then, for each state that pops up from the queue, the algorithm actually simulates what happens if a set of nodes is tagged with a popup state, any combination of nodes formed with an existing node, and as a child node of an operator node (see Figure 3.16). If such a combination of tagged child nodes represents an unseen state-that is, some non-terminator selected rules or nodes are different than the existing state-the new state promises to exist and is added to the queue. When the queue becomes empty, the algorithm terminates, indicating that all States of interest have been generated. Fraser "99" in a well-known code generation system called BURG[1] implemented this algorithm, since the introduction of burg in the compiler community has led the naming convention, I call it burger phenomenon [2].
If you reduce the number of build states, you can increase the speed of the table builder. Henry "127" [3] made the initial attempt, which was later improved and popularized by proebsting "187,188". Proebsting has developed two methods to reduce the number of build states: State pruning (statetrimming), which expands and promotes Henry's approach, and chain rule pruning (chain rule trimming). The former adds two possibilities to create the same state by eliminating non-terminator information that proves not to be involved in the lowest cost coverage. The latter minimizes the number of States by using the same rules as much as possible. The algorithm is further improved by Kang and Choe "136,137", which take full advantage of the nature of the generic machine description to reduce repetitive state testing.
[1] The connection between Burg and Iburg began with Iburg as a test platform for the syntax description, which was later used for Burg. Because some of the ideas applied in Iburg show some benefits, Fraser and so on Iburg improved and expanded into a separate instruction selector generator.
[2] In the study of this review, I encountered the following: BURG "99", Cburg "202", Dburg "80", Gburg "97", Iburg "98", Jburg "222", Hburg "218", Lburg "122", Mburg "114,115", Ocamlburg "225", and Wburg "189".
[3] Based on the second-hand data from "187".
Therefore, the idea of combining offline cost analysis with bottom-up tree pattern matching has been implemented in many compiler-related systems. Other notable but not mentioned procedures include: Hatcher and Tuller's Unh-codegen "126];engler and proebsting DCG" 78 "; Hanson and Fraser Lburg" 122 " , and the Wburg "189" of proebsting and Whaley. Burg also has a Haskell version, called Hburg "218".
3.7.Both worlds
Both DP-based and table-driven command selectors have their own pros and cons. The former--the full cost of applying a rule is calculated during code generation--with the benefit of supporting dynamic costs, that is, the cost of a pattern depends on context rather than static. It is much slower than the pure-table-driven equivalent of faster code generation in exchange for longer preprocessing time. However, because of these tables, such directive selectors have a much larger tendency to generate them very time consuming; for morbid syntax, this may not be feasible. In addition, the cost of a particular rule must be fixed.
Ertl and other "81" found a way to integrate the advantages of both technologies to compensate for their shortcomings. Intuitively this is true: not all States are pre-generated, only the necessary state is generated on a given input tree to perform the command selection. This is done by creating the state on demand during code generation. When a new subtree is encountered, use dynamic planning to create the state that is required to process the subtree. These states are then reused for the other identical subtrees that may appear in the input program, and the cost of the build state is apportioned. Therefore, unlike the previous state calculation as part of the compiler compiler-the state must be computed for all possible input trees-the state in this method only needs to process the single subtrees tree. This results in much shorter state generation times and smaller tables-in fact, it is equivalent to a purely DP-based solution-enabling it to handle larger, more complex machine descriptions. In addition, compared to a full table-driven directive selector, the cost is minimal in the reuse state. Ertl also expands the idea to deal with the dynamic cost by rewriting the state in the hash table of calculations and sorting as soon as the root node cost changes. Although this leads to additional overhead, it is still faster than a purely DP-based implementation.
3.8.other tree-based practices
Ganapathi "103" attempts to integrate tree rewriting, parsing, automation-driven tree pattern matching, and implements a system for the study of logical programming language Prolog. This scenario allows the command selection to be extended to a DAG (the topic is discussed more in the next chapter), but the worst-case execution time is a number of levels.
Giegerich and Schmal "110" The question of the selection of directives was re-elaborated as "a problem of a derived hierarchy" (Problem of a hierarchic derivor), and some of the practices of the same era were re-worded as such. In short terms, this requires specifying and implementing a mechanism "γ:t (q) →t (z)", where T (q) and t (z) represent algebraic entries (term algebras) in intermediate and machine languages, respectively. Therefore, gamma can be considered as the result of a directive selector. However, the machine description usually contains rules, in which each machine instruction in Z is expressed in accordance with Q, so we can treat the machine description as a homomorphism "δ:t (Z) →t (Q)". The task of the Command selection generator is to deduce gamma by inverting δ (i.e. through pattern matching techniques). For optimal command selection, whenever a "q∈t (q)" has several "z∈t (z)" to "δ (q) = Z", the generator must also stagger the δ?1 's construction with a selection function ξ. Interested readers are advised to refer to the paper.
By providing an algebraic framework, the purpose of Giegerich and Schmal is to allow formal descriptions of all aspects of code generation-not only command selection, but also instruction scheduling and register allocation, to simplify machine descriptions and to make it possible to prove completeness and correctness. Despland and other "63" put forward similar, based on rewriting techniques, dold and so on "67,246" using abstract state machine, developed the technology to prove the correctness of such descriptions. However, these ideas do not attract attention, because the number of citations of articles is at best Limited.
In an attempt to solve the hardware test, Nowak and Marwedel "179" developed a method in which the machine is molded into a graph that matches the input program (represented as a tree) on this machine diagram. Their papers are mentioned here only for completeness, because the practice integrates code generation into a single whole (that is, scheduling and register allocation) but rarely focuses on command selection.
Hatcher "125" developed a system called UCG that implements a similar approach to Pelegrí-llopart and Graham, but relies on logical equations rather than burs theory. These two notation are closely related, both of which apply a set of predefined rules to rewrite the input program as a single target item. However, in the machine description given as a logical equation, all of its conversion rules are based on a set of built-in operations. Built-in operations have a cost and implicit semantics expressed as code outflows. The cost of a rule equals the sum of all the built-in rule costs used in the rule, thus avoiding the cost of manually using each rule. In addition, there is no pre-defined built-in operation in UCG, but is given as part of the logical equation. This provides a very general mechanism for describing the machine. The best use of rules is achieved for a given input program by recalculating the matching state with a cost to the table. However, the work does not seem to be effective or very limited.
Another re-elaboration of the instruction selection problem is given by the Ferdinand, such as "88". Ferdinand the problem into a finite tree automaton, and by applying the existing theories in the field, it summarizes the state-based pattern matching algorithms previously invented by Hoffmann and O ' Donnell and Pelegrí-llopart and Graham. Ferdinand also shows several new algorithms based on subset construction, which generate finite tree automata from instruction selection. However, the lack of sufficient experimental data and comparisons with the same-era approach make it difficult to judge its importance. Later Borchardt "27" expanded the work by replacing tree automata with tree series transducers, but the importance of this was unclear.
Pointing to the digital signal processor, wess "236" specifically presents a method of using a raster diagram to integrate instruction selection with register allocation. The input tree is first converted to a raster graph, which essentially captures the use of all available machine instructions and registers for any given node in the expression tree. Each node in the raster diagram contains an array of optimal values (OVA), where each element represents a value stored in memory or a specific register. The value of the element represents the lowest accumulative cost from the leaf to the node. If saved in a register, the element also indicates which registers are available, which means that the size of the array is 2n?1+1 (the target register must be available and assume that each instruction writes only one register), where n is the number of registers on the target machine. For example, for a machine with two registers R1 and R2, the OVA is
where TL (i) represents the target position of the value, and RA (i) represents the available registers (examples are taken from "236"). Using this setting, a node is generated for each intermediate node of the expression tree in a raster diagram. A two raster graph node is generated for each leaf node to handle the case of input values that first need to be converted to another location before use. The En (i) is expressed as an OVA element I at node N. For a unary operation node, if there is an instruction sequence that implements this unary operation and the value of En (j) is generated by EM (i), an edge is generated between en (i) and Em (j). Similarly, for a two-dollar operation node, if there is such a corresponding sequence of instructions, a pair of edges are generated from en (i) and Nm (j) to EO (k). This can be generalized to n-ary operations. Finding the optimal code for a particular expression tree is simplified to find a path from each leaf to the root node, so that the final value is kept in one place, and the corresponding OVA element at the root node is minimal. Figure 3.7 shows an example. Because the raster diagram relies on the target machine, the redirect is done by modifying the way the grid diagram is formed. Although raster graphs allow processing of asymmetric registers and simultaneous instruction selection and register assignment, the processing time is several times the number of States. Fr?hlich and other "101" have been improved to make the raster diagram build on demand. However, it is not possible to imitate complex instructions because it assumes that the expression is one by one mapped to the machine instruction.
Figure 3.17: For the target machine for the 2 register described in the body, apply to the expression-(A * b) a raster diagram of –c. Assume that variables a, B, and C start in memory.
An unconventional technique was developed by using the theory of genetic algorithm "198" by Shu and other "210". The idea is to represent a solution as a DNA string, called a chromosome, and then split, merge, and mutate the existing solution (hopefully) to end with a better one. As for the question of command selection, Shu the chromosome as a binary string, where 1 indicates the selection of a specific pattern. So the length of each chromosome equals the number of pattern instances that match in a given tree. Each chromosome is evaluated by a finite function, and this function is defined as
where k is a constant greater than 1, F1 is the number of selected modes, and F2 is the number of nodes that are covered by multiple selected modes. So the goal is to maximize the adaptive value. This is achieved by subjecting a bit string to a standard GA operation (i.e., a reasonably proportional copy (fitness-proportionate reproduction), a single-point crossover (Single-point crossover), a little mutation (one-bit Mutations), etc., refer to Goldberg "112"). However, the experimental data in the paper is weak: The test case is limited to a medium-sized base block (up to 50 nodes) obtained from only two algorithms, and the importance of this practice is unclear.
Bravenboer and Visser "32" apply the rules-based program conversion system strategy (recent survey Reference "230") to resolve the command selection. Using a system called Stratego "231", the pattern selector can be defined as part of the machine description, allowing it to be clipped to the instruction set. In their paper, it is said that this provides a rewriting strategy. The system allows modeling of methods such as exhaustive search, maximum chewing, and dynamic programming. However, pure-table-driven technology such as consolidation-line cost analysis is obviously not supported. Therefore, theoretically stratego can combine several pattern selection techniques, but bravenboer and Visser do not provide a useful example.
3.9.Application
[1]
Over the years, the application tree-covered code generation system has been widely used in many compilers. Let's take a look at some examples. Araujo and Malik "16" use olive to attempt to integrate command selection with scheduling and register allocation. The record compiler developed by Leupers and Marwedel "160,169" uses Iburg, similar to the Redaco developed by "151" such as Kreuzer, which works on the compiler on the raster diagram. Pagode compiler, developed by "37" such as Canalda, applied a form of burs theory. Spam, a DSP-fixed-point processor compiler that applied the olive, developed in Princeton. The cosy compiler applies an improved version of Beg [2]. Boulytchev "28" overrides burg to assist instruction set selection. Finally, Lburg is used in LCC (Little C Compiler), written by Hanson and Fraser "122", and Brandner and other "31", they developed a structured architecture description language from which machine instructions can be automatically deduced.
3.10.Summary
In this chapter we looked at a number of tree-based overlays, or the practice of working on trees in such a way. These practices allow for more complex patterns than macro expansions, resulting in more efficient command selectors, and by applying dynamic programming, you can produce optimal code at linear times. Several techniques also integrate the offline cost analysis into the table generator, which further accelerates code generation. In other words, these practices are very fast, very efficient, and support the code generation of many machines. As a result, tree cover becomes the most famous method of instruction selection-even if it doesn't work best.
However, all of these methods have two inherent drawbacks. The first disadvantage is related to expression modeling. Because of the nature of the tree, common sub-expressions cannot be modeled correctly. For example, the following code
[1] This section mainly refers to the Leuper and Marwedel "159" before the investigation.
[2] According to "159" and "44".
Cannot be constructed as a tree, it does not have (i) repeated operations, i.e. = (y,+ (+ (A, B), + (A, b)), or (ii) split into a forest, i.e. = (x, (+ (A, b)) and = (y,+ (x, X)). The former causes the instruction to repeat, while the latter may result in a bad decision about the location of the data, because the connection between the two trees is lost. Therefore, tree-based directives only guarantee optimal selection when the input tree does not contain common sub-expressions-in the usual case, unreasonable assumptions, because such expressions are far from uncommon. In addition, this restriction prevents the modeling of machine instructions with multiple outputs (that is, the divmod instruction of both the quotient and the remainder, or any instruction that sets the condition code or status tag).
The second disadvantage is that the tree cannot emulate the control flow. For example, a for statement requires a back edge, which violates the definition of the tree. For this reason, tree-based instruction selectors work only on expression trees within the base block and use a separate method to flow out the code for the control stream. This results in an impediment to the matching of complex machine instructions containing any type of control flow, which must either be removed from the machine description or manually handled by the property function. In addition, the optimal decision on a local block domain may be suboptimal on a global function domain. Another related drawback is that machine instructions that cover multiple trees cannot be automatically matched or selected, such as SIMD instructions. This is attributed to the status tag, which can traverse only one tree at a time, as well as the pattern selection. Finally, none of the practices described in this chapter can handle machine instructions that do not fit the typical assumptions (that is, some additional resource constraints are used).
Therefore, although the tree cover method is better than macro expansion, at the cost of increasing complexity, it greatly improves the code quality, but it assumes that the program structure and machine behavior are not established in practice. In addition, all of these methods are limited to working within the base block, which can result in suboptimal results for the entire function. In the next chapter, we will look at ways to deal with these problems.
Directive Selector Survey (4)