-
Notifications
You must be signed in to change notification settings - Fork 3
[Model] FeasibleRegisterAssignment #899
Description
Motivation
FEASIBLE REGISTER ASSIGNMENT (P294) from Garey & Johnson, A11 PO2. Given an expression DAG and a fixed assignment of registers to vertices, determine whether there exists a computation order that respects the assignment. This extends RegisterSufficiency (P293) by adding a constraint: not only must K registers suffice, but each vertex must use a specific pre-assigned register. Arises in compilers when register preferences are dictated by calling conventions or hardware constraints.
Associated reduction rules:
- As source: (none in G&J)
- As target: [Rule] 3-SATISFIABILITY to FEASIBLE REGISTER ASSIGNMENT #905 (3-SATISFIABILITY → FeasibleRegisterAssignment)
- Connections (beyond G&J):
- Extends RegisterSufficiency (P293/R225): if the register assignment is not fixed, we get the simpler sufficiency question
- Related to graph coloring: a register assignment is essentially a coloring of the interference graph, and feasibility asks if that coloring is realizable under evaluation order constraints
- Applications: compiler backends with ABI register constraints, hardware with dedicated register roles
Definition
Name: FeasibleRegisterAssignment
Reference: Garey & Johnson, Computers and Intractability, A11 PO2
Mathematical definition:
INSTANCE: Directed acyclic graph G = (V, A), positive integer K, a register assignment function f: V → {R₁, R₂, ..., Rₖ}.
QUESTION: Is there a computation for G (an ordering of the vertices respecting the DAG dependencies) such that at each step, when a vertex v is computed, register f(v) is available (not holding a live value needed later)?
Semantics:
A "computation" is a topological ordering π of the vertices (from leaves to roots). At step i, vertex π(i) is evaluated and its result is placed in register f(π(i)). A register Rⱼ is "available" at step i if no previously computed vertex u with f(u) = Rⱼ still has a descendant that has not yet been computed. In other words, the value in Rⱼ can be overwritten only if it is no longer needed.
The question is whether the DAG can be evaluated in some topological order such the fixed register assignment f never causes a conflict (needing to store a live value and a new value in the same register simultaneously).
Variables
- Count: The configuration space is the set of valid topological orderings of G.
- Per-variable domain: For brute-force binary encoding, one can assign each vertex a time slot (integer in [0, |V|-1]).
- Meaning: A valid computation is a topological ordering π such that for all i, register f(π(i)) does not hold a value still needed by an uncomputed vertex.
Schema (data type)
Type name: FeasibleRegisterAssignment
Variants: (none)
| Field | Type | Description |
|---|---|---|
num_vertices |
usize |
Number of vertices n = |V| |
arcs |
Vec<(usize, usize)> |
Directed arcs (v, u) meaning v depends on u |
num_registers |
usize |
Number of registers K |
assignment |
Vec<usize> |
Register assignment f: vertex index → register index (0-based) |
Notes:
- This is a decision (feasibility) problem: does a valid computation order exist?
assignment[v]gives the register index assigned to vertex v, with values in0..num_registers.- Schema follows the same pattern as
RegisterSufficiency(flat fields, no graph wrapper type). - Key getter methods:
num_vertices()(= number of vertices),num_arcs()(= number of arcs),num_registers()(= K).
Complexity
- Decision complexity: NP-complete (Sethi, 1975; transformation from 3SAT).
- Restrictions: NP-complete even with max out-degree 2.
- Best known exact algorithm: Brute-force over topological orderings with per-step register check.
- Complexity expression for
declare_variants!:num_vertices ^ 2 * 2 ^ num_vertices(same bound as RegisterSufficiency; the additional assignment check is O(1) per step). - References:
- R. Sethi (1975). "Complete Register Allocation Problems." SIAM Journal on Computing, 4(3), pp. 226–248. Original NP-completeness proof and relationship to register sufficiency.
Specialization
- This is a special case of: General register allocation (where both assignment and sufficiency are free)
- Generalizes: RegisterSufficiency (P293) — if we existentially quantify over f, we get register sufficiency
- Known special cases: Trees (polynomial — Sethi-Ullman techniques apply)
Extra Remark
Full book text:
INSTANCE: Directed acyclic graph G = (V, A), positive integer K, register assignment f: V → {R₁, R₂, ..., Rₖ}.
QUESTION: Is there a computation for G that respects the register assignment f?
Reference: [Sethi, 1975]. Transformation from 3-SATISFIABILITY.
Comment: NP-complete even with maximum out-degree 2.
How to solve
- It can be solved by (existing) bruteforce. Enumerate all topological orderings of the DAG and check if any respects the register assignment constraints.
- It can be solved by reducing to integer programming. (Possible via scheduling-style ILP with register liveness constraints.)
- Other: Polynomial for expression trees.
Example Instance
Expression DAG G with 4 vertices {0, 1, 2, 3}, K = 2 registers {R₀, R₁}:
- Leaves: {2, 3} (no dependencies)
- Internal: {1} depends on {3}
- Root: {0} depends on {1, 2}
- Arcs: (0→1), (0→2), (1→3)
Register assignment: f(0) = R₀, f(1) = R₁, f(2) = R₀, f(3) = R₀
Answer: YES — a feasible computation order exists.
Valid computation order: 3 → 1 → 2 → 0
- Step 1: Compute v3, place in R₀. (R₀ = v3, live — needed by v1)
- Step 2: Compute v1 = op(v3), place in R₁. v3 has no remaining dependents, so R₀ is now free. (R₁ = v1, live — needed by v0)
- Step 3: Compute v2 (leaf), place in R₀. (R₀ = v2, live — needed by v0; R₁ = v1, live — needed by v0)
- Step 4: Compute v0 = op(v1, v2), place in R₀. Reads v1 from R₁ and v2 from R₀, then overwrites R₀ with result. Done.
No register conflicts occur: each time a vertex is computed, its assigned register either was free or held a value no longer needed.
Infeasible variant (same DAG, K = 1, all vertices assigned to R₀):
- f(0) = R₀, f(1) = R₀, f(2) = R₀, f(3) = R₀
- Any valid topological order requires v3 before v1, and both v1 and v2 before v0.
- After computing v3 (R₀ = v3), computing v2 overwrites R₀ — but v1 still needs v3. Alternatively, computing v1 next overwrites R₀ — but v0 still needs v2. With only one register and fan-in 2 at the root, no order avoids a conflict.
- Answer: NO — no feasible computation order exists.
Validation script
#!/usr/bin/env python3
"""Validate FeasibleRegisterAssignment examples."""
from itertools import permutations
def is_topo_order(order, arcs, n):
pos = [0] * n
for i, v in enumerate(order):
pos[v] = i
return all(pos[u] < pos[v] for (v, u) in arcs)
def is_feasible(order, arcs, n, assignment):
dependents = {v: [] for v in range(n)}
for (v, u) in arcs:
dependents[u].append(v)
computed = set()
for v in order:
reg = assignment[v]
for w in computed:
if assignment[w] == reg:
if any(d not in computed and d != v for d in dependents[w]):
return False
computed.add(v)
return True
def solve(n, arcs, assignment):
return [list(p) for p in permutations(range(n))
if is_topo_order(p, arcs, n) and is_feasible(p, arcs, n, assignment)]
# Feasible: 4 vertices, arcs (0,1),(0,2),(1,3), K=2, assignment [0,1,0,0]
r1 = solve(4, [(0,1),(0,2),(1,3)], [0,1,0,0])
assert len(r1) == 1 and r1[0] == [3,1,2,0], f"Expected [[3,1,2,0]], got {r1}"
print("Feasible example: PASS")
# Infeasible: same DAG, K=1, assignment [0,0,0,0]
r2 = solve(4, [(0,1),(0,2),(1,3)], [0,0,0,0])
assert len(r2) == 0, f"Expected [], got {r2}"
print("Infeasible example: PASS")References
- [Sethi, 1975]: R. Sethi (1975). "Complete Register Allocation Problems." SIAM Journal on Computing, 4(3), pp. 226–248.
Metadata
Metadata
Assignees
Labels
Type
Projects
Status