Skip to content

The graphs a release opt will actually print, drawn inline - #48

Merged
tamnd merged 1 commit into
mainfrom
graph-viewer
Sep 6, 2026
Merged

tamnd merged 1 commit into
mainfrom
graph-viewer

Conversation

@tamnd

@tamnd tamnd commented Sep 6, 2026

Copy link
Copy Markdown
Owner

opt carries six dot printers that a release build keeps: dot-cfg,
dot-cfg-only, dot-dom, dot-post-dom, dot-ddg and dot-callgraph.
This reads what they emit and draws it, so the picture in a lesson is
LLVM's graph rather than one reconstructed from the IR alongside it.

m = irx.compile_c(src, opt="-O1")
irx.cfg(m)          # blocks with their instructions, T/F on the arms
irx.cfg(m, bodies=False)
irx.dom(m)          # and irx.graph(m, "post-dom")
irx.ddg(m)
irx.callgraph(m)

A Graph prints as text in a plain terminal, renders as an inline SVG in
a notebook, and exposes .nodes, .edges, .loops and .successors()
for a lesson that wants to assert on the shape rather than show it.

It is not a SelectionDAG viewer

-view-isel-dags and that whole family are declared inside #ifndef NDEBUG; the #else branch supplies static const bool ViewDAGCombine1 = false, .... On a release toolchain the flag is not turned off, it is not
a flag at all, and opt/llc reject it
(llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:147-189@llvmorg-23.1.0).
The book pins a release build, so no lesson can use them. The data
dependence graph is the graph a release opt gives you that genuinely is
a DAG, cycles and all collapsed into pi-blocks, and it is here as
irx.ddg.

Notes

  • No Graphviz. Layout is a longest-path ranking with lanes for back
    edges and for forward edges that skip a row, which is enough for the
    block counts a lesson shows and keeps the install to nothing.
  • Stable bytes. LLVM names nodes after object addresses, so printing
    the same function twice gives two different files. The parser maps them
    to n0, n1, ... and the one generated id in the SVG is a content
    hash, so rebuilding a notebook does not produce a diff.
  • No script, no click handlers. It ends up in saved notebooks and in
    static site HTML.
  • proc.run grows a cwd parameter: the printers write into the working
    directory and there is no flag that redirects them.

Checks

  • toolkit: 209 tests, OK (26 new, 8 of them against a real LLVM)
  • repo: 98 tests, OK
  • ruff check ., build.py check, prosecheck, refcheck --ledger,
    build.py diagrams clean

Part of #10.

`opt` has six dot printers that survive a release build, and this reads
their output rather than building a picture of its own. What comes back
is LLVM's graph, laid out and coloured, as an inline SVG with no
Graphviz on the machine and no JavaScript in the page.

Not a SelectionDAG viewer. `-view-isel-dags` and the rest of that family
live inside `#ifndef NDEBUG`, and the `#else` branch hands back constant
`false` flags, so on the toolchain this book pins the flag is not off,
it does not exist
(llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp:147-189@llvmorg-23.1.0).
The data dependence graph is the one a release `opt` gives you that is
actually a DAG, and it is here as `irx.ddg`.

LLVM names its dot nodes after object addresses, so the same function
printed twice gives two different files. The parser drops them for
`n0`, `n1` and so on, which is also what makes the SVG bytes stable
across a rebuild.

`proc.run` grows a `cwd`, because the printers write into the working
directory and no flag redirects them.
@tamnd
tamnd merged commit 032b040 into main Sep 6, 2026
8 checks passed
@tamnd
tamnd deleted the graph-viewer branch September 6, 2026 01:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant