-
Notifications
You must be signed in to change notification settings - Fork 3
[Model] MinimumCodeGenerationOneRegister #900
Description
Motivation
MINIMUM CODE GENERATION ON A ONE-REGISTER MACHINE (P296) from Garey & Johnson, A11 PO4. A fundamental compiler optimization problem: given an expression DAG, find the minimum number of instructions needed to evaluate all root values on a machine with a single accumulator register (supporting LOAD, STORE, and OP instructions). This models the instruction selection and scheduling phase of code generation for simple architectures.
Associated reduction rules:
- As target: R308 (3-SATISFIABILITY →)
- Connections (beyond G&J):
- Generalizes the Sethi-Ullman numbering problem for expression trees (which is polynomial)
- Related to RegisterSufficiency (P293): both concern register allocation, but this problem fixes the register count to 1 and asks about instruction count
Definition
Name: MinimumCodeGenerationOneRegister
Reference: Garey & Johnson, Computers and Intractability, A11 PO4
Mathematical definition:
INSTANCE: Directed acyclic graph G = (V, A) with max out-degree 2. Leaf vertices (out-degree 0) represent input values stored in memory. Internal vertices represent operations. Root vertices (in-degree 0) are the values to compute.
OBJECTIVE: Find a program of minimum number of instructions for a one-register machine that computes all root vertices.
Instruction semantics:
- LOAD v: Load the value of vertex v from memory into the register. For leaves, the value is the input; for internal vertices, the value must have been previously STOREd.
- STORE v: Save the current register value into memory as the computed value of vertex v.
- OP v: Compute vertex v by applying its operation to two operands: one must be in the register and the other must be in memory. The result is placed in the register. For unary operations (out-degree 1), only the register operand is used.
A valid program respects data dependencies: all children of v must be computed before OP v is executed.
Variables
- Count: n = |V| (one variable per vertex representing its position in the instruction schedule)
- Per-variable domain: {0, 1, ..., 3n-1} (time step at which the vertex's instruction is executed; upper bound since at most 3 instructions per vertex: LOAD/STORE/OP)
- Meaning: A valid program is a sequence of LOAD, STORE, and OP instructions that respects DAG dependencies and computes all root vertices. The objective minimizes the total instruction count.
Schema (data type)
Type name: MinimumCodeGenerationOneRegister
Variants: (none — fixed to DAGs)
| Field | Type | Description |
|---|---|---|
num_vertices |
usize |
Number of vertices |
edges |
Vec<(usize, usize)> |
Directed arcs (parent, child) in the expression DAG |
num_leaves |
usize |
Number of leaf vertices (out-degree 0) |
Complexity
- Decision complexity: NP-complete (Bruno and Sethi, 1976; transformation from 3SAT).
- Best known exact algorithm: O*(2^num_vertices) brute-force over instruction orderings. No sub-exponential exact algorithm is known.
- Restrictions: NP-complete even when vertices with in-degree > 1 have arcs only to leaves. Polynomial-time solvable for directed forests (trees) — the classical Sethi-Ullman algorithm gives an optimal instruction sequence for expression trees in O(n) time.
- References:
- J. Bruno, R. Sethi (1976). "Code Generation for a One-Register Machine." Journal of the ACM, 23(3), pp. 502–510.
- R. Sethi, J.D. Ullman (1970). "The Generation of Optimal Code for Arithmetic Expressions." Journal of the ACM, 17(4), pp. 715–728.
Extra Remark
Full book text:
INSTANCE: Directed acyclic graph G = (V, A) with maximum out-degree 2, positive integer K.
QUESTION: Is there a program of K or fewer instructions for a one-register machine that computes all the root (in-degree 0) vertices of G?
Reference: [Bruno and Sethi, 1976]. Transformation from 3-SATISFIABILITY.
Comment: NP-complete even if the only vertices having in-degree greater than 1 have arcs only to leaves [Bruno and Sethi, 1976]. Solvable in polynomial time for directed forests [Sethi and Ullman, 1970].
Note: The original G&J formulation is a decision problem with threshold K. We use the equivalent optimization formulation: minimize the number of instructions.
How to solve
- It can be solved by (existing) bruteforce. (Enumerate all valid instruction sequences respecting DAG dependencies; return the one with minimum length that computes all roots.)
- It can be solved by reducing to integer programming.
- Other: Sethi-Ullman algorithm for the tree/forest case (polynomial).
Example Instance
Expression DAG G with 7 vertices {v0, v1, v2, v3, v4, v5, v6}:
Leaves (out-degree 0, inputs in memory): {v4, v5, v6}
Internal nodes (binary operations):
- v3 = op(v5, v6)
- v1 = op(v3, v4)
- v2 = op(v3, v5) — note: v3 has in-degree 2 (shared subexpression)
- v0 = op(v1, v2) — root (in-degree 0)
Arcs: (v0→v1), (v0→v2), (v1→v3), (v1→v4), (v2→v3), (v2→v5), (v3→v5), (v3→v6)
Optimal program (8 instructions):
Leaves v4, v5, v6 are pre-loaded in memory as inputs.
- LOAD v5 — reg = v5
- OP v3 — reg = op(v5, mem[v6]) = v3; v6 is a leaf already in memory
- STORE v3 — mem[v3] = v3 (shared subexpression, needed by both v1 and v2)
- OP v2 — reg = op(v3, mem[v5]) = v2; v5 is a leaf still in memory
- STORE v2 — mem[v2] = v2
- LOAD v4 — reg = v4
- OP v1 — reg = op(v4, mem[v3]) = v1
- OP v0 — reg = op(v1, mem[v2]) = v0 ✓
Key insight: By computing v2 immediately after v3 (while v3 is still in the register), we avoid an extra LOAD. The shared subexpression v3 forces one STORE, and v2 forces another STORE to free the register for computing v1.
Suboptimal program (10 instructions): Computing v1 before v2 requires an extra LOAD v5 and STORE v1, totaling 10 instructions.
Expected Outcome
Optimal value: Min(8) — the minimum number of instructions to compute the root v0. Breakdown: 2 LOADs + 2 STOREs + 4 OPs = 8. The shared subexpression v3 (in-degree 2) is the source of complexity; without sharing, the tree case would be solvable by Sethi-Ullman in fewer steps.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status