diff --git a/docs/handoffs/HANDOFF-lowering-buffer.md b/docs/handoffs/HANDOFF-lowering-buffer.md new file mode 100644 index 0000000..d633f6f --- /dev/null +++ b/docs/handoffs/HANDOFF-lowering-buffer.md @@ -0,0 +1,73 @@ +# Handoff — one buffer for every lowering + +Branch `dev-loop`, worktree `agent-a9d4028fa5752ba39`, from `f772162`. + +`spike/x86/dump.sh` landed at `f772162` and prints four lowerings of one function side by side: the LLVM IR +the frontend emits, what `llc` makes of it at `-O0` and at `-O2`, and what the hand-written x86 backend emits. +Reading one against another is the only way to check a lowering by eye. A shell script that prints all four +into a scrollback is not how anyone reads them, though: three of the four are noise on any given day, and the +one that is not is the one you are elbow-deep in. So the same four go into an Emacs buffer with collapsible +sections, and the buffer remembers which of them you had open. + +`M-x flan-lowering`, `C-c C-l` in `flan-mode`. + +## The three decisions + +### 1. It compiles the file; it does not ask the daemon + +`flan-disassemble` (`C-c C-a`) asks the running program what the body it is calling for a name actually came +out as. This asks a different question — what does this source compile to, through four different lowerings — +and the two cannot be merged, for a concrete reason rather than a stylistic one: **the daemon has the +installed body's `.ll` and its `.so`, and neither `llc -O2` nor the hand-written backend has ever been run +over it.** There is no answer in the daemon to give. `llc -O2` on the installed IR would be a fifth thing, +built here and never run anywhere, and the backend's output for an installed body does not exist at all +unless the daemon was started `--x86`. + +So the two commands sit beside each other and each says which question it answers. `flan-disassemble` keeps +its header, whose `showing` line is the daemon's own account of how much its answer claims. This buffer's +header says the opposite thing just as plainly: it names the file and the compiler flags, and says the +listing is what the source on disk compiles to and not what the program is running. Both docstrings +cross-reference the other. + +### 2. `outline-minor-mode`, not `magit-section` and not overlays of my own + +Nothing under `emacs/` requires a package that is not in Emacs — the whole client is `subr-x`, `seq`, +`pcase`, `cl-lib`, `xref`, `eldoc`, `comint`, `imenu` and its own files. Taking a dependency on Magit for a +four-section buffer would be the first, and it would be for folding, which Emacs has had since before Magit +existed. + +`outline-minor-mode` on GNU Emacs 30.2.50 is the whole of what was asked for: `outline-cycle` is `TAB` on a +heading, `outline-hide-body` and `outline-show-all` collapse and expand everything, and +`outline-next-visible-heading` / `outline-previous-visible-heading` are `n` and `p`. Hand-rolling it would be +a hundred lines re-implementing that badly. + +Headings are found by `outline-search-function` keyed to a text property this file puts on the four heading +lines, **not** by a regexp over the text. That is not fussiness: LLVM IR has `;` comments, assembler output +has `#` and `;` comments and lines that start with `.`, and `objdump` prints `:` label lines. Any +regexp loose enough to match four section headers matches inside three of the four bodies, and folding then +fragments in the middle of a listing. + +### 3. The open/closed state is a global alist keyed by section, and nothing else + +One `defvar`, four entries, alive for the Emacs session and no longer. Not persisted to disk: it is four +booleans, a preference file for it would one day have to be migrated, and nobody has ever wanted yesterday's +fold state back. + +Keyed to the **section**, not to the function. The workflow is "I am working on the backend today", which is +a fact about the section and holds across every function the author looks at while he is doing it. Keyed to +the function it would forget on every `M-x flan-lowering` of a different name, which is exactly the thing he +asked not to happen. + +The alist is the single source of truth. A toggle mutates it and then applies it to the buffer; a refresh +applies it to the newly drawn buffer. Visibility is never read back out — that would couple this to whether +outline folds with overlays or with text properties, which is a thing that has changed between Emacs +versions and is none of this file's business. + +## Status + +- [x] Handoff stub, decisions fixed +- [ ] `emacs/flan-lower.el` +- [ ] Key in `flan-mode`, autoloads +- [ ] Tests in `emacs/test-flan-dev.el` +- [ ] `emacs/MANUAL.md` +- [ ] `dune test`, `@page`, `@cells`