Repository navigation
M9: Third target, third host, Postgres #10
Description
The third target and the third host, and PostgreSQL.
RISC-V 64 is what spec/10-backend.md calls the middle-end canary: an architecture different enough from x86-64 and AArch64 that a middle-end assumption baked into both of them shows up as a failure rather than as slightly worse code. Windows brings COFF, a fourth ABI and SEH unwind tables, and it is the host most likely to find something the other two tolerated.
Exit criterion. The full six-row CI matrix is green, make check-world passes, pgbench is within the bound, and a GCC-built extension loads into a rucc-built server.
RISC-V 64
- The rule set, discharged by
rucc-verify - The encoder, and relaxation
- The calling convention
- Whatever the middle end assumed and should not have
Windows
- The COFF writer. Done through W1 to W2 (W1: rucc on Windows, and something executes #2067, W2: The constructs real programs hit #2068), with
SECREL,SECTION, DWARF in COFF, TLS anddllimport, and i386 decoration in W6 (W6: i686 Windows #2072). - The Windows x64 ABI, including the parts that are not System V with different registers.
ms_abiandsysv_abiper function in W2 (W2: The constructs real programs hit #2068), with the ABI differential against MinGW GCC in W3 (W3: UCRT, winpthreads, and the real corpus #2069) and againstcl.exein W4 (W4: The MSVC environment #2070). - SEH unwind tables.
.pdataand.xdatafor every function, realigned frames in W2 (W2: The constructs real programs hit #2068), AArch64 in W5 (W5: AArch64 Windows #2071), and no function ending in a call in W6 (Put a trap after a call that ends a Windows x86-64 function #2779). - Windows as a host: the full suite passing natively, and finding the MSVC or MinGW toolchain.
rucc.exeand host detection in W0 and W1 (W0: A release user gets a Windows executable #2066, W1: rucc on Windows, and something executes #2067),lld-linkand the MSVC environment in W4 (W4: The MSVC environment #2070), andtest on windows x86-64passes onwindows-2025again since Escape the incbin test's path and run every test binary on each host #2805.
PostgreSQL
- Builds unpatched at all levels
-
make check-worldpasses -
pgbenchwithin the code quality bound, published including any losses - A GCC-built extension loads into a
rucc-built server, which is the real ABI test
CI
- All six rows of the matrix in
spec/15-testing.mdsection 15.7
What is explicitly not in scope
The kernel, and the hardening flags it needs. Those are M10 and M11.
This is the second sane stopping point, and the strongest one. At the end of M9 the project has met three of its four axes on three hosts and three targets against two large real databases, with continuous fuzzing and verified rewrite rules. Whether to attempt the kernel from here is a decision made with far better information than we have now.
Activity
tamnd commentedon Sep 18, 2026
#1435 lands the first half of the SEH unwind tables line above. A function that keeps a frame pointer on
x86_64-windows-gnunow reaches an object file with a record in it, which it never did before, and that covers every variable length array, everyallocaand everysetjmpon the target. The record a function carries on Windows counts every slot from where the stack pointer ends the prologue, so the order the prologue had, which is push the pointer, point it at the frame, then take the frame, has no rows the format can write. The fix reorders the prologue on that target only: push everything, take the frame, and only then point the register at it, with the move emitting aDefCfathat the writer turns intoUWOP_SET_FPREG. That is the shape gcc 13.2 emits forx86_64-w64-mingw32, measured on server3 rather than read off a manual, and what it costs is the chain of frame pointers, which nothing on Windows walks.Verified end to end: a program with all three shapes of frame in it compiles here, links with the mingw driver, runs under wine and prints the right answers, and its three
.xdatarecords decode by hand to the prologues the disassembly shows.The line stays unticked because one shape is still refused rather than described, which is a frame that forces its own alignment past sixteen bytes. The
andmask leaves the pushes at no constant distance from anything, so the pointer has to go up before the mask, and describing that needs a second base register. It is filed as #1422.tamnd commentedon Sep 18, 2026
#1442 has landed, which defines
__SEH__forx86_64-windows-gnuand closes the last gap in the predefined macro set for this target. It was held back by #1403 rather than by anything about the macro: mingw'ssetjmp.hreads it to choose the two argument_setjmp, whose second argument is__builtin_frame_address(0), and a function that asks for that used to be refused by the unwind writer.The pleasant part is that the two halves fit without anything having to be arranged.
longjmphands that second argument toRtlUnwindExas the frame to unwind to, which must be the establisher frame the target function's own unwind record reports, and the late prologue leaves the frame pointer holding exactly that address. So the number the builtin copies out of the register and the number the walk arrives at are the same number by construction.Measured on server3. A program that longjmps out of four frames of recursion back past a
setjmp, with a variable length array after it, prints the same answers under wine whether gcc 13.2 or this compiler built it, and the object passes%rbpto_setjmpwhere gcc passes%rbp.setjmp.his the only header in the mingw tree that reads the macro, so nothing else changes shape.tamnd commentedon Sep 18, 2026
Rung 1 is done, and the thing that stood in its way was one line of the code generator rather than anything about the tree.
sqlite3.ccompiled against the fetched sysroot on the first try, in 21 seconds, with nothing said on the command line about where the headers are.shell.cdid not: it stopped atnothing reaches 'sqlite3_free' through a table here [E0652], because the shell stores that function in a table of callbacks and every function a file only declares went into the set of names the instruction pointer cannot reach. That set exists for the global offset table and COFF has no such table, so the object writer was handed a relocation it has no spelling for and refused the file. On this format the question does not arise, since a name the link resolves out of another object is in the image and a name from a DLL arrives through an import library holding a jump under the plain name, which is why gcc writesleaq other(%rip), %raxthere. That is #1443 and #1448 fixed it.With that in, both objects compile, link with
x86_64-w64-mingw32-gccand run under wine.-Msays every header the build read came out of/root/.cache/rucc/sysroots/x86_64-windows-gnu, which is the treerucc --fetch x86_64-windows-gnuinstalls and nothing else. The shell prints3.53.4 2026-07-24 19:02:57 bf7c7f30...for-versionand answers3|6|one,two,threeto a create, an insert of three rows and a select.One rung left here, which is the row in section 13.1 with the installed size. The tree measures 85 MiB installed with an empty
libdirectory, so the import library question the description raises is still open and is what that row has to be honest about.tamnd commentedon Sep 18, 2026
All five rungs are done, so this closes.
The last one was the row in section 13.1, and the interesting part of it was that the estimate was wrong by a factor of five. The tree was written down as 15 MB and it is 80.5 MB, which is 1,702 headers and 8.5 MB gzipped, and that is larger on its own than the 75 MB the whole base distribution is budgeted for. So the row moved out of the base and into the cache of section 13.2, which is where the compiler was already putting it, and the rows above the line come to 55.9 MB.
Where the bytes go makes the number stop being surprising.
mshtml.halone is 6.5 MB, more than the entire glibc header tree, andddkis 2.2 MB andGLis 1.4 MB before any of it has declared a C library function. That is this issue's own observation about the Windows SDK half of the tree, arriving as a budget line.One question is left open and is named as open in the document rather than left implied: whether the published tree should be all of upstream or a subset. It is a question about which headers a program on this target may include rather than a question about bytes, so it waits for a program a subset would break.
The whole issue in order: #1403 for the unwind record, #1442 for
__SEH__, #1443 for the address of a declared function on COFF, and #1449 for the row. What is still not here is the import libraries, so the published tree has an emptyliband a link still names mingw's own, which is the next thing in front of #618 for this target.tamnd commentedon Sep 28, 2026
The Postgres section of this milestone is now split into ten milestones, PG0 to PG9, each with its own issue and exit criterion. They are labelled
area/postgres. The harness lives in a new repository, tamnd/rucc-postgres, and every compiler change still lands here.That is about 60 engineer-weeks for one person and about 35 for two, since PG5 and PG6 are independent of each other after PG3, and PG7 can start once PG2 gives a server to measure. The Postgres checkboxes above close when PG3 (check-world), PG7 (pgbench) and PG3's cross module test do, and all of it holds for good when PG9 does. RISC-V and the rest of Windows here are not affected.
tamnd commentedon Oct 4, 2026
The Windows part of this is done. W0 through W6 are closed, the last of them released in v0.19.0. x86_64-windows-gnu is tier 2, aarch64-windows-gnu is tier 2, x86_64-windows-msvc links through
lld-link, and i686-windows-gnu is tier 3 with rung 0 passing natively through WoW64 and under Wine. The four Windows items above are ticked with the issues that did each. RISC-V, PostgreSQL and the full CI matrix are still open here.tamnd commentedon Oct 17, 2026
#3712 is merged, and "test on windows x86-64" passes on its PR run. The job had failed on main for days with 8 tests in three places, none of them a compiler bug: two tests compared paths as strings and missed a path joined with a
\on Windows, and six lane checks in wasm_simd_lanes linked a host program on a Windows host that has no sysroot in the test job. The two now compare paths, and the host half of the six is left out on Windows when the test is compiled.