Uh oh!
There was an error while loading. Please reload this page.
refactor: prefix every remaining public macro with FF_ - #91
Conversation
THE RULE
Every macro that survives preprocessing of a header under include/ -- every
#define not #undef'd before the end of the header that defined it -- must be
spelled FF_*. Installing a header means every translation unit downstream of
it inherits its macros; an unprefixed one is a name this project has silently
taken from everybody who includes us. 184 macros here already followed the
convention. This is the remaining 31, minus the exemptions below.
Macros defined and consumed inside a single .cpp are NOT covered -- they never
leave the translation unit. That is why the dispatch pyramid's local
NDIM_SWITCH / BOUND_SWITCH / MV_ARGS / *_DT / BND1..3 are untouched here:
they are TU-private, and their design is a separate change in other hands.
WHAT CHANGED
FF -> FF_NS (see below)
CUGLOB/CUHOST/CUDEV/CUHOSTDEV -> FF_* core/cuda_switch.h
DISPATCH_PP -> FF_DISPATCH_PP api/{cpu,cuda}/pushpull_dispatch.h
PP_{BOUND,DTYPE,ORDER} -> FF_PP_* (renamed, not redesigned)
ATOMIC_INTEGER_IMPL -> FF_ATOMIC_INTEGER_IMPL
GPU_ATOMIC_INTEGER -> FF_GPU_ATOMIC_INTEGER
INTERPOL_UTILS -> FF_INTERPOL_UTILS
DIST_USE_LOOP -> FF_DIST_USE_LOOP
JFH_OnePlusTiny -> FF_ONE_PLUS_TINY, and de-duplicated: it was #defined
identically in three sibling posdef headers; only
posdef/utils.h keeps it, the other two include it.
uchar_t -> deleted, expanded to `unsigned char` at its six uses.
A lowercase macro impersonating a typedef is worse
than a shouty one: a downstream
`typedef unsigned char uchar_t;` does not merely
collide, it fails with a diagnostic pointing at the
wrong file.
DISPATCH_PP becomes FF_DISPATCH_PP rather than FF_PP_DISPATCH because
impl/cuda/pushpull.h already uses the latter spelling. It #undef's it, so
there is no real collision -- but reusing the name would be needlessly
confusing to read.
WHY FF ITSELF WAS RENAMED
It is a two-letter, all-caps macro in an installed header: the worst offender
on the list, and an entirely plausible downstream identifier. 253 use sites
across 105 files, of which 228 are FF_NAMESPACE_BEGIN(FF)/END(FF).
`#undef FF` at the end of core/defines.h was considered and is not an
alternative -- it is actively wrong. FF is used by ~105 *other* files after
they include defines.h, so undefining it there would turn every
FF_NAMESPACE_BEGIN(FF) into a namespace literally named `FF` rather than into
a compile error. Silently the wrong namespace is worse than the status quo.
Keeping it with a comment was the other option. Rejected: the macro is exactly
the hazard this pass exists to remove, and unlike most renames this one is
verified by the compiler -- a missed site is an undeclared identifier, never a
silent behaviour change. The indirection itself is kept deliberately (headers
must not hard-code `ff::`), so the macro is renamed rather than removed.
DELIBERATELY NOT TOUCHED
core/cuda_switch.h keeps two families unprefixed, because prefixing them would
destroy the thing they exist to do:
* #define int8_t ... uint64_t, under #ifdef __CUDACC_RTC__. NVRTC ships no
standard library, so these hand definitions ARE <cstdint> in that mode.
* #define __device__ / __host__, under #ifndef __CUDACC__ and each behind
its own #ifndef. These erase nvcc's qualifiers for a host compiler;
renaming them would leave the real names undefined.
core/dlpack.h is vendored upstream code (DLPACK_*) and is never rewritten.
The rewrite is tools/rename-macros.py, committed and idempotent. It ends by
re-scanning include/ and failing if any unprefixed, non-exempt macro remains,
so `--check` doubles as a lint. If this needs rebasing, do not resolve
conflicts by hand: reset, re-run the script on the new base, commit that.The comment explaining why the root-namespace macro was renamed spelled the old two-letter name literally, which made tools/rename-macros.py non-idempotent against this one file: a second run rewrote the prose. Restate it using only the post-rename spelling, so `--check` is clean and the script's idempotency claim holds. Also expands the reasoning slightly -- the #undef trap is the part worth not rediscovering.
balbasty
commented
Aug 19, 2026
Two deliberate non-changes, flagged so a reviewer who greps does not read them as misses: 1. That is a verbatim quotation of the title of The script only walks 2. Generated by Claude Code |
balbasty
commented
Aug 19, 2026
Gate: unmoved
Tail of the CPU job, verbatim: Same 13 suites, same 59 886 checks / 0 failures as Why a rename this wide is safe to review quicklyEvery one of these is compiler-verified. There is no spelling of this The one place that reasoning does not apply is Merge orderThis touches The script is deterministic and idempotent — Generated by Claude Code |
balbasty
commented
Aug 19, 2026
Local clean-worktree run finished: And the result that matters most for a rename this wide — the per-suite output Same 13 suites, same 59 886 checks, same zero failures, in the same order. A
Generated by Claude Code |
distance_mesh.h conflicted with the sdt_naive launcher and vertex-normal fix from #86. Resolved by taking main's version wholesale and re-running tools/rename-macros.py over the tree rather than hand-editing: the script is idempotent and self-verifying, so its clean --check ('0 file(s) would change', include/ clean) is the evidence the rename is complete on the new base.
Uh oh!
There was an error while loading. Please reload this page.
Brings in #87, #90, #91 and #95. One conflict, in include/fastfields/impl/kernels/parallel.h: #91 renamed FF_NAMESPACE_BEGIN(FF) to FF_NAMESPACE_BEGIN(FF_NS) on the line this branch inserts the FF_GRAIN_SIZE block above. Resolved by keeping both -- the new block, then main's FF_NS spelling. Everything else auto-merged. #91's renames do not touch anything this branch depends on: has_atomic_add / anyAtomicAdd keep their names, FF_NS still expands to ff, and the CUDEV -> FF_CUDEV rename is confined to the CUDA half of atomic.h. FF_GRAIN_SIZE, the one macro this branch adds to an installed header, already satisfies #91's FF_-prefix rule -- `tools/rename-macros.py --check` reports "0 file(s) would change" and "include/ is clean". Re-verified on the merge result: * tools/test-baseline.sh --legs default,lib -> byte-identical to tools/test-baseline.expected. 13 suites, 59,886 checks, 0 failures. * -DFF_GRAIN_SIZE=1 -> 59,886 / 13 / 0. * -DFF_GRAIN_SIZE=1 + TSan, FF_NUM_THREADS=4, halt_on_error=1 -> 59,886 / 13 / 0, zero reports. * clone syscalls: 0 across all 13 binaries at the shipping grain size, 2 per binary at FF_GRAIN_SIZE=1. The threshold is unchanged by the merge (0 clones at n=32768, 2 at n=32769, on main and on this branch alike). * The thread-pool defects still reproduce on main at f63c7d8: the data race is deterministic under TSan (threadpool.h:148 write / :164 read) and the lost-wakeup deadlock is stochastic (8/320 trials over FF_NUM_THREADS 8/16/32/64). Both are gone on this branch: 0/320 hangs, 0 TSan reports.
Four conventions landed after this branch was cut; the new files predate all of them. * #pragma once on line 1, and the whole-file `#ifndef FF_HALF` guard removed (#145). The file had acquired BOTH, which is the one combination the convention rules out -- core/dlpack.h is the sole guard exception and it is vendored, so its upstream macro can collapse with a system DLPack header's. * FF_NAMESPACE_BEGIN/END(FF_NS), not (FF): #91 renamed the root-namespace macro, because a bare two-letter all-caps name in an installed header takes that identifier away from every downstream translation unit. * FF_CUHOSTDEV, not the unprefixed CUHOSTDEV, for the same reason (#91). * <fastfields/...> for the public interface, here and in the three test and probe files that include it (#146). Applied with tools/normalise-header-guards.py, normalise-include-delimiters.py and rename-macros.py; all three now pass --check, as does check-cuda-launches.py. The continuation backslashes in the two clang-format-off macro blocks are re-aligned to the new column so the blocks stay readable. No behaviour change: FF_CUHOSTDEV and CUHOSTDEV expand identically, and the namespace is `ff` either way.
PR 2 of 2. Stacked on #90 — review and merge that first. (Base is
refactor/dedup-shared-macros; it will retarget tomainautomatically when#90 lands.)
#90 de-duplicated the copy-pasted dispatch helpers and prefixed the ones it
moved. This finishes the job on the rest of the installed surface.
The rule
Installing a header means every translation unit downstream inherits its
macros; an unprefixed one is a name this project has silently taken from
everybody who includes us. 184 macros here already followed the convention
— it existed, it just was not applied. This is the remaining 31, minus the
exemptions.
Macros defined and consumed inside a single
.cppare not covered — theynever leave the translation unit. That is why the dispatch pyramid's local
NDIM_SWITCH/BOUND_SWITCH/MV_ARGS/KN_ARGS/DG_ARGS/*_DT/BND1..3are untouched: they are TU-private, and their design is a separatechange in other hands.
What changed
FFFF_NScore/defines.h— see belowCUGLOBCUHOSTCUDEVCUHOSTDEVFF_CUGLOB…core/cuda_switch.hDISPATCH_PPFF_DISPATCH_PPapi/{cpu,cuda}/pushpull_dispatch.hPP_BOUNDPP_DTYPEPP_ORDERFF_PP_*ATOMIC_INTEGER_IMPL,GPU_ATOMIC_INTEGERFF_*impl/kernels/atomic.hINTERPOL_UTILSFF_INTERPOL_UTILSimpl/kernels/spline.hDIST_USE_LOOPFF_DIST_USE_LOOPimpl/kernels/distance/mesh.hJFH_OnePlusTinyFF_ONE_PLUS_TINY#defined identically in three siblingposdef/headers; onlyposdef/utils.hkeeps it, the other two already include ituchar_tunsigned charat its six usesuchar_tis deleted rather than renamed. A lowercase macro impersonating atypedef is worse than a shouty one: a downstream
typedef unsigned char uchar_t;does not merely collide, it fails to compilewith a diagnostic pointing at the wrong file.
DISPATCH_PP→FF_DISPATCH_PP, notFF_PP_DISPATCH, becauseimpl/cuda/pushpull.halready uses that second spelling. It#undefs it sothere is no real collision — but reusing the name would be needlessly confusing
to read.
FFitself — the verdict, and the reasoningRenamed to
FF_NS. 253 use sites across 105 files, 228 of which areFF_NAMESPACE_BEGIN(FF)/FF_NAMESPACE_END(FF).#undef FFat the end ofcore/defines.hwas considered and is not analternative — it is actively wrong.
FFis consumed by ~105 other filesafter they include
defines.h. Undefining it at the bottom of the definingheader would make every
FF_NAMESPACE_BEGIN(FF)expand to a namespaceliterally named
FF— not a compile error, just silently the wrongnamespace in every file. That is strictly worse than the status quo. The
#undefidiom only works for a macro used within the header that defines it,which is not this one.
Keeping it with a documented rationale was the real alternative. Rejected,
on three grounds:
header — and
FFis an entirely plausible downstream identifier (an enummember, a constant, a template parameter). "Anything on the installed public
surface must be prefixed" does not get an exception for the macro that most
needs it.
is an undeclared identifier, never a silent behaviour change. The blast
radius is large but the risk is not.
and if the base moves the fix is to re-run it rather than resolve conflicts.
The indirection is kept deliberately — headers must not hard-code
ff::—so the macro is renamed, not removed.
core/defines.hnow carries thereasoning inline, including the
#undeftrap, so the next person does not haveto rediscover it.
Deliberately not touched
core/cuda_switch.hkeeps two families unprefixed, because prefixing themwould destroy the thing they exist to do:
#define int8_t … uint64_tunder#ifdef __CUDACC_RTC__. NVRTC ships nostandard library, so these hand definitions are
<cstdint>in that modeand must keep the standard spellings.
#define __device__/#define __host__under#ifndef __CUDACC__. Theseerase nvcc's qualifiers for a host compiler; renaming them would leave the
real names undefined. Correctly guarded — inside
#ifndef __CUDACC__,and each behind its own
#ifndefso a pre-existing definition wins.core/dlpack.his vendored upstream (DLPACK_*) and is never rewritten.Reviewing this
It is one script. Re-derive rather than read:
tools/rename-macros.py --checkdoubles as a lint: it re-scansinclude/afterwards and exits non-zero if any unprefixed, non-exempt macro remains. It
currently reports:
If this needs rebasing (it touches
impl/cuda/widely, so it will conflictwith #86 and #87): do not resolve conflicts by hand. Reset, re-run the script
on the new base, commit that. It is deterministic — that is why it is committed
rather than described. This PR should land after the in-flight CUDA work.
Validation
make test CXX=clang++— CPU suite, 59,886 checks / 13 suites / 0failures, unchanged. (Results posted below once the clean-worktree run
finishes.)
codespellclean.core/changes trigger the full matrix, whichis what you want for a rename that touches
CUDEV/CUHOSTDEVin 1,500places.
clang-formatwill report emptily — see the note in refactor: de-duplicate the dispatch helpers into shared headers #90; that job is brokenindependently of this work and is
continue-on-error.Generated by Claude Code