Value numberingValue numbering is a technique of determining when two computations in a program are equivalent and eliminating one of them with a semantics-preserving optimization. Global value numberingGlobal value numbering (GVN) is a compiler optimization based on the static single assignment form (SSA) intermediate representation. It sometimes helps eliminate redundant code that common subexpression elimination (CSE) does not.[citation needed] At the same time, however, CSE may eliminate code that GVN does not, so both are often found in modern compilers. Global value numbering is distinct from local value numbering in that the value-number mappings hold across basic block boundaries as well, and different algorithms are used to compute the mappings. Global value numbering works by assigning a value number to variables and expressions. The same value number is assigned to those variables and expressions which are equivalent. For instance, in the following code: w := 3 x := 3 y := x + 4 z := w + 4 a good GVN routine would assign the same value number to w := 3 x := w y := w + 4 z := y Depending on the code following this fragment, copy propagation may be able to remove the assignments to The reason that GVN is sometimes more powerful than CSE comes from the fact that CSE matches lexically identical expressions whereas the GVN tries to determine an underlying equivalence. For instance, in the code: a := c × d e := c f := e × d Without copy propagation, CSE would not eliminate the recomputation assigned to In IRs and source languages where rebinding (assigning to the same variable more than once) is possible, SSA form is required to perform GVN so that false mappings are not created. Local value numberingLocal value numbering (LVN) is a compiler optimization that aims to find multiple instances of equivalent expressions (i.e. expressions which yield the same result) and replace them with the first occurrence. LVN is a local optimization, meaning that unlike global value numbering, it operates on a single basic block at a time. Local value numbering works by assigning a unique number to each operation and remembering these associations. Subsequent instructions are then looked up and, in case an identical instruction has already been registered, replaced with the previous instruction's result. For example: a ← 4 a is tagged as #1 b ← 5 b is tagged as #2 c ← a + b c (#1 + #2) is tagged as #3 d ← 5 d is tagged as #2, the same as b e ← a + d e, being '#1 + #2' is tagged as #3 By assigning numbers to instructions, comparing for duplicates is turned into simple integer comparisons. In this particular example, Difficulties and extensionsIssues when not using SSAA naive implementation might attempt to perform the optimization by directly using the variable names instead of numbers. However, this approach does not work when the values of variables can change. Consider the pseudocode: a ← 1 a is tagged as #1 b ← 2 b is tagged as #2 c ← a + b c is tagged as #3 b ← 3 d ← a + b d is incorrectly tagged as #3 In this scenario, Using mathematical identitiesA simple implementation might also be unable to catch all equivalent expressions, even when they only differ by the order of their operands. In the following example, a ← 1 + 2 b ← 2 + 1 This issue can easily be resolved either by assigning the same number to both cases (i.e. Local value numbering optimizers may also be aware of mathematical identities. Assuming b ← a + 0 c ← a * 1 d ← min(a, MAX_INT) e ← max(a, a) f ← a & 0xFF..FF (assuming '&' denotes bitwise AND) See alsoReferences
Further reading
|