Constructing a DAG for a Basic Block with Variable Redefinitions

Constructing a DAG for a Basic Block with Variable Redefinitions

Verified Sources
Nov 4, 2026

To construct the DAG for a basic block, you typically represent each statement as a node and draw edges to express data dependencies between the definitions of values and the uses of those values. Key dependency notions include true (flow) dependence and anti-dependence; together they guide correct ordering constraints. 2

For the basic block:

d=b∗ce=a+bb=b∗ca=e−d\begin{aligned} d &= b * c \\ e &= a + b \\ b &= b * c \\ a &= e - d \end{aligned}

the challenge is the redefinition of bb in the third statement. That means the uses of bb in statement 2 must depend on the original bb (from before the block), while the computation in statement 3 defines a new bb that is not used later within the block. Correct DAG construction therefore distinguishes “versions” of bb (via conceptual SSA-style renaming) so that edges reflect the proper source of each used value. 2

Footnotes

  1. Dynamic Data Flow Dependence / true dependence concepts (overview) - Defines true (flow) dependence and related dependence types. ↩

  2. Reordering constraints from dependence (data dependence graph relationships) - Discusses dependence relations used in program analysis. ↩

  3. Static Single Assignment (SSA) form - Explains SSA renaming and why it clarifies definitions/uses. ↩

  4. Compiler intermediate representation basics (basic blocks) - Defines basic blocks and how straight-line code segments are modeled. ↩

Data Dependence Graphs and SSA (conceptual overview)

Key definitions for DAG construction

  • basic block: we assume control flow is fixed, so dependencies are about values, not branch decisions.
  • node: each assignment becomes a node.
  • use and definition: edges connect definitions to uses.
  • SSA renaming: often done conceptually to handle reassignments like b=b∗cb=b*c.

A compact way to think about the DAG is:

  1. Create a node for each assignment.
  2. For each operand on the RHS, connect from the node (or input) that produces that exact value version.

Footnotes

  1. Static Single Assignment (SSA) form - Explains SSA renaming and why it clarifies definitions/uses. ↩

Step-by-step: build the DAG nodes and edges

  1. 1
    Step 1

    Create nodes N1..N4 corresponding to the four assignments in program order.

  2. 2
    Step 2

    Because bb is assigned in statement 3, treat the bb used in statements 1 and 2 as b0b_0 (the block’s incoming value), and treat the bb defined in statement 3 as b1b_1.

  3. 3
    Step 3

    For each statement, add incoming edges from the node/input that defines each RHS operand. For example, d=b∗cd=b*c uses b0b_0 and cc.

  4. 4
    Step 4

    Treat aa, b0b_0, and cc as coming from the block inputs (source nodes), then connect them to the computations that use them.

  5. 5
    Step 5

    The b1b_1 defined in statement 3 is not used later in the block, so there are no edges from N3 to statements after it.

  6. 6
    Step 6

    Because edges only go from the defining occurrence to the later use within the basic block, the graph remains acyclic.

DAG construction with value renaming

Let:

  • Node N1N1: d←b∗cd \leftarrow b * c
  • Node N2N2: e←a+be \leftarrow a + b
  • Node N3N3: b←b∗cb \leftarrow b * c (redefines bb)
  • Node N4N4: a←e−da \leftarrow e - d

Conceptually rename:

  • bb used in N1N1 and N2N2 is b0b_0 (incoming bb to the block)
  • bb defined by N3N3 is b1b_1

Also treat aa and cc as block inputs feeding the first uses:

  • aa input is a0a_0
  • cc input is c0c_0

Now the true dependencies are:

  • N1N1 uses b0b_0 and c0c_0, defines dd
  • N2N2 uses a0a_0 and b0b_0, defines ee
  • N3N3 uses b0b_0 and c0c_0, defines b1b_1
  • N4N4 uses ee and dd, defines aa (new value a1a_1)

Thus, edges are from the definition of each operand to each use:

  • From input b0b_0 to N1N1, N2N2, N3N3
  • From input c0c_0 to N1N1, N3N3
  • From input a0a_0 to N2N2
  • From N1N1 (defines dd) to N4N4 (uses dd)
  • From N2N2 (defines ee) to N4N4 (uses ee)

A correct DAG reflects only these value-producing dependencies (and not “schedule” dependencies that would be implied by anti/output dependence unless you’re building a dependence graph for reordering). The usual DAG for expression evaluation in a basic block is centered on true data dependencies. 2

Footnotes

  1. Dynamic Data Flow Dependence / true dependence concepts (overview) - Defines true (flow) dependence and related dependence types. ↩

  2. Reordering constraints from dependence (data dependence graph relationships) - Discusses dependence relations used in program analysis. ↩

Visual DAG (true data dependence)

Pro Tip: Rename only what matters

You don’t need full SSA construction for every variable; here it’s sufficient to distinguish b0b_0 vs b1b_1 so that uses in N2N2 correctly depend on the pre-redefinition bb.

Don’t add edges based on “name” alone

A common mistake is to connect N3N3 to N4N4 because both mention bb/aa by name. DAG edges should connect the specific value definitions to their uses.

Dependency-driven evaluation order (one valid schedule)

Compute d and e in parallel

Step 1

N1 and N2 depend only on inputs a0, b0, c0."

Compute b1

Step 2

N3 can run after inputs are available; it does not affect later nodes in this block."

Compute a1

Step 3

N4 requires both d (from N1) and e (from N2)."

Summary of true dependencies per node

Counts of distinct value sources feeding each computation (inputs and prior nodes).

FAQ on DAG vs other dependence graphs

Knowledge Check

Question 1 of 4
Q1Single choice

In the DAG for the block, which statement defines the value of dd used by the final statement a=e−da=e-d?