From cc46936784b79d210aca0d04239535c2da02dd74 Mon Sep 17 00:00:00 2001 From: Douglas Whittingham Date: Fri, 21 Aug 2026 12:30:38 -1000 Subject: [PATCH] Key the object cache on the sources that generate the objects DOLLLVM_CACHE_VERSION is a hand-edited string, so the generated-object cache only invalidates when someone remembers to bump it. It does not invalidate when the emitter changes, which is the case that matters: a stale object is a measurement of code that is no longer in the tree. Hash the sources that decide what gets emitted and fold the digest into every job key. The file list is a CONFIGURE_DEPENDS glob rather than an explicit list -- an explicit list has to be maintained, and the backend rewrite renamed most of the files one would have contained. Editing any covered file re-runs configure and changes the digest, which changes every cache key. Verified: touching src/backend/llvm/psq.cpp moved the digest from 0f6d8569 to 880db2ba across the 46 covered files, and 28/28 ctest passes with it applied. Note this branch is cut from main, which does not currently link against the official LLVM 20 Windows package; the digest was verified on a tree that also carries that link fix. --- CMakeLists.txt | 24 ++++++++++++++++++++++++ src/app/pipeline.c | 8 ++++++++ 2 files changed, 32 insertions(+) diff --git a/CMakeLists.txt b/CMakeLists.txt index dbba0e8..10b7aca 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -196,6 +196,30 @@ add_library(dr_app STATIC src/app/pipeline.c ) target_include_directories(dr_app PUBLIC ${DOLRECOMP_SRC}) +# The generated-object cache must invalidate when the code that generates those +# objects changes. A hand-edited version string cannot do that -- it only +# invalidates when somebody remembers to bump it. Hash the sources that decide +# what gets emitted and fold the digest into every cache key. GLOB with +# CONFIGURE_DEPENDS so a newly added emitter file is covered automatically +# rather than needing to be added to a list that can rot. +file(GLOB DOLRECOMP_CODEGEN_SOURCES CONFIGURE_DEPENDS + "${CMAKE_CURRENT_SOURCE_DIR}/src/backend/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/backend/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/backend/llvm/*.cpp" + "${CMAKE_CURRENT_SOURCE_DIR}/src/backend/llvm/*.h" + "${CMAKE_CURRENT_SOURCE_DIR}/src/ir/*.c" + "${CMAKE_CURRENT_SOURCE_DIR}/src/ir/*.h") +list(SORT DOLRECOMP_CODEGEN_SOURCES) +set(DOLRECOMP_CODEGEN_DIGEST "") +foreach(_codegen_source IN LISTS DOLRECOMP_CODEGEN_SOURCES) + file(SHA256 "${_codegen_source}" _codegen_file_hash) + string(APPEND DOLRECOMP_CODEGEN_DIGEST "${_codegen_file_hash}") +endforeach() +string(SHA256 DOLRECOMP_CODEGEN_SOURCE_HASH "${DOLRECOMP_CODEGEN_DIGEST}") +list(LENGTH DOLRECOMP_CODEGEN_SOURCES _codegen_count) +message(STATUS "Codegen source digest: ${DOLRECOMP_CODEGEN_SOURCE_HASH} (${_codegen_count} files)") +target_compile_definitions(dr_app PRIVATE + DOLRECOMP_CODEGEN_SOURCE_HASH="${DOLRECOMP_CODEGEN_SOURCE_HASH}") target_link_libraries(dr_app PUBLIC dr_backend dr_analysis dr_frontend dr_platform dr_ir) if(DOLRECOMP_ENABLE_LLVM) target_link_libraries(dr_app PUBLIC dr_llvm) diff --git a/src/app/pipeline.c b/src/app/pipeline.c index 3306611..945ebb8 100644 --- a/src/app/pipeline.c +++ b/src/app/pipeline.c @@ -250,6 +250,14 @@ static u64 hash_file_contents(u64 hash, const char* path) { static u64 llvm_job_hash(const LLVMChunkJob* job) { u64 hash = 1469598103934665603ull; hash = hash_bytes(hash, DOLLLVM_CACHE_VERSION, strlen(DOLLLVM_CACHE_VERSION)); +#ifdef DOLRECOMP_CODEGEN_SOURCE_HASH + /* A hand-edited version string cannot invalidate the cache when the code + that generates the objects changes -- it only invalidates when somebody + remembers to bump it. CMake hashes the emitter sources and passes the + digest in, so editing any of them changes every job key automatically. */ + hash = hash_bytes(hash, DOLRECOMP_CODEGEN_SOURCE_HASH, + strlen(DOLRECOMP_CODEGEN_SOURCE_HASH)); +#endif hash = hash_bytes(hash, &job->function_address, sizeof(job->function_address)); hash = hash_bytes(hash, &job->count, sizeof(job->count)); u32 state_size = (u32)sizeof(CPUState);