)]}'
{
  "log": [
    {
      "commit": "9f7c14708775063e109c262e1fa94f1ea5b869a0",
      "tree": "0c197793cc84959381e5ab8a5495a7901bf05e00",
      "parents": [
        "292a72e941876bfe9f98412a0b0770fc22717346"
      ],
      "author": {
        "name": "Leon Aschenbrenner",
        "email": "62488245+Antipath1@users.noreply.github.com",
        "time": "Mon Oct 26 10:58:43 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 26 10:58:43 2026 +0100"
      },
      "message": "Add derivtive for math.clampf (#3488)\n\nCo-authored-by: Paul Berg \u003cnaydex.mc+github@gmail.com\u003e"
    },
    {
      "commit": "292a72e941876bfe9f98412a0b0770fc22717346",
      "tree": "65627e6e58fee61666533e925453a91a924a4cc7",
      "parents": [
        "0d8dd7332d8a78a180c1d873d885e5edd30c6ae8"
      ],
      "author": {
        "name": "Zelenev Nikolay",
        "email": "zelenev.kolya.177@gmail.com",
        "time": "Sun Oct 25 12:21:17 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 25 09:21:17 2026 -0700"
      },
      "message": "Pin cmakefmt to 2.3.0 and update formatting (#3521)"
    },
    {
      "commit": "0d8dd7332d8a78a180c1d873d885e5edd30c6ae8",
      "tree": "9b5e7a9a0fc1d4b532ddfc8ba093a1b0291e75e9",
      "parents": [
        "0b31beb7815f3a19ce4c0ffd0c0bf3ec0cf87b74"
      ],
      "author": {
        "name": "Paul Berg",
        "email": "naydex.mc+github@gmail.com",
        "time": "Thu Oct 22 21:23:31 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 22 14:23:31 2026 -0500"
      },
      "message": "[MLIR] Run reverse interface hooks for non readonly ops (#3518)\n\n* [MLIR] A store of an inactive value to active memory is active\n\n* A non-readonly op is potentially not fully inactive"
    },
    {
      "commit": "0b31beb7815f3a19ce4c0ffd0c0bf3ec0cf87b74",
      "tree": "5151105557489a77b800c4393d2a2c8b0006640b",
      "parents": [
        "e9a0adaeded722850af1d6a2840bb61a614d3cb9"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Wed Oct 21 19:33:03 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 21 19:33:03 2026 +0200"
      },
      "message": "Keep flang runtime calls on inactive descriptors as they are (#3332)\n\n* Keep flang runtime calls on inactive descriptors as they are\n\nA statement such as ALLOCATE(active(n), inactive(n)) reaches the replay\nrule for the inactive descriptor too, with nothing to replay: keep the\nprimal call instead of reporting a missing derivative.\n\nAlso know flang\u0027s DateAndTime, CpuTime, SystemClock,\nGetCommandArgument and GetEnvVariable to be inactive.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01M5d6m8eQfhUdHDMXaDuYq6\n\n* Leave flang\u0027s time and environment queries to #3333\n\n#3333 makes them inactive with their actual names\n(_FortranASystemClockCount etc.; there is no _FortranASystemClock) and\nwith the attributes reverse mode needs. This PR keeps the\ninactive-descriptor case of the replay rule only.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01M5d6m8eQfhUdHDMXaDuYq6\n\n---------\n\nCo-authored-by: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "e9a0adaeded722850af1d6a2840bb61a614d3cb9",
      "tree": "2052a31d8591c771183ccf7856c111c321479834",
      "parents": [
        "fa98c5729c8b63255d8ea2581d2e68cac9020634"
      ],
      "author": {
        "name": "Paul Berg",
        "email": "naydex.mc+github@gmail.com",
        "time": "Wed Oct 21 15:47:31 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 21 15:47:31 2026 +0200"
      },
      "message": "[MLIR] Remove walk from root on every inserted op during op removal (#3508)"
    },
    {
      "commit": "fa98c5729c8b63255d8ea2581d2e68cac9020634",
      "tree": "62fd31b042f46a1b8cc0237685e878876c68e527",
      "parents": [
        "8c56d2c89e6e13092a3a9312acc640bbf19943b0"
      ],
      "author": {
        "name": "copybara-service[bot]",
        "email": "56741989+copybara-service[bot]@users.noreply.github.com",
        "time": "Wed Oct 21 08:15:24 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 21 08:15:24 2026 -0500"
      },
      "message": "Pass a null LibraryOptionsContext to getLicmMssa*Cap with LLVM 24 (#3512)\n\nLLVM 372a4c35991023298bbb35d3371f9010656fa176 made the LICM accessors take a\nconst cl::LibraryOptionsContext*; nullptr returns the global option value.\n\nAlso pins the MLIR CI\u0027s llvm/llvm-project checkout to f9cea2f24b6713cc344a875e674d45728c19d24e, the LLVM commit google3 is on (was 1ee8805f01a663b7f2b09215a8eab5ab2d15ce35).\n\nGoogle-Internal-CL: 1003331757\n\nCo-authored-by: Copybara \u003cno-reply@google.com\u003e\nCo-authored-by: William Moses \u003cgh@wsmoses.com\u003e"
    },
    {
      "commit": "8c56d2c89e6e13092a3a9312acc640bbf19943b0",
      "tree": "8ef1e49161d186612897d9273aca83b36d3b2927",
      "parents": [
        "14e4d4182d8363be1cc6e0e0bb6c0ee022c2287b"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Wed Oct 21 11:30:59 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 21 11:30:59 2026 +0200"
      },
      "message": "Forward mode for LLVM flang runtime functions on descriptors (#3331)\n\n* Forward mode for LLVM flang runtime functions on descriptors\n\nMost flang runtime calls that take descriptors change the structure of\nFortran objects rather than compute with their values: allocation and\ndeallocation, bounds, pointer association, initialization, copies. Their\nforward-mode derivative is the same call on the shadow descriptors,\nfollowing _FortranAAssign (#3192). FlangRuntime.h lists them with the\npositions of their descriptor arguments; all other arguments (bounds,\ntype info, stat, errmsg, source location, molds) are passed unchanged.\n\nMemory that AllocatableAllocate or PointerAllocate allocates is zeroed\nin the shadow (Size x elem_len bytes) and then re-initialized with\n_FortranAInitialize, which restores the component descriptors of derived\ntypes and does nothing for intrinsic types.\n\nType analysis gives the descriptor arguments of these calls the\ndescriptor type tree of #3192. Flang I/O (_FortranAio*), inquiries\n(Size, SizeDim, IsContiguous, PointerIsAssociated, ...), character\noperations (Trim, Index, Adjustl, ...) and termination are known to be\ninactive.\n\nWith these rules, differentiating a Fortran constructor that allocates\nderived types through the runtime builds the shadow of the constructed\nstate: separate, zeroed memory, with every pointer in the shadow\nstructure mirroring the primal one.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01M5d6m8eQfhUdHDMXaDuYq6\n\n* flangallocate.ll: give the shadow by metadata, not by a table\n\nThe test does not depend on __enzyme_shadow_global tables (#3330):\n!enzyme_shadow on the module variable is enough.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01M5d6m8eQfhUdHDMXaDuYq6\n\n* Apply clang-format to the flang runtime forward-mode rules\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01Sv7b5f8VG9JkZikqGQzFbx\n\n* Use getInt8PtrTy for the flang runtime descriptor pointers\n\nPointerType::getUnqual(LLVMContext\u0026) is not available on every supported\nLLVM; use the Utils.h wrapper (check_llvm_api.py).\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01Sv7b5f8VG9JkZikqGQzFbx\n\n---------\n\nCo-authored-by: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "14e4d4182d8363be1cc6e0e0bb6c0ee022c2287b",
      "tree": "8ffb97c4c01d4417df759a9f242454e74860c038",
      "parents": [
        "e1ed6425d5f87cd794268c193de59e2e6de88c18"
      ],
      "author": {
        "name": "copybara-service[bot]",
        "email": "56741989+copybara-service[bot]@users.noreply.github.com",
        "time": "Tue Oct 20 22:28:51 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 20 22:28:51 2026 -0500"
      },
      "message": "Adapt to LLVM BasicBlock::getFirstNonPHIOrDbg* rename (#3513)\n\n* Adapt to LLVM BasicBlock::getFirstNonPHIOrDbg* rename\n\nLLVM 06d62fc244617b7b3e70c93ec9b28a40c1280261 renamed getFirstNonPHIOrDbg to\ngetFirstNonPHIOrPseudoProbe and getFirstNonPHIOrDbgOrLifetime to\ngetFirstNonPHIOrLifetime.\n\nAlso pins the MLIR CI\u0027s llvm/llvm-project checkout to f9cea2f24b6713cc344a875e674d45728c19d24e, the LLVM commit google3 is on (was 1ee8805f01a663b7f2b09215a8eab5ab2d15ce35).\n\nGoogle-Internal-CL: 1003331811\n\n* Update enzyme-mlir.yml\n\n---------\n\nCo-authored-by: Copybara \u003cno-reply@google.com\u003e\nCo-authored-by: William Moses \u003cgh@wsmoses.com\u003e"
    },
    {
      "commit": "e1ed6425d5f87cd794268c193de59e2e6de88c18",
      "tree": "4f2fb0932e4f2319e1a2b21d747f4cb234a89319",
      "parents": [
        "cf3b4149ea58f4a060db3c772efc31bf15dead7a"
      ],
      "author": {
        "name": "Quoc Truong",
        "email": "quoct@google.com",
        "time": "Tue Oct 20 13:44:05 2026 -0700"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 20 15:44:05 2026 -0500"
      },
      "message": "Replace linux-x86-n2-32 runner label with linux-x86-n4-32 (#3511)\n\n* Replace linux-x86-n2-32 runner label with linux-x86-n4-32\n\n* ci: remove single quotes from working-directory in enzyme-mlir.yml\n\n* ci: cap LLVM_PARALLEL_COMPILE_JOBS\u003d16 in enzyme-mlir.yml"
    },
    {
      "commit": "cf3b4149ea58f4a060db3c772efc31bf15dead7a",
      "tree": "27a5dc6abb7a68f66557ab44cd70091f86a0bd0d",
      "parents": [
        "befd01ad046cae3949aee3b6618cffb86e082536"
      ],
      "author": {
        "name": "copybara-service[bot]",
        "email": "56741989+copybara-service[bot]@users.noreply.github.com",
        "time": "Tue Oct 20 09:30:51 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 20 09:30:51 2026 -0500"
      },
      "message": "[Enzyme] Fix build after LLVM integrate: `ListInit::getValues()` was removed (#3510)\n\nUpstream LLVM removed `llvm::ListInit::getValues()` (replaced by\n`getElements()`), breaking `enzyme-tblgen` and hence every Enzyme target in\ngoogle3.\n\nSwitch the call sites to `ListInit::size()`, `ListInit::getElement(i)` and\nrange-for iteration, which exist on all LLVM versions Enzyme supports, so no\n`LLVM_VERSION_MAJOR` guard is needed.\n\nGoogle-Internal-CL: 1003064513\n\nCo-authored-by: Billy Moses \u003cwmoses@google.com\u003e"
    },
    {
      "commit": "befd01ad046cae3949aee3b6618cffb86e082536",
      "tree": "877619ac59b75780382ad1c9e10b6190f02f8d58",
      "parents": [
        "d7bbabf8209409e2841b0fb8f1450f34d43ed426"
      ],
      "author": {
        "name": "Paul Berg",
        "email": "naydex.mc+github@gmail.com",
        "time": "Tue Oct 20 15:13:09 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 20 08:13:09 2026 -0500"
      },
      "message": "ActivityAnalyzer: use a DenseSet for the visited uses of isValueInactiveFromUsers (#3509)\n\nThe visited set of (op, parent, UseActivity) tuples was a std::set, which\nallocates a node per insert and dominates the profile of large reverse-mode\nmodules. A DenseSet takes --enzyme on a large raised module from 595s to 262s\nwith identical output.\n\n\nClaude-Session: https://claude.ai/code/session_01Nzfc3FNrrSoMGHN4oHZvty\n\nCo-authored-by: Claude Sonnet 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "d7bbabf8209409e2841b0fb8f1450f34d43ed426",
      "tree": "15dbb390eb878a4e289615c366ebe9bb2fb62a0a",
      "parents": [
        "0a8be29f271b1b572511425b3ab7cba11f5e8589"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Mon Oct 19 20:45:20 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 19 13:45:20 2026 -0500"
      },
      "message": "Build Enzyme_jll for LLVM 23 (#3502)\n\nJulia master (1.14-DEV) moved to LLVM 23.1.4; build for it instead of\n22.1.8, which no Julia release uses. Also drop the dead LLVM 11 special case.\n\nAssisted-by: Claude Code (Opus 5.5)"
    },
    {
      "commit": "0a8be29f271b1b572511425b3ab7cba11f5e8589",
      "tree": "9fa4dba90799acaa912b2b3f552ae7f402e8e8b2",
      "parents": [
        "8ca3b76f39e98274f1d80e36dcb4438051a9ab41"
      ],
      "author": {
        "name": "copybara-service[bot]",
        "email": "56741989+copybara-service[bot]@users.noreply.github.com",
        "time": "Fri Oct 16 20:17:37 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 16 20:17:37 2026 +0000"
      },
      "message": "Allowlist libc++ basic_string::__assign_c_str in EnzymeLogic for upcoming Crosstool release (#3495)\n\nAlso pins the MLIR CI\u0027s llvm/llvm-project checkout to 1ee8805f01a663b7f2b09215a8eab5ab2d15ce35, the LLVM commit google3 is on (was 2e0d9e12b36e853d9b108c4da09509cd54d1f3f9).\n\nGoogle-Internal-CL: 1001010670\n\nCo-authored-by: Copybara \u003cno-reply@google.com\u003e"
    },
    {
      "commit": "8ca3b76f39e98274f1d80e36dcb4438051a9ab41",
      "tree": "9f7eb36a92d84eddb70215c9a5061154cb9f4520",
      "parents": [
        "2c8fd12d5ccc2f4f26a171f6a79ac170bc986ce4"
      ],
      "author": {
        "name": "Leon Aschenbrenner",
        "email": "62488245+Antipath1@users.noreply.github.com",
        "time": "Wed Oct 14 03:10:37 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 14 03:10:37 2026 +0000"
      },
      "message": "Add derivative for math::FPowIOp (#3487)"
    },
    {
      "commit": "2c8fd12d5ccc2f4f26a171f6a79ac170bc986ce4",
      "tree": "b583fb4490e958a0b2b9c721ff1b29deb79911c2",
      "parents": [
        "6fbd5c11e308abe9ff5e1dea45b91a388ccf0288"
      ],
      "author": {
        "name": "copybara-service[bot]",
        "email": "56741989+copybara-service[bot]@users.noreply.github.com",
        "time": "Mon Oct 12 20:33:07 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 20:33:07 2026 -0500"
      },
      "message": "Use LICM accessor functions with LLVM 24 (#3482)\n\n* Use LICM accessor functions with LLVM 24\n\nLLVM replaced the exported `llvm::SetLicmMssaOptCap` and `llvm::SetLicmMssaNoAccForPromotionCap` `cl::opt` globals with `llvm::getLicmMssaOptCap()` and `llvm::getLicmMssaNoAccForPromotionCap()`. Use the accessors when `LLVM_VERSION_MAJOR \u003e\u003d 24`.\n\nAlso pins the MLIR CI\u0027s llvm/llvm-project checkout to 2e0d9e12b36e853d9b108c4da09509cd54d1f3f9, the LLVM commit google3 is on (was 018a9e4a74ba5d383351bda907a8b116bc5d8c47).\n\nGoogle-Internal-CL: 998226217\n\n* Build the MLIR CI against the LLVM commit google3 is on\n\nThe LICM accessors this PR switches to exist only from LLVM e61035ac27ca\n(2026-10-09), but the MLIR CI was pinned to 62e30e3326d9 (2026-10-02),\nwhich is already LLVM 24 and still has the old cl::opt globals. Move the\npin to 2e0d9e12b36e, as the PR description says.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n---------\n\nCo-authored-by: Billy Moses \u003cwmoses@google.com\u003e\nCo-authored-by: William Moses \u003cgh@wsmoses.com\u003e\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "6fbd5c11e308abe9ff5e1dea45b91a388ccf0288",
      "tree": "df753e8cd6ab20db93dc82bf678352c4f65e6285",
      "parents": [
        "bc02e1ccdcea3d4ce9b14e448644655cac5c462b"
      ],
      "author": {
        "name": "Leon Aschenbrenner",
        "email": "62488245+Antipath1@users.noreply.github.com",
        "time": "Tue Oct 13 03:02:39 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 21:02:39 2026 -0400"
      },
      "message": "Mark RoundOp, RoundEvenOp, TruncOp inactive (#3483)"
    },
    {
      "commit": "bc02e1ccdcea3d4ce9b14e448644655cac5c462b",
      "tree": "0908ab29bdfa42db455d8a032fbfc054e7eabc6b",
      "parents": [
        "4d1ab28d8e18e1fcec18ee828a6896a44201fc36"
      ],
      "author": {
        "name": "Leon Aschenbrenner",
        "email": "62488245+Antipath1@users.noreply.github.com",
        "time": "Tue Oct 13 03:02:09 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 12 21:02:09 2026 -0400"
      },
      "message": "[MLIR] Add atan2 derivative (#3476)\n\n* Add atan2 derivative\n\n* convention stuff whatever"
    },
    {
      "commit": "4d1ab28d8e18e1fcec18ee828a6896a44201fc36",
      "tree": "e3f67c45fa8f50370449d840caed4505518e2d6a",
      "parents": [
        "25d27195c099f3ab5a9e3d2bb99bd29ddb2aa1fe"
      ],
      "author": {
        "name": "Leon Aschenbrenner",
        "email": "62488245+Antipath1@users.noreply.github.com",
        "time": "Mon Oct 12 04:52:38 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 22:52:38 2026 -0400"
      },
      "message": "[MLIR] Add derivative rules for math ops: trig, hyperbolic, exp/log, erf (#3396)\n\n* Add diff rules for hyperbolic functions in math mlir\n\n* Add derivative rules for math.tan\n\n* Add derivative for math.asin and math.acos\n\n* Add derivative for math.asinh acosh and atanh\n\n* Add derivative for math.expm1\n\n* Add derivative for math.log10\n\n* Add derivative for math.rsqrt and cbrt\n\n* Add derivative for math.erf and erfc\n\n* Fmt\n\n---------\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "25d27195c099f3ab5a9e3d2bb99bd29ddb2aa1fe",
      "tree": "f7a5691097fb4bc993af846d762a01ac0dc77f75",
      "parents": [
        "889b7f4f2c8c229409dec878120ea877b33dedf3"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Sun Oct 11 21:43:30 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 21:43:30 2026 -0400"
      },
      "message": "Fold a memref.cast into enzyme.atomic_rmw and enzyme.affine_atomic_rmw (#3475)\n\nA memref.cast that only makes a memref\u0027s sizes dynamic folds into\nmemref and affine loads and stores; the enzyme atomics had no folder,\nso an accumulation into a scratch through such a cast kept it:\n\n  %cast \u003d memref.cast %s : memref\u003c72xf64, 3\u003e to memref\u003c?xf64, 3\u003e\n  %r \u003d enzyme.affine_atomic_rmw addf %v, %cast, (#map) [] ... -\u003e f64\n\nwhich Enzyme-JAX\u0027s raising then had to follow by hand. Fold it with\nmemref::foldMemRefCast, as the loads and stores do.\n\n\nClaude-Session: https://claude.ai/code/session_016zErYp7upmqr4NHfhod9UD\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "889b7f4f2c8c229409dec878120ea877b33dedf3",
      "tree": "e0565181e2329899f0adfc6b08dda39867b66915",
      "parents": [
        "06da3b77d8ceaa9e260c7147a2e6bedf27b6d377"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Sun Oct 11 18:26:56 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 18:26:56 2026 -0400"
      },
      "message": "Build sumMIT against a pinned pyre commit (#3474)"
    },
    {
      "commit": "06da3b77d8ceaa9e260c7147a2e6bedf27b6d377",
      "tree": "a88c9cb8bd4871f3434702ca981ef249a84a1962",
      "parents": [
        "1cdd148b3c1942f7a76663c96e5551097d9142a4"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Mon Oct 12 00:12:22 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 18:12:22 2026 -0400"
      },
      "message": "Do not over-align vector accesses in addToInvertedPtrDiffe (#3446)\n\n* Do not over-align vector accesses in addToInvertedPtrDiffe\n\naddToInvertedPtrDiffe combines a range of equally typed fields into one\nvector type (e.g. \u003c4 x double\u003e). Several loads and stores of that vector\ntook its ABI alignment, which can exceed the alignment of the memory:\n\n- Without a caller-provided alignment, the accumulation into the shadow\n  used the vector\u0027s ABI alignment. Enzyme.jl passes no alignment for the\n  cotangent of an Active struct argument of a custom rule, so it stored\n  \u003c4 x double\u003e with align 32 into an 8-aligned alloca, which faults on\n  AVX (EnzymeAD/Enzyme.jl#3775). Default to the element type\u0027s alignment.\n- \"cast.load\" read the vector from an alloca of the differential\u0027s type\n  with the vector\u0027s alignment. Use the alloca\u0027s alignment.\n- \"gep.load\" read the vector from a packed struct at offset `start` with\n  the vector\u0027s alignment. Align the alloca for the stored differential and\n  load with the alignment common to it and the offset.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n* Give gep.alloca the alignment of the original pointer\n\nThe alloca mirrors the memory at the original pointer, so use that\nalignment for it and for the store of the differential into it, instead\nof the ABI alignment of the differential\u0027s type.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_0147v1tzYSVQ8PhXBJ31AinC\n\n* Only align gep.alloca when the original pointer\u0027s alignment is known\n\nAssisted-by: Claude Code (Opus 5.5)\n\n* Keep align as MaybeAlign in addToInvertedPtrDiffe\n\nInstead of defaulting align up front, fall back to the element type\u0027s\nalignment only for the accesses of the shadow that would otherwise take\nthe vector type\u0027s ABI alignment.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n* Set the gep.alloca store\u0027s alignment after creating it\n\nPer review: create the store as before and only set its alignment (and\nthe alloca\u0027s) when the original pointer\u0027s alignment is known.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n* Create the loads plainly and set their alignment afterwards\n\nPer review: use CreateLoad and set the alignment on the result, drop the\nelement-type alignment fallback when no alignment is known, and drop the\ncomments.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n---------\n\nCo-authored-by: Claude \u003cnoreply@anthropic.com\u003e\nCo-authored-by: William S. Moses \u003cgh@wsmoses.com\u003e"
    },
    {
      "commit": "1cdd148b3c1942f7a76663c96e5551097d9142a4",
      "tree": "e449f020d95b359a058ecbbd8b5ef90979244185",
      "parents": [
        "2dc81ee3dcb062f0d303dbe04c5b6c63ecd3a52d"
      ],
      "author": {
        "name": "Leon Aschenbrenner",
        "email": "62488245+Antipath1@users.noreply.github.com",
        "time": "Sun Oct 11 21:38:25 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 15:38:25 2026 -0400"
      },
      "message": "[MLIR] Add mlir tablegen multiresult forword mode support (#3465)\n\n* Add mlir tablegen multiresult forword mode support\n\n* slightly better test\n\n* slightlyier betterer test\n\n* Mark reverse mode inactive and revert forword only code\n\n* Add SelectIfAllResultsActive instead of SelectIfBothResultsActive\n\n* Completely avoid lambda even during tablegen generation"
    },
    {
      "commit": "2dc81ee3dcb062f0d303dbe04c5b6c63ecd3a52d",
      "tree": "fb2afc267e77d4635111b2a00ca68a21d9dabc01",
      "parents": [
        "7e52cfa02a7f628cb248abae562bb55a4e9eb033"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Sun Oct 11 15:37:57 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 15:37:57 2026 -0400"
      },
      "message": "Make callers of local read-only-or-throw callees local when memory can flow back (#3445)\n\n* Make callers of local read-only-or-throw callees local when memory can flow back\n\nA local read-only-or-throw callee may write memory it allocates and hand it\nto its caller through its return value or an sret-like argument. The\ninference only checked where the callee\u0027s sret-like arguments point, so a\ncaller that returned such memory was marked fully read-only-or-throw.\nActivity analysis then treated a call to it returning a pointer as unable to\npropagate derivatives, and the reverse pass passed `nothing` for the shadow\nof its arguments.\n\nSince #3418 a Julia 1.10 function filling a new array is local\nread-only-or-throw, so a function returning `collect(::SVector)` was marked\nfully read-only-or-throw, and the gradient of a closure calling it segfaulted\n(EnzymeAD/Enzyme.jl#3776).\n\nMake the caller local if the call\u0027s return value, or an sret-like argument,\ncan hold a pointer.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n* Treat calls marked local read-only-or-throw by metadata like calls to such functions\n\nA call carrying `enzyme_LocalReadOnlyOrThrow` metadata was skipped by the\nread-only-or-throw inference, so its caller could be marked fully\nread-only-or-throw although the call may hand it memory it wrote. Handle it\nlike a call to a local read-only-or-throw function, accounting for its sret-\nlike arguments and its result.\n\nAlso clarify the documentation of the two attributes: a fully\nread-only-or-throw function never returns memory holding data it wrote,\nwhile a local one may.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n* Decide whether a caller of a local callee is local by whether memory escapes\n\nRather than whether the call\u0027s result or sret type may hold a pointer,\ntreat memory a local read-only-or-throw callee hands back like an allocation\nof ours that was written to: the caller is only local read-only-or-throw if\nthe call\u0027s result, or memory its sret-like arguments point to, may escape it,\ndirectly or through a pointer loaded from it. A caller that only reads that\nmemory stays fully read-only-or-throw.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n* Make a function local only if memory it wrote may reach its return value\n\nA function writing an object it allocated, or memory a local\nread-only-or-throw callee handed it, was made local read-only-or-throw as\nsoon as that memory was captured at all. Only if the memory may reach the\nfunction\u0027s return value does it outlive the call holding data the function\nwrote. Escaping otherwise does not matter: storing it into memory existing\nbefore the call is a write that disqualifies the function anyway, and storing\nit into another allocation is checked when that allocation is written to.\n\nShare one walk, mayReachReturn, for all of these. It follows pointer\narithmetic, phis, selects and aggregates, stores into allocas through what is\nloaded or copied from them, and treats returning a pointer, or passing it to\na call that may capture and hand it back, as reaching the return value.\n\nAlso accept writes through any field of an object allocated uninitialized,\nnot only the data field of a Julia array, if the field only holds fresh data.\nJulia\u0027s runtime allocators initialize their objects\u0027 other fields themselves,\nso only their data field is accepted.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n* Decide whether a value may hold a pointer from its uses and enzyme_type info\n\nIntegers can hold pointers (e.g. Julia\u0027s Ptr, or the result of ptrtoint), so\nthe LLVM type of a value written memory reaches says nothing about whether it\nmay return that memory. Follow the uses whatever their type, and only rule\nout a pointer for void or token values, or when enzyme_type info (on a\ncall\u0027s result, the callee\u0027s return, an instruction\u0027s metadata, or the\nfunction\u0027s own return) says every byte is an integer or a float.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n* Include SmallSet.h in FunctionUtils.cpp\n\nNewer LLVM versions no longer pull it in through other headers.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n* Recheck callers of pending callees; keep calls that move active data active\n\nWhen a function was first checked while some callees were not yet known to\nbe read only or throw, it was later marked using the result of that first\ncheck, which could not tell whether a callee that turned out to be only\nlocal made it local too (by returning memory the callee wrote), or ruled it\nout (by having the callee write through an argument that is not ours). Check\nsuch functions again once all their callees are known.\n\nActivity analysis treated any read-only-or-throw call returning no float as\nan inactive instruction. A read-only-or-throw function may still move active\ndata into memory of its own (e.g. copying an active argument into a\ntemporary), which makes the call active even though no derivative outlives\nit: its reverse pass accumulates into the shadows of its arguments, so it\nmust be passed them rather than undef. Infer enzyme_NoDataWrite for\nread-only-or-throw functions that write no data at all (allocating does not\ncount), and only skip the analysis for read-only-or-throw calls returning a\npointer if the callee writes no data or is an allocation.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n* Keep read-only-or-throw calls inactive; pass differentiated calls their shadows\n\nA fully read-only-or-throw function writes nothing that outlives the call\n(allocating is not a write), so a call to it that returns no float is\ninactive, as before. Drop the exception for initializing returned objects\nfrom the documentation, and revert the activity-analysis change and the\nenzyme_NoDataWrite inference that only fed it.\n\nThe crash it worked around was elsewhere: a constant-instruction call whose\nresult is active is still differentiated, but its reverse call was passed\nundef for its arguments\u0027 shadows, while its augmented call got the real ones.\nA callee whose reverse touches those shadows, for instance to propagate a\ncopy into a temporary of its own, then crashes, although what it adds is\nzero. Pass the reverse call the same shadows as the augmented call.\n\nFor the gradient pass, differential-use analysis now also counts the shadow\nof an argument to such a call as needed in the reverse pass whenever the\ncall\u0027s shadow result is used at all (asked of the primal pass, which decided\nto differentiate the call), so the shadow is kept rather than erased.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* Move the reverse-call shadow fix to its own PR\n\nThe fix for reverse calls of differentiated constant calls being passed\nundef shadows is now #3468. Restore AdjointGenerator.h,\nDifferentialUseAnalysis.h and the affected tests here, and drop\nretptr_writes_local.ll, which #3468 replaces.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* Do not treat floating-point values or arithmetic on them as possible pointers\n\nWhether a value may hold a pointer to written memory was decided only by\nvoid/token types and enzyme_type info, so a double loaded from memory a local\ncallee returned made its caller local when returned, and any arithmetic on it\n(which fell through to the conservative end of the escape walk) did too.\nFloating-point values and integers narrower than a pointer cannot hold one;\nintegers as wide as a pointer still can (ptrtoint, Julia\u0027s Ptr). The walk\nnow follows integer arithmetic on a possible pointer and ignores\ninstructions that neither write memory nor produce a value able to hold one.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* Follow a written pointer stored into memory of the function\n\nWhen a pointer to written memory was stored into memory that is not an\nalloca, the escape walk relied on that memory being checked \"when it is\nwritten to\", but that check only asks whether the memory itself reaches the\nreturn value, not whether a pointer loaded back out of it does. A function\nboxing a written object in another allocation and returning what it loads\nback from the box, directly or through a call returning a field, was marked\nfully read-only-or-throw.\n\nFollow such memory like an alloca: what is loaded from it, deeply, and any\nobject whose fresh data it is. Storing the pointer into an argument or a\nglobal hands it to the caller.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* Check every load of a written fresh field, including nested owners\n\nA write to fresh data only checked whether the written pointer itself, or\nthe objects whose field it was loaded from, reach the return value. Two\ngaps:\n\n* Another load of the same field yields the same written data. Returning\n  it (a Julia `pointer(arr)`) was missed.\n* Fresh data found through a store of other fresh data into an object\u0027s\n  field (e.g. a Memory\u0027s data pointer kept in another fresh object) did not\n  record the objects at the inner level, so returning the Memory itself was\n  missed.\n\nRecord each owning object with the offset of the field holding the fresh\ndata, at every level, and check the object, every load of that field, and\nanything copying the field or handing back what a call loads from the\nobject.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* Only treat fields of allocators that leave them uninitialized as fresh\n\nAny field of any allocation call was accepted as holding only fresh data if\nevery write to it in the function did. But isAllocationCall also covers\nallocators that initialize fields themselves, e.g. swift_allocObject\u0027s\nmetadata pointer, custom enzyme_allocator ones, and allocators registered\nwith a shadow handler, whose fields may point to memory that existed before\nthe call. Writing through such a field was taken as writing fresh data.\n\nAccept fields only of the C and C++ allocators and Julia\u0027s object\nallocators, which leave them uninitialized (or zeroed).\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* Read sret-like markings of the called function when walking through a call\n\nmayHandBackPointer used hasSRetRRootsOrUnionSRet, which reads only call-site\nattributes and only an sret on the first argument, while\nenzymejl_returnRoots and enzymejl_sret_union_bytes usually sit on the\ncalled function. Also check sret on any argument and those markings on the\ncallee.\n\nNo test fails before this: a callee writing a pointer into such an argument\nis either local read-only-or-throw, and the local-callee branch already\nreads the callee\u0027s markings and follows the argument, or it disqualifies\nthe caller. This keeps the escape walk consistent with that branch.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* Cache escape queries per object and skip them while a callee is pending\n\nEach write to the same object reran the full escape walk (and the fresh\ndata check), and a function with a callee not yet known to be read only or\nthrow ran all of them although the result is discarded and the function is\nchecked again once its callees are known.\n\nCache isFreshData, mayReachReturn and the per-field checks per object\nwithin one check of a function, and skip the escape queries, which only\ndecide whether the function is local, once a callee is pending. Whether a\nwrite is allowed at all is still decided.\n\nNo behavior change.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* Do not count julia.gc_loaded rooting a fresh object as handing back its field\n\nThe check that a written fresh field cannot reach the return value treated\nany call receiving the owning object and returning a pointer as possibly\nhanding back what it loads from it. julia.gc_loaded(obj, ptr), which Julia\n1.11+ emits around every access to Memory data, takes obj only to keep it\nalive and returns ptr; a load of the field passed as ptr is checked as a\nload. Counting it made every function writing fresh Memory data local, e.g.\nbc1_affine_normalize in Enzyme.jl\u0027s test/advanced.jl, which writes a\ntemporary it does not return and so is fully read-only-or-throw.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* Spell out the field overlap check so clang-format 16 and 18 agree\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* Skip the escape queries for a function that cannot hand back a pointer\n\nA function whose return value cannot hold a pointer, by its type or\nenzyme_type, and that has no sret-like argument cannot hand memory it wrote\nto its caller other than by a write that rules it out anyway. Decide that\nonce, rather than walking every written object to its return.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* Make the helpers of the read-only-or-throw check members\n\nThe static helpers only the check uses become members of\nReadOnlyOrThrowDetector: those that took a TargetLibraryInfo use the\nclass\u0027s, the pure type and value predicates are static members, and the\ntype aliases they share move into the class. The lambdas caching escape\nqueries become member functions with their caches as members.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* Format cannotHandBackPointer with clang-format 16\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n---------\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "7e52cfa02a7f628cb248abae562bb55a4e9eb033",
      "tree": "8ceaff233d2762b143741935581acd6990a7cff8",
      "parents": [
        "0a6169227ec145358afa7224f7b7b145c39f3eda"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Sun Oct 11 14:42:51 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 14:42:51 2026 -0400"
      },
      "message": "NFC: make the read-only-or-throw check of a function a class (#3473)\n\n* NFC: make the read-only-or-throw check of a function a class\n\nTurn DetectReadonlyOrThrowFn into ReadOnlyOrThrowDetector, holding the\nfunction, its pending callees, the TLI and the local flag as members, so\nthat helpers of the check can be member functions rather than lambdas.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* NFC: make the helpers only the read-only-or-throw check uses members\n\naddReadOnlyOrThrowAttributes, isFreshJuliaMemory, dataFieldOnlyHoldsFreshData,\nisFreshJuliaArray and isFreshJuliaMemoryOrArrayData become members of\nReadOnlyOrThrowDetector, taking the function, TLI and local flag from it.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n---------\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "0a6169227ec145358afa7224f7b7b145c39f3eda",
      "tree": "7b911105fbbea80994239bccff25eb5d170c77cc",
      "parents": [
        "8797fc6ff4275a531b7f489172c70ec6c6cf1435"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Sun Oct 11 14:35:07 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 14:35:07 2026 -0400"
      },
      "message": "MLIR: derivatives of math.tanh and math.cbrt (#3471)\n\nd tanh(x) \u003d 1 - tanh(x)^2 and d cbrt(x) \u003d cbrt(x) / (3x), as the LLVM\nrules for tanh and cbrt compute them. Without them reverse mode stops at\n\"could not compute the adjoint for this operation\" on any function that\ncalls either, e.g. MFEM\u0027s bench_bpl through the Reactant raising path.\n\n\nClaude-Session: https://claude.ai/code/session_016zErYp7upmqr4NHfhod9UD\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "8797fc6ff4275a531b7f489172c70ec6c6cf1435",
      "tree": "3b9f5090c91264de43fc21c220b9ac05e7b21172",
      "parents": [
        "c1905441d7545c90cd05b2d9f02abf89074f8d2f"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Sun Oct 11 13:09:27 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 11 13:09:27 2026 -0400"
      },
      "message": "Re-check a function once the callees it waited on are read only or throw (#3472)\n\nA function whose callees were not yet classified when it was first checked\nwas later marked from that first check alone. That check treated the\ncallees as unknown, so it could not see what a callee that turned out to\nbe only local writes: passing an argument that is not our sret as the\ncallee\u0027s sret writes memory our caller can see, and passing our sret\nthrough makes us local. Such functions were marked fully read-only-or-throw,\nand the pointer written was even inferred readnone. Run the check again\nonce every callee is marked, and let it set the attributes.\n\n\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "c1905441d7545c90cd05b2d9f02abf89074f8d2f",
      "tree": "d90f8b7faf1896cef42d0b7375a86364de6ebdee",
      "parents": [
        "3eb77c40fc8e40e0e6f5a2765f82fb4fafe1a86d"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Sat Oct 10 19:22:54 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 10 14:22:54 2026 -0500"
      },
      "message": "Replace the local read-only-or-throw attribute when upgrading to full (#3469)\n\nEnzyme.jl runs the read-only-or-throw inference several times, and the\ninference only skips functions already marked fully read-only-or-throw. A\nfunction an earlier run marked enzyme_LocalReadOnlyOrThrow (e.g. while it\nstill called a callee that could hand back memory it wrote) is checked again\nand, once it qualifies, also gets enzyme_ReadOnlyOrThrow, leaving both.\nRemove the local attribute when marking a function fully read-only-or-throw.\n\n\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "3eb77c40fc8e40e0e6f5a2765f82fb4fafe1a86d",
      "tree": "530d1dc405ee6f1827e90df6154fca17c3fa29a0",
      "parents": [
        "ad5e418d157eb03094829230c80ddc06fb9198a3"
      ],
      "author": {
        "name": "aokblast",
        "email": "aokblast@FreeBSD.org",
        "time": "Sat Oct 10 06:45:37 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 10 01:45:37 2026 -0500"
      },
      "message": "[MLIR] Multiple return values packing in createTerminator (#3466)\n\n* Multiple return values packing in createTerminator\n\nllvm.return and cir.return doesn\u0027t support multiple return values like\nmlir.return. As a result, any primals in llvm or cir with more than one\nreturn values will fail to create Terminator. Dispatch the create return\nop to createReturn in different implementations.\n\n* fixup! Multiple return values packing in createTerminator"
    },
    {
      "commit": "ad5e418d157eb03094829230c80ddc06fb9198a3",
      "tree": "82467a8d3259e31dd0d049acde29fe0067204725",
      "parents": [
        "25adc42ed8f9d1f570fa876b24b1e52593148127"
      ],
      "author": {
        "name": "copybara-service[bot]",
        "email": "56741989+copybara-service[bot]@users.noreply.github.com",
        "time": "Fri Oct 09 16:51:57 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 09 16:51:57 2026 -0500"
      },
      "message": "Fix Enzyme demangled prefix match for libc++ basic_string::__assign_no_alias (#3457)\n\nAlso pins the MLIR CI\u0027s llvm/llvm-project checkout to 62e30e3326d9b4e3948d242ccfee7aa4fc030ef3, the LLVM commit google3 is on (was 018a9e4a74ba5d383351bda907a8b116bc5d8c47).\n\nGoogle-Internal-CL: cl/995776807\nPiperOrigin-RevId: 995776807\n\nCo-authored-by: Copybara \u003cno-reply@google.com\u003e"
    },
    {
      "commit": "25adc42ed8f9d1f570fa876b24b1e52593148127",
      "tree": "725784c5c90494f14063bd18aa605fafdcf686cb",
      "parents": [
        "e949b437dc6450204871ccd9a84ce7802125d617"
      ],
      "author": {
        "name": "aokblast",
        "email": "aokblast@FreeBSD.org",
        "time": "Fri Oct 09 21:51:33 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 09 16:51:33 2026 -0500"
      },
      "message": "[MLIR] Add FunctionReturnOpInterface (#3461)\n\n* [MLIR] Add isReturn InterfaceMethod\n\nisReturn indicates whether a statment returns from its caller. However,\nmlir::OpTrait::ReturnLike implies RegionBranchTerminatorOpInterface,\nwhich models a statement that transfers control and valus to its parent.\n\nA cir.return can appear inside an cir.if statement and return directly\nfrom the enclosing function instead. Since this berhavior does not\nsatisfy RegionBranchTerminatorOpInterface, cir.return cannot use\nReturnLike.\n\nWe provide a isReturn method so that new dialects can wire their\nimplementation to isReturn.\n\n* fixup! [MLIR] Add isReturn InterfaceMethod"
    },
    {
      "commit": "e949b437dc6450204871ccd9a84ce7802125d617",
      "tree": "a68b832bb62cf3740b9d892dcd9274d96969f871",
      "parents": [
        "56e474ac23d6777d86c573ab71600c62f4971c32"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Fri Oct 09 07:56:24 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 09 07:56:24 2026 +0200"
      },
      "message": "Install enzyme_function_hooks.mod with the Fortran bindings (#3328)\n\nCo-authored-by: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nCo-authored-by: Joe Wallwork \u003cjw2423@cam.ac.uk\u003e"
    },
    {
      "commit": "56e474ac23d6777d86c573ab71600c62f4971c32",
      "tree": "647ae942a212b49f821e8fd78a657a8f01c0b1fa",
      "parents": [
        "fd4e81c4f8b7be063818729aa97009c5a1e3fa33"
      ],
      "author": {
        "name": "copybara-service[bot]",
        "email": "56741989+copybara-service[bot]@users.noreply.github.com",
        "time": "Thu Oct 08 10:43:00 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 10:43:00 2026 -0500"
      },
      "message": "Fix a few comment typos in ActivityAnalysis and MustExitScalarEvolution (#3458)\n\npropogate/deriviative -\u003e propagate/derivative, occured -\u003e occurred,\npreceeding -\u003e preceding. Comments only, no functional change.\n\nAlso pins the MLIR CI\u0027s llvm/llvm-project checkout to 62e30e3326d9b4e3948d242ccfee7aa4fc030ef3, the LLVM commit google3 is on (was 018a9e4a74ba5d383351bda907a8b116bc5d8c47).\n\nGoogle-Internal-CL: cl/995847602\nPiperOrigin-RevId: 995847602\n\nCo-authored-by: Billy Moses \u003cwmoses@google.com\u003e"
    },
    {
      "commit": "fd4e81c4f8b7be063818729aa97009c5a1e3fa33",
      "tree": "1c8baa54b1b457403427e02252036b38aa5d6f51",
      "parents": [
        "efffbd4b16d7597250ad17368c7a4a19a46348c1"
      ],
      "author": {
        "name": "Katharine Hyatt",
        "email": "kshyatt@users.noreply.github.com",
        "time": "Thu Oct 08 16:23:34 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 09:23:34 2026 -0500"
      },
      "message": "Handle trivial aggregates in the calling convention fixup (#3456)"
    },
    {
      "commit": "efffbd4b16d7597250ad17368c7a4a19a46348c1",
      "tree": "c32690673ec27926f57196be8a3d82bdd9d38908",
      "parents": [
        "47143643743112f5e7bad1eaa5ee71204ff93bdf"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Thu Oct 08 08:10:45 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 08:10:45 2026 +0200"
      },
      "message": "Mark OpenMP runtime calls as not freeing or returning allocations (#3392)\n\nAssisted-by: Claude Code (Opus 5.5)"
    },
    {
      "commit": "47143643743112f5e7bad1eaa5ee71204ff93bdf",
      "tree": "73d7a8aa02dfe2339fff35a5232653af043475c3",
      "parents": [
        "80297354483ef86027553a97cb0400d792238b2c"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Thu Oct 08 08:08:51 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 08 08:08:51 2026 +0200"
      },
      "message": "Install a flang config file that loads Enzyme for compile and LTO link (#3435)\n\nCo-authored-by: Claude \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "80297354483ef86027553a97cb0400d792238b2c",
      "tree": "0139573b09cc779142cbc79bca6ff9515cd02a76",
      "parents": [
        "302b6684461c68bd6ad03b3da9c18ec64bb41a9f"
      ],
      "author": {
        "name": "copybara-service[bot]",
        "email": "56741989+copybara-service[bot]@users.noreply.github.com",
        "time": "Wed Oct 07 15:59:40 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 15:59:40 2026 -0500"
      },
      "message": "Fix \"occured\" typo in activity analysis comments (#3454)\n\nTest change for the Copybara google3 -\u003e GitHub upstream workflow\n(third_party/enzyme default_upstream). Fixes the same comment typo in the\nLLVM and MLIR activity analyses.\n\nPiperOrigin-RevId: 995278653\n\nCo-authored-by: Billy Moses \u003cwmoses@google.com\u003e"
    },
    {
      "commit": "302b6684461c68bd6ad03b3da9c18ec64bb41a9f",
      "tree": "9b1f871d9d2d865291f299f4d4985397b4754c89",
      "parents": [
        "9c73160e7f628d5c8ae5076d554d2273194ad7b0"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Wed Oct 07 21:50:35 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 21:50:35 2026 +0200"
      },
      "message": "Fix the value of pi in the sincn, sincospi, sinpi and cospi rules (#3274)\n\nCo-authored-by: Claude \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "9c73160e7f628d5c8ae5076d554d2273194ad7b0",
      "tree": "21d30a38ceba4fb4d8a3a7c966d915893318dad5",
      "parents": [
        "f60c06fb5ee92beb6bb21a4269212c80547c1a1c"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Wed Oct 07 18:08:21 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 18:08:21 2026 +0200"
      },
      "message": "TypeAnalysis: tan, asin, acos, atan, atan2 and sincos intrinsics (#3385)\n\nThese take and return floating-point values like the other libm\nintrinsics, but had no rule, so their results stayed untyped. A phi\nmerging such a result with a float then has no type (\"Cannot deduce type\nof phi\"), as in MITgcm gchem_insolation, where flang emits llvm.asin and\nllvm.sincos.\n\nAssisted-by: Claude Code (Opus 5.5)"
    },
    {
      "commit": "f60c06fb5ee92beb6bb21a4269212c80547c1a1c",
      "tree": "68a3f2ae346fef24e798b2c57ae4e9909af4cf8c",
      "parents": [
        "10beef3564f953d9eb4c2b0b60fa7dc002d6174a"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Wed Oct 07 18:07:50 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 18:07:50 2026 +0200"
      },
      "message": "Fix the sign of AndLinearShift when the shared operand comes first (#3284)\n\n`(b + a) \u003d\u003d c` was rewritten to `a \u003d\u003d b - c` and `(b - a) \u003d\u003d c` to\n`a \u003d\u003d b + c`. For stencils whose offsets are not symmetric this put the\nentries of a sparse derivative at the wrong indices.\n\nAssisted-by: Claude Code (Opus 5.5)"
    },
    {
      "commit": "10beef3564f953d9eb4c2b0b60fa7dc002d6174a",
      "tree": "ecafbbf53c71473103277db00cd1dfbcff486e78",
      "parents": [
        "dfaaf2a286208072747cc420374af83629637bad"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Wed Oct 07 14:34:22 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 09:34:22 2026 -0500"
      },
      "message": "Relax CHECK-NEXT in lto_prelink_rule.c for clang builds that keep value names (#3450)\n\nWith a clang that preserves value names (e.g. assertion builds, or\n-fno-discard-value-names), the entry block is printed with an explicit\n`entry:` label, so the line after `define ... @dsquare_a(` is not the\n`ret`:\n\n    define dso_local noundef double @dsquare_a(double noundef %x) ... {\n    entry:\n      ret double 1.000000e+02\n    }\n\n`CHECK-NEXT: ret double 1.000000e+02` therefore fails with\n\"CHECK-NEXT: is not on the line after the previous match\", even though\nthe post-link result is exactly what the test wants to verify.\n\nUse a plain `CHECK` instead. It is still scoped to the function by the\npreceding `CHECK-LABEL`, and the trailing `CHECK-NOT: __enzyme_fwddiff`\nstill guarantees the call was fully resolved."
    },
    {
      "commit": "dfaaf2a286208072747cc420374af83629637bad",
      "tree": "21b4f92e4ba0e18364d6acf6d74311e6e1c880a4",
      "parents": [
        "96041627496624d3f7d6b2bf23d17c9c248c4186"
      ],
      "author": {
        "name": "Manuel Drehwald",
        "email": "git@manuel.drehwald.info",
        "time": "Wed Oct 07 10:33:11 2026 -0400"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 09:33:11 2026 -0500"
      },
      "message": "Walk L, not anc, in overwritesToMemoryReadByLoop\u0027s ancestor gates (#3447)\n\n* Test a wrong gradient from an outer-loop overwrite\n\nIn both tests a store in outer iteration i+1 overwrites exactly what a\nload read in iteration i. overwritesToMemoryReadByLoop reports no\noverwrite, the load is not cached, and the reverse pass reloads the\nclobbered memory.\n\nThe lit test records the generated function, including that reload\n(%v_unwrap from %A). The integration test runs it: at -O0/-O1 eight\ngradient entries come out as 6 instead of 12..28. Both record the current,\nwrong output.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\n\n* Walk L in overwritesToMemoryReadByLoop\u0027s gates\n\nBoth legality gates initialise L \u003d anc but then test and advance anc, so\nthey check the innermost common loop repeatedly instead of every common\nloop in [anc, scope): an unvisited outer loop still counts as legal and the\nload is wrongly reported as not overwritten. Advancing anc also corrupts\nthe anc that skipLoop captures by reference for the second hasOverlap call.\n\nWalk L instead and leave anc alone. The lit test now shows %v cached and\nread back from the cache, and the integration test produces the exact\ngradient at every optimisation level.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\n\n---------\n\nCo-authored-by: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "96041627496624d3f7d6b2bf23d17c9c248c4186",
      "tree": "583fb8de552aa018e9ea02d5f6a295aef483f672",
      "parents": [
        "ede97b5c7b8d1ddacd5383601798a67aaac2077c"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Wed Oct 07 10:28:41 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Oct 07 10:28:41 2026 +0200"
      },
      "message": "Know flang\u0027s time, command line and environment queries to be inactive (#3333)\n\nCo-authored-by: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "ede97b5c7b8d1ddacd5383601798a67aaac2077c",
      "tree": "54e2fadbd177ccd245061c4ede705fdd71eb5df9",
      "parents": [
        "61d28ed38b895446a4f3806e41652fb3b6b558ea"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Tue Oct 06 21:24:40 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 16:24:40 2026 -0500"
      },
      "message": "Answer whether the augmented pass used a primal from the augmented pass (#3442)\n\nIn split mode the augmented forward pass and the reverse pass are separate\ncompilations, and their differential use analyses can disagree on whether\nthe primal of a call was used, e.g. when only the augmented function\nreturns it. A caller rebuilding how a call was augmented, such as a custom\nrule choosing its config and tape layout, needs the augmented pass\u0027s\nanswer. Record the augmented pass\u0027s unnecessary values and recompute\ndecisions in its AugmentedReturn, and expose\nEnzymeGradientUtilsGetAugmentedPrimalReturnUsed, which answers from them\nin the reverse pass.\n\n\nClaude-Session: https://claude.ai/code/session_015RAaewsVwF5wyRBfErBEEr\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "61d28ed38b895446a4f3806e41652fb3b6b558ea",
      "tree": "25478fa4275ed215b38a67e7f0de9551dc0f9a5a",
      "parents": [
        "4eaa75a8f3f905c7f269311bf848cfec6c007720"
      ],
      "author": {
        "name": "Vimarsh Sathia",
        "email": "vimarsh.sathia@gmail.com",
        "time": "Tue Oct 06 12:14:38 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 12:14:38 2026 -0500"
      },
      "message": "Revert \"Fix captures and memory checks in AD hoisting (#3431)\" (#3434)\n\nThis reverts commit bf5e11676038d9d3662f0183b18e324eb11dcb4e."
    },
    {
      "commit": "4eaa75a8f3f905c7f269311bf848cfec6c007720",
      "tree": "946eb79212dcbac0eca4e86f8ed5f30078428492",
      "parents": [
        "2bc9044087502e08606548a6d4ad944ad3a8d925"
      ],
      "author": {
        "name": "Vimarsh Sathia",
        "email": "vimarsh.sathia@gmail.com",
        "time": "Tue Oct 06 12:13:54 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 12:13:54 2026 -0500"
      },
      "message": "Revert \"Preserve captures when outlining AD regions (#3424)\" (#3433)\n\nThis reverts commit d4b281484f35d238b7865eb2473d62f7f2bb6d0c."
    },
    {
      "commit": "2bc9044087502e08606548a6d4ad944ad3a8d925",
      "tree": "0b527e3e5d18c2446b79c178a2579db5eb7ee2cb",
      "parents": [
        "bf5e11676038d9d3662f0183b18e324eb11dcb4e"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Tue Oct 06 18:33:06 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 18:33:06 2026 +0200"
      },
      "message": "Split LLVM_DEFINITIONS before add_definitions (#3427)\n\nLLVM_DEFINITIONS is a single space-separated string. Passing it to\nadd_definitions as one argument made CMake define the first macro with\nthe rest of the string as its value. Since LLVM 22 the string starts\nwith -D_GLIBCXX_USE_CXX11_ABI\u003d1, which breaks libstdc++ with\n\"token \\\"\u003d\\\" is not valid in preprocessor expressions\" on mingw and\nmusl cross builds.\n\n\nClaude-Session: https://claude.ai/code/session_01CuzKVFFbVPMttQ86pjGeKd\n\nCo-authored-by: Claude \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "bf5e11676038d9d3662f0183b18e324eb11dcb4e",
      "tree": "452c28a656cd714e945375daf02279c164adaef3",
      "parents": [
        "d4b281484f35d238b7865eb2473d62f7f2bb6d0c"
      ],
      "author": {
        "name": "Vimarsh Sathia",
        "email": "vimarsh.sathia@gmail.com",
        "time": "Tue Oct 06 11:00:23 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 11:00:23 2026 -0500"
      },
      "message": "Fix captures and memory checks in AD hoisting (#3431)\n\nKeep constant captures separate from active arguments.\nIf an effect or dependency check fails, reject motion.\nKeep automatic allocations in their owning scopes.\nCheck allocation and free effects for alias conflicts.\n\nTest that memref.alloca stays inside the AD region.\nTest that memref.dealloc stays after a store to the same buffer.\n\nRelated: EnzymeAD/Enzyme-JAX#3204."
    },
    {
      "commit": "d4b281484f35d238b7865eb2473d62f7f2bb6d0c",
      "tree": "874b4eefea83244135dfddf3000e0ddf37dae0ec",
      "parents": [
        "fb91d7330c0fbfc81b350dcc739124b6d7f5f164"
      ],
      "author": {
        "name": "Vimarsh Sathia",
        "email": "vimarsh.sathia@gmail.com",
        "time": "Tue Oct 06 09:50:18 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 09:50:18 2026 -0500"
      },
      "message": "Preserve captures when outlining AD regions (#3424)"
    },
    {
      "commit": "fb91d7330c0fbfc81b350dcc739124b6d7f5f164",
      "tree": "3646d6f65e3a1c9ac68aaf59dc4e606646a4e989",
      "parents": [
        "465ca03fe9bc53f08732325ff8e1ddd6b7907ff5"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Tue Oct 06 14:56:20 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 07:56:20 2026 -0500"
      },
      "message": "Defer differentiation from an LTO pre-link pipeline to the post-link run (#3211)\n\n* Defer differentiation from an LTO pre-link pipeline to the post-link run\n\naugmentPassBuilder registers Enzyme on two extension points: OptimizerEarly,\nwhich runs per translation unit, and FullLinkTimeOptimizationEarly, which runs\ninside the linker. With -flto both fire, and the pre-link one fires first on a\nmodule that is only one translation unit -- so a __enzyme_autodiff call naming a\nfunction defined in another object fails with \"failed to find fn to\ndifferentiate\" before the link-time run ever gets to see the whole program.\n\nThat forced an either/or: load the plugin in the compiler (-fpass-plugin\u003d) or in\nthe linker (-Wl,--load-pass-plugin\u003d), but not both, even though on LLVM \u003e\u003d 16\nFlangEnzyme/ClangEnzyme/LLDEnzyme are the same library behind the same\nllvmGetPassPluginInfo.\n\nSince LLVM 20 the OptimizerEarly callback receives the ThinOrFullLTOPhase, which\nEnzyme discarded. Use it: skip the body at FullLTOPreLink and ThinLTOPreLink and\nlet the post-link run do the work -- FullLinkTimeOptimizationEarly for full LTO,\nthis same callback re-entered with ThinLTOPostLink for ThinLTO. The PreserveNVVM\npass still runs at pre-link, so the functions involved stay alive until then.\n\nThis needs the plugin to be loaded by the linker as well; where that is not\npossible, -mllvm -enzyme-lto-prelink\u003d1 restores the old behaviour. Nothing\nchanges for non-LTO builds, and LLVM \u003c 20 is untouched since the phase is not\navailable there.\n\nCo-Authored-By: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01TC5oeSdtsztrJspe4tFCJx\n\n* Restore linkage after a deferring LTO pre-link and keep ThinLTO O0 eager\n\nA pre-link pipeline that defers differentiation skipped the PreserveNVVM\nend pass, leaving every static or inline function a custom rule,\nenzyme_function_like or implements names with external linkage in the\nbitcode. Two objects including the same rule then failed to link on\nduplicate symbols. Run a pre-link end pass instead that restores the\noriginal linkage and keeps the functions alive through llvm.compiler.used\nuntil the post-link end pass drops those entries again.\n\nA ThinLTO post-link pipeline at O0 invokes no extension point callbacks,\nso a deferred call was never differentiated. Do not defer a ThinLTO\npre-link at O0; the driver passes the compile -O level on to the linker.\n\nAlso load LLDEnzyme rather than ClangEnzyme into opt in the tests, and\nrename the substitution so lit does not expand its %opt prefix first.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n---------\n\nCo-authored-by: Claude Opus 5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "465ca03fe9bc53f08732325ff8e1ddd6b7907ff5",
      "tree": "148b81ffd3614328a29f94e9b53b146cce5be8f1",
      "parents": [
        "8217349cb859856d61a446f0f2964a650eeba1d6"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Tue Oct 06 12:40:02 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 12:40:02 2026 +0200"
      },
      "message": "Cache values in flang\u0027s OpenMP worksharing loops (#3387)\n\n* Cache values in flang\u0027s OpenMP worksharing loops\n\nThe cache of a loop over a thread\u0027s chunk of a worksharing loop is sized\nfor the iterations of all threads and offset by the start of the chunk,\nso that it can be allocated before the parallel region. CacheUtility only\nrecognized clang\u0027s loop, whose limit has a -lb term. flang\u0027s\nOpenMPIRBuilder computes the chunk\u0027s trip count as zext(ub - lb + 1), and\nat O3 the loop is vectorized with a remainder loop, so its limit hid the\nbounds under a zext or a udiv. The cache was then sized from the chunk\u0027s\nbounds inside the outlined function, which the fork call site cannot see\n(\"inst-\u003egetParent()-\u003egetParent() \u003d\u003d newFunc\" in lookupM).\n\nRecognize any loop whose limit depends on a bound __kmpc_for_static_init\nstored. A vectorized loop or its remainder runs at most as many\niterations as the chunk, so the same offset keeps threads disjoint.\n\nAlso store a phi cached per thread after all phis of its block; the\nremainder loop\u0027s start phi broke the verifier.\n\nFortran tests: a private temporary (O1 and O3) and a routine with a\nparallel loop called twice; the existing square test now also runs at O2\nand O3.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n* Apply batched suggestions from code review\n\nCo-authored-by: Valentin Churavy \u003cv.churavy@gmail.com\u003e"
    },
    {
      "commit": "8217349cb859856d61a446f0f2964a650eeba1d6",
      "tree": "fce8031f104d6b253a3e00763e7ed541f033b3b8",
      "parents": [
        "9c5dc14d61d39862300117075feb8b4510f81b58"
      ],
      "author": {
        "name": "Joe Wallwork",
        "email": "22053413+joewallwork@users.noreply.github.com",
        "time": "Tue Oct 06 08:40:23 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 08:40:23 2026 +0000"
      },
      "message": "Add Fortran forward test for MPI_Isend, MPI_Irecv, and MPI_Wait (#3419)\n\n* Separate out flangenzyme version of test\n\n* Fix attribute for irecv with -O1+\n\n* Link to issue for reverse mode\n\n* Only use Flang plugin if flangenzyme"
    },
    {
      "commit": "9c5dc14d61d39862300117075feb8b4510f81b58",
      "tree": "976abb23ab9b2f0dcc8349ecd54fec607baa8e6e",
      "parents": [
        "56b02e7e94265e7af38fe95e9fbf9818ef1d09c0"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Tue Oct 06 07:49:26 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Oct 06 07:49:26 2026 +0200"
      },
      "message": "Build Enzyme_jll for LLVM 22 (#3423)\n\nJulia master (1.14-DEV) uses LLVM 22.1.8; add it to the Yggdrasil recipe.\n\nAssisted-by: Claude Code (Opus 5.5)"
    },
    {
      "commit": "56b02e7e94265e7af38fe95e9fbf9818ef1d09c0",
      "tree": "9e4597212e8ca944301cb6a1b0907a9d13b6226e",
      "parents": [
        "b1d93d0bb23a8cb01123e0b66f1b50d2c505c6d6"
      ],
      "author": {
        "name": "Vimarsh Sathia",
        "email": "vimarsh.sathia@gmail.com",
        "time": "Mon Oct 05 19:12:32 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 05 19:12:32 2026 -0500"
      },
      "message": "Add OffsetViewInterface (#3420)\n\n* Add NoOffsetViewInterface\n\n* Use NoOffsetViewInterface in getBaseObject\n\nFollow views that implement NoOffsetViewInterface when offsets are disabled.\n\nAssisted-By: OpenAI Codex\n\n* add memref ops to interface\n\n* Bazel build fixes for new llvm\n\n* rename interface, refactor code a bit\n\n* Add zero-offset queries to OffsetViewInterface\n\n* Add isZeroOffset() for llvm gep\n\n* Use OffsetViewInterface for LLVM address-space casts\n\n* Use view interfaces in capture and activity analysis\n\n* Fix clang-format for memref view interface registration\n\n* Remove redundant LLVM cast checks from activity analysis"
    },
    {
      "commit": "b1d93d0bb23a8cb01123e0b66f1b50d2c505c6d6",
      "tree": "39c9a05051477ed8590b34dd6372c6b711774690",
      "parents": [
        "b62f728ec1ba1fed3696a327e78f1396eebf1f4c"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Mon Oct 05 21:14:13 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 05 14:14:13 2026 -0500"
      },
      "message": "Bound the size of NoType error messages (#3413)\n\n* Bound the size of NoType error messages\n\nTypeResults::firstPointer and intType built their \"Cannot deduce type of\ninteger\" message from the whole function and the whole type analysis\n(dump). The error is recoverable (EmitNoTypeError hands it to the custom\nerror handler, and compilation continues), so it can be reported for many\nvalues of one function; for a large function the message alone is GBs.\n\n- firstPointer, intType: name the function instead of printing it, and no\n  longer append the type analysis. A custom error handler gets the analyzer\n  and the instruction and can produce these itself.\n- EmitNoTypeError without a custom handler: append the function and its\n  type analysis once (it appended the type analysis a second time), bounded\n  by the new option -enzyme-max-error-dump (1 MiB by default, 0 for no\n  limit), through a BoundedStringOStream. Also no longer dereferences a null\n  gutils (intType passes nullptr).\n- DiffeGradientUtils::addToDiffe: name oldFunc in its two NoType messages\n  instead of printing it.\n- New C API EnzymeTypeAnalyzerToStringBounded, for handlers that want a\n  bounded type analysis.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n* Drop the function and type analysis dumps from NoType errors\n\nPer review: don\u0027t print the whole function or type analysis where the\nerror is raised (TypeResults::intType/firstPointer, addToDiffe), and drop\nthe -enzyme-max-error-dump bound. Only EmitNoTypeError appends the\nfunction and type analysis, and only when there is no custom error\nhandler; a custom handler (e.g. Julia\u0027s) decides itself what to print.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n* Remove the bounded string stream and bounded type analyzer dump\n\nWith the dumps gone from the error sites and left to EmitNoTypeError\n(only without a custom handler), nothing needs to bound them.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n---------\n\nCo-authored-by: William S. Moses \u003cgh@wsmoses.com\u003e\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "b62f728ec1ba1fed3696a327e78f1396eebf1f4c",
      "tree": "17e4693b5d7d1d39252435db37443331004c1a64",
      "parents": [
        "d13ea74cb06e7d5377afaa62490dcae920708435"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Mon Oct 05 17:45:32 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 05 12:45:32 2026 -0500"
      },
      "message": "Treat writes to the data of a fresh Julia Memory or array as local (#3418)\n\n* Treat writes to the data of a fresh Julia Memory as local\n\nA Julia function that builds a temporary array, such as `x .- μ`, writes it\nthrough the Memory\u0027s data pointer, which is loaded from the Memory object.\nThe read-only-or-throw inference only accepted writes whose base object is\nan allocation, so it did not mark such functions LocalReadOnlyOrThrow, and\ncallers had to treat calls to them as possibly overwriting anything.\n\nThe data field, which follows the length, of a Memory allocated by\njl_alloc_genericmemory is set on allocation and never changed, so its data\ndid not exist before the call either. For n \u003d\u003d 0 Julia uses the empty Memory\nsingleton instead of allocating; no in-bounds access writes its data, and\nEnzyme.jl marks its global enzymejl_empty_memory. Accept writes through a\npointer loaded from that field of such objects, or of phis and selects of\nthem, as local writes.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n* Also treat writes to the data of a fresh Julia array as local\n\nWrites through the data field, at offset 0, of a Julia array allocated in\nthe function also write memory that did not exist before the call, provided\nthe field only ever holds fresh data. On Julia 1.10, jl_alloc_array_* sets it\nto data it allocates, and every array access reloads it from the array. From\nJulia 1.11 on the array is allocated like any object and the function stores\nthe data of a fresh Memory into it.\n\nUnlike a Memory\u0027s, the field can change, e.g. when the array grows. Accept it\nonly if every store to it in the function stores fresh data (or null), and\nthe array\u0027s address is not stored or passed to a call that may capture or\nwrite through it, so no other code can change the field while the function\nruns.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n* Find fresh Julia Memory and array objects with getBaseObjects\n\nTake the offset of the loaded data pointer from LLVM\u0027s\nstripAndAccumulateConstantOffsets, and the objects it may point into from\ngetBaseObjects, rather than a custom stripping helper and recursion over\nphis. Selects of fresh objects are no longer recognized.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n* Look through selects in getBaseObjects\n\nA select picks one of its operands like a phi does, so return the base\nobjects of both. This lets a pointer loaded from a select of fresh Julia\nMemory or array objects be recognized again.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n---------\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "d13ea74cb06e7d5377afaa62490dcae920708435",
      "tree": "d1b81859a4aa35fca01310657f2182513b1cabab",
      "parents": [
        "ad0f8e0b5ba8da6b955c834cc8bbac9e24b76ac1"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Mon Oct 05 17:39:40 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 05 10:39:40 2026 -0500"
      },
      "message": "Treat `\u003e\u003d` loop exits as signed when the predicate is sge (#3406)\n\n* Treat `\u003e\u003d` loop exits as signed when the predicate is sge\n\nIn the `X \u003e Y` branch of computeExitLimitFromICmp, `IsSigned` was set from\nICMP_SLE instead of ICMP_SGE, a predicate that cannot reach that branch. A\nsigned `i \u003e\u003d m` exit was analysed as unsigned, which can give a wrong trip\ncount: for a loop counting down to a possibly negative bound, the count came\nout as 0, so the reverse pass cached one iteration in an 8-byte buffer\nwhile the forward pass wrote every iteration into it.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n* Fix typo in RUN command for loopcount_sge.ll\n\n* Update loopcount_sge.ll\n\n---------\n\nCo-authored-by: William Moses \u003cgh@wsmoses.com\u003e"
    },
    {
      "commit": "ad0f8e0b5ba8da6b955c834cc8bbac9e24b76ac1",
      "tree": "eaaa73811aebb69906355abd744b8729cfef669d",
      "parents": [
        "3cd66b79ce224b8dc35cfac0e37038ed186b2013"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Mon Oct 05 15:27:38 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Oct 05 10:27:38 2026 -0500"
      },
      "message": "Do not treat read-only-or-throw calls as overwriting callee data (#3415)\n\n* Do not treat read-only-or-throw calls as overwriting callee data\n\nWhen a callsite decides whether memory the callee read may be overwritten\nafterwards, any later instruction that may write memory made subsequent\ncalls count as writing. A call that only writes memory on paths that throw\n(enzyme_ReadOnlyOrThrow) was counted too, although if it throws the reverse\npass never runs. With subsequent writes, everything the callee loads through\na pointer loaded from memory, such as a Julia array\u0027s data, has to be cached.\n\nThis made two consecutive non-inlined calls that each loop over an array\ncache every element they read: in Julia, the gradient of such a function\ntook 12x the primal, against 3x when the calls were inlined.\n\nSkip read-only-or-throw calls when checking for later writes. Also treat a\nLocalReadOnlyOrThrow call, which may additionally write memory it allocated\nand its sret-like arguments, as only writing those arguments: it is not an\nunknown write if they are uncaptured local memory, and it only overwrites a\ncallee argument that may alias one of them.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n* Use a static member function rather than a lambda for mayModify\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n* Rename the uncaptured local memory helpers to mention noalias arguments\n\nThey also accept uncaptured noalias arguments, whose memory existed before\nthe function. Say so in the names, and explain why no pointer loaded from\nmemory can reach such memory.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01En5yBUJEvaEnaaCAoSm5UR\n\n---------\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "3cd66b79ce224b8dc35cfac0e37038ed186b2013",
      "tree": "6f57cc2ad496470a189778cde01615e5f4668f7a",
      "parents": [
        "c13ddc71a6360ab9e3f13afb8a2e2353eef9ff6a"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Mon Oct 05 06:08:37 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 04 23:08:37 2026 -0500"
      },
      "message": "TypeTree::allFloat: handle Anything at offset 0 with anythingIsFloat (#3410)\n\n* TypeTree::allFloat: handle Anything at offset 0 with anythingIsFloat\n\nIf the type tree has no [-1] entry and offset 0 is Anything, allFloat with\nanythingIsFloat continues with flt \u003d\u003d nullptr and then takes\nDataLayout::getTypeSizeInBits(nullptr), which segfaults. Walk the bytes one\nat a time until a float type is found, then step by its size.\n\nReached from invertPointerM for a store of a byte extracted from an\naggregate typed {[0]:Anything, [1..6]:Integer}: on Julia 1.13 this is the\ncopy of the 7 padding bytes after a 1-byte field (e.g. a grid\u0027s\narchitecture in SpeedyWeather.jl\u0027s ShallowWater model).\n\nAssisted-by: Claude Code (Opus 5.5)\n\n* Update allfloat-anything-offset0.ll\n\n* Update allfloat-anything-offset0.ll\n\n---------\n\nCo-authored-by: William Moses \u003cgh@wsmoses.com\u003e"
    },
    {
      "commit": "c13ddc71a6360ab9e3f13afb8a2e2353eef9ff6a",
      "tree": "494665d68155affa0dcc2b40cd3b3f77928a1787",
      "parents": [
        "d7420561ea325d0f9f6977b0532aae801fce20cc"
      ],
      "author": {
        "name": "Vimarsh Sathia",
        "email": "vimarsh.sathia@gmail.com",
        "time": "Sun Oct 04 22:58:06 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 04 22:58:06 2026 +0000"
      },
      "message": "Add an offset-preserving mode to MLIR getBaseObject (#3412)\n\nAdd offsetAllowed with the same default as the LLVM helper. When false, retain operations that can change the starting address. Handle LLVM operations before their generic view interfaces.\n\nTest both modes with GEPs, casts, subviews, byte shifts, and reinterpret casts."
    },
    {
      "commit": "d7420561ea325d0f9f6977b0532aae801fce20cc",
      "tree": "a710875e56d8d10186169416c349e333c47d5d08",
      "parents": [
        "3cfc955c9c73ad7c54334e0db15b46000932297a"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Sun Oct 04 20:08:41 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Oct 04 20:08:41 2026 +0000"
      },
      "message": "Migrate the MLIR dialects to strict property assembly, and move CI to 018a9e4a (#3411)"
    },
    {
      "commit": "3cfc955c9c73ad7c54334e0db15b46000932297a",
      "tree": "608f8033e3c8b83ec1e68111e9f8edf8b9e5991c",
      "parents": [
        "d3c235e31a3440d0d30ddc9f828cfc370b56c967"
      ],
      "author": {
        "name": "isaacaka",
        "email": "ia464@cam.ac.uk",
        "time": "Sat Oct 03 17:39:40 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 03 17:39:40 2026 +0000"
      },
      "message": "Document Fortran custom derivative registration (#3318)\n\n* Document Fortran custom derivative registration\n\nAdd tests for defining custom derivatives using only Fortran and add\nrelevant documentation\n\n* Add tests for forward mode custom derivatives\n\n* Rename reverse mode tests\n\n* Fix Fortran custom derivative docs after test rename\n\n- Update README links and shell commands to the renamed test files\n  (custom_derivative.f90, custom_derivative_accumulation.f90).\n- Use a single opt pipeline (preserve-nvvm,enzyme,preserve-nvvm-end)\n  throughout the README; `-passes\u003denzyme` alone never runs\n  PreserveNVVM, so registration was silently skipped.\n- Describe the mechanism as one derived-type variable with three\n  procedure-pointer components, and document forward-mode\n  registration via __enzyme_register_derivative.\n- Align the ReverseMode/custom_derivative.f90 RUN lines with the\n  sibling tests.\n\nAssisted-by: Claude Code (Fable 5.1)\n\n---------\n\nCo-authored-by: Valentin Churavy \u003cv.churavy@gmail.com\u003e"
    },
    {
      "commit": "d3c235e31a3440d0d30ddc9f828cfc370b56c967",
      "tree": "59c0d757209b25af31c7612938b074831dc5a52b",
      "parents": [
        "cdfaa22a4c3ceee3c19ba7c213ed039a278fe255"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Sat Oct 03 18:33:20 2026 +0200"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sat Oct 03 18:33:20 2026 +0200"
      },
      "message": "Keep the augmented call when it returns an empty tape directly (#3376)\n\nWhen a call is differentiated with an augmented forward pass that returns\nonly its tape (tapeIdx \u003d\u003d -1), the tape value is the augmented call itself.\nIf the tape type is empty ({}), the isEmptyTy() branch erased the tape to\nreplace it with undef, which deleted the augmented call and the primal side\neffects of the callee.\n\nOnly erase the tape when it is an extractvalue of the augmented call.\n\nCo-authored-by: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "cdfaa22a4c3ceee3c19ba7c213ed039a278fe255",
      "tree": "f642d60ff44f0701bc525df7ad7811e64087e104",
      "parents": [
        "2b3255e3808aa234500bbf4bc22a832d01756228"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Fri Oct 02 05:12:29 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Fri Oct 02 05:12:29 2026 +0000"
      },
      "message": "Type the results of lround, lrint and fptosi.sat as integers (#3384)\n\nTypeAnalysis had no rule for llvm.lround/llround/lrint/llrint or\nllvm.fptosi.sat/fptoui.sat, so their results, and everything computed from\nthem, had no type. Flang lowers NINT to llvm.lround. In MITgcm\u0027s\ncheckpointed time step myIter \u003d iloop - 1 + nIter0 with nIter0 \u003d NINT(...),\nso the alloca holding myIter had no pointee type, the activity analysis took\nit as possibly active, and thermodynamics\u0027 load of myIter failed with\n\"Cannot deduce adding type\". Type them as fptosi is typed: an integer\nresult of a floating point operand.\n\nAssisted-by: Claude Code (Opus 5.5)"
    },
    {
      "commit": "2b3255e3808aa234500bbf4bc22a832d01756228",
      "tree": "522fa73dfb44434eba5b21ef0ac8a9eb93d064a6",
      "parents": [
        "2f02f493edc6c610e5caf105122aaa78db4dc913"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Thu Oct 01 22:12:44 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 22:12:44 2026 +0000"
      },
      "message": "Derive SCEV\u0027s wrap-flag type from a flag constant (#3362)\n\nLLVM renamed SCEV::NoWrapFlags to SCEVFlags (llvm/llvm-project#225179,\nafter #226935 freed the name) and dropped the SCEV::NoWrapFlags alias,\nso MustExitScalarEvolution.cpp no longer builds against LLVM main.\n\nTake the type from SCEV::FlagNSW, which every version provides, instead\nof naming it. The alias gets a name of its own (WrapFlagsTy), because\nthe file uses namespace llvm and an alias named like one of LLVM\u0027s\nspellings would be ambiguous there.\n\nAssisted-by: Claude Code (Opus 5.5)"
    },
    {
      "commit": "2f02f493edc6c610e5caf105122aaa78db4dc913",
      "tree": "d6dc4155322925d0fd7fe3bcb84b2ac1013ebb2b",
      "parents": [
        "2e645ce58121f722e98d854c9f26429aa0e7f8f1"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Thu Oct 01 19:16:12 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 13:16:12 2026 -0500"
      },
      "message": "Shadow of a constant GEP of a global at width \u003e 1 (#3369)\n\n* Shadow of a constant GEP of a global at width \u003e 1\n\ninvertPointerM of a constant-expression getelementptr built every lane\nfrom the whole shadow of its base. At width \u003e 1 the shadow of a global\nwith an enzyme_shadow annotation is a [W x ptr] array constant of the\nper-lane shadows, so the GEP got that array as its pointer operand.\nWith LLVM assertions on, ConstantExpr::getWithOperands asserts\n(`SrcTy || (Ops[0]-\u003egetType() \u003d\u003d getOperand(0)-\u003egetType())`); without\nthem the pass emits invalid IR that indexes into the [2 x ptr] aggregate.\n\nPass the base shadow to applyChainRule so that each lane builds its GEP\nfrom its own shadow of the base.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n* Match the lane-1 shadow GEP on newer LLVM too\n\nNewer LLVM does not fold the nested constant GEP of the lane-1 shadow\ninto one GEP; accept both forms.\n\nAssisted-by: Claude Code (Opus 5.5)"
    },
    {
      "commit": "2e645ce58121f722e98d854c9f26429aa0e7f8f1",
      "tree": "212b1b860a62616bbd05fea2472148ca844fe0cf",
      "parents": [
        "6ff01050d956a1d87cd02c33e83a3707c2ea9be8"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Thu Oct 01 16:33:42 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 11:33:42 2026 -0500"
      },
      "message": "Replay the stores through a Julia array\u0027s data pointer when rematerializing it (#3375)\n\n* Replay the stores through a Julia array\u0027s data pointer when rematerializing it\n\nA Julia array allocated in a function is rematerialized in the reverse pass:\nthe allocation is redone and the stores into it are replayed. The use walk in\ncomputeForwardingProperties stops at loads, so the array\u0027s data pointer (an\naddrspace(13) pointer the allocator set up, loaded from the object) and\neverything through it were invisible: the data stores were never recorded as\nstores to replay, and the data loads never as loads that must be reloadable.\nThe reverse pass then re-ran the data pointer load on the fresh object and\nread its unfilled buffer.\n\nThis went unnoticed while the reads were cached by other means. A load\nthrough a pointer loaded from memory was cached whenever any write at all\nfollowed the call in the caller. Since #3325 only unknown writes count, so\nthe callee reloads, and Turing\u0027s demo_dot_assume_observe_index model on\nJulia 1.10 silently returned a wrong gradient: sqmahal\u0027s `x .- μ` temporary\nwas recreated empty before invwsumsq\u0027s reverse read it. The same happens\nwithout any callee once nothing follows the loads in the function.\n\nWalk through an addrspace(13) pointer loaded from the allocation as if it were\npointer arithmetic on it, as already happens for julia.gc_loaded on newer\nJulia versions where this worked. The data stores are then replayed before the\nreverse pass reads the data, and the usual checks apply to the data loads.\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n* Only walk through the data pointer when Julia address-space loads are enabled\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\n---------\n\nCo-authored-by: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "6ff01050d956a1d87cd02c33e83a3707c2ea9be8",
      "tree": "a64a08f446a07ad53b6fba703045ba30a5fe7010",
      "parents": [
        "ef2c24eeb482740c4817c67b7f3969405864b039"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Thu Oct 01 16:01:28 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 10:01:28 2026 -0500"
      },
      "message": "Replay MPI calls per lane in vector forward mode (#3347)\n\n* Replay MPI calls per lane in vector forward mode\n\nIn forward mode the derivative of MPI_Bcast, MPI_Send, MPI_Recv,\nMPI_Allreduce and MPI_Reduce (of a sum) is the same call on the shadow\nbuffers. At vector width \u003e 1, handleMPI asserted width 1; replay the call\nonce per lane instead, and report the other MPI functions as unsupported.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01M5d6m8eQfhUdHDMXaDuYq6\n\n* Test vector forward mode of mpi_allreduce_/mpi_bcast_\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01M5d6m8eQfhUdHDMXaDuYq6\n\n* Replay MPI calls per lane in the existing forward-mode rules\n\nInstead of a separate vector-mode path in front of handleMPI, every\nforward-mode rule (Isend/Irecv, Wait, Waitall, Send/Ssend, Recv, Bcast,\nReduce, Allreduce, Gather, Scatter, Allgather) now emits its shadow call\nthrough one helper, createMPIForwardCall. The helper replaces the buffer\narguments with their shadows and replays the call once per lane at\nwidth \u003e 1. All other arguments, including the Fortran `ierr`, are passed\nas in the original call, and an inactive constant buffer (MPI_IN_PLACE,\nMPI_STATUS_IGNORE) is passed unchanged.\n\nSo Isend/Irecv/Wait/Waitall/Gather/Scatter/Allgather also work in vector\nforward mode now. As a side effect, the forward rules of Waitall and\nAllgather pass all arguments of the call: before, they dropped the\nstatuses argument and the Fortran `ierr`. Reverse mode at width \u003e 1\nreports an unsupported-derivative error instead of asserting.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n* Test vector forward mode of mpi_allreduce/mpi_bcast from Fortran\n\nTwo lanes with rank-dependent seeds, so that the tangent sum of the\nallreduce and the root tangent of the bcast differ per lane. Without\nthe change, Enzyme asserts `getWidth() \u003d\u003d 1` in handleMPI.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n---------\n\nCo-authored-by: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "ef2c24eeb482740c4817c67b7f3969405864b039",
      "tree": "26a414d79107b50ef33dfb14ebb8acb78c2e1667",
      "parents": [
        "2a69a48db18a6fd84f02fd4060b587c127fb8e31"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Thu Oct 01 14:32:34 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 14:32:34 2026 +0100"
      },
      "message": "Reassign the GUID of cloned functions on LLVM 23+ (#3359)\n\nLLVM 23 persists every function\u0027s GUID in `!guid` metadata and\nCloneFunctionInto copies it, so a derivative clone shared its primal\u0027s\nGUID. LTO keys per-function state by GUID and mishandles the duplicate:\na definition reachable only through the clone, such as a registered\ncustom rule called from the generated derivative, was dropped to a\ndeclaration and the link failed with an undefined reference. Seen on\nthe flang 23 CI job for the Fortran custom-derivative tests at -O0 LTO.\n\nCall GlobalValue::reassignGUID() on every function Enzyme clones so the\nclone gets a GUID derived from its own name. No-op before LLVM 23.\n\nAssisted-by: Claude Code (Fable 5.1)"
    },
    {
      "commit": "2a69a48db18a6fd84f02fd4060b587c127fb8e31",
      "tree": "3abf5ef3dedf9c54c96aeebdae3a9d99de402ed4",
      "parents": [
        "4344243342fa0c1e15f306f1c51bb9fce4a82743"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Thu Oct 01 07:43:42 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 07:43:42 2026 +0100"
      },
      "message": "Undo the partial rewrite when automatic sparsity gives up (#3283)\n\n* Declare the sparsity placeholders memory(none) on LLVM 16+\n\n`readnone` is no longer a function attribute, so a module with\n`__enzyme_sum`/`__enzyme_product` declarations failed verification.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n* Undo the partial rewrite when automatic sparsity gives up\n\nWhen fixSparseIndices bailed out, it left the `__enzyme_sum` and\n`__enzyme_product` placeholders and the `enzyme.sparse.inbounds` markers in\nthe function, and the branches it had already rewritten kept comparing\nagainst phis that were replaced by undef. Restore the original branch\nconditions, remove the markers, and lower the placeholders on every exit.\nInteger placeholders are now lowered with integer arithmetic.\n\nAssisted-by: Claude Code (Opus 5.5)"
    },
    {
      "commit": "4344243342fa0c1e15f306f1c51bb9fce4a82743",
      "tree": "621cda8b7986d22b61f9a34f2e802d70f26b787d",
      "parents": [
        "abe42215455cd2c28975b74a9f6b06c1c29aeb01"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Thu Oct 01 07:43:08 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Thu Oct 01 07:43:08 2026 +0100"
      },
      "message": "Declare the sparsity placeholders memory(none) on LLVM 16+ (#3282)\n\n`readnone` is no longer a function attribute, so a module with\n`__enzyme_sum`/`__enzyme_product` declarations failed verification.\n\nAssisted-by: Claude Code (Opus 5.5)"
    },
    {
      "commit": "abe42215455cd2c28975b74a9f6b06c1c29aeb01",
      "tree": "86fed1f0bf27eab9d7e09d6350dc2531817d2ca5",
      "parents": [
        "0c6d756b1112e0597c98337670f2521bb0d8526c"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Thu Oct 01 03:01:04 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 22:01:04 2026 -0500"
      },
      "message": "Treat a rule registered through metadata as a custom rule for attribute inference (#3353)\n\nA derivative can also be registered for a function through\nenzyme_augment / enzyme_gradient / enzyme_derivative /\nenzyme_splitderivative metadata (__enzyme_register_derivative and\nfriends), not only by a frontend marking it enzyme_math\u003denzyme_custom.\nThe same reasoning applies: the rule may read a parameter the body\nnever reads, so DetectReadonlyOrThrow must not infer writeonly or\nreadnone for it either.\n\nFactor the metadata check that shouldDisableNoWrite already does into\nhasCustomRuleMetadata and use it in both places.\n\n\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\nCo-authored-by: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "0c6d756b1112e0597c98337670f2521bb0d8526c",
      "tree": "ca85156bbd5aceeb3257fec4c47990506e0b842e",
      "parents": [
        "ae388a550c27d3c3b9d8110fbfdb5f433ab743c6"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Thu Oct 01 02:53:39 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 21:53:39 2026 -0500"
      },
      "message": "Do not infer writeonly or readnone on the parameters of a custom-rule function (#3352)\n\nDetectReadonlyOrThrow derives a function\u0027s parameter attributes from its\nbody. For a function whose derivative comes from a custom rule\n(\"enzyme_math\"\u003d\"enzyme_custom\", as Enzyme.jl marks functions that have an\nEnzymeRules rule), the body is not the whole story: the augmented\nforward, reverse or forward-mode replacement may read a parameter the\nbody never reads, for instance to compute the derivative from the\nprimal inputs. A writeonly or readnone inferred from the body would then\nlet Enzyme treat that argument\u0027s contents before the call as dead.\n\nKeep inferring readonly, which only says the body does not write, and\nkeep annotating the parameters that just carry the result: an sret, one\nstill marked enzyme_sret or enzyme_sret_v for Enzyme.jl\u0027s calling\nconvention fixup (which relies on writeonly there), a Julia sret union,\nand returnRoots. A marking the function already carries, on a parameter\nor on the function itself, is kept: it was stated deliberately.\n\nA function marked enzyme_custom_full_attributes is exempt: the frontend\nstates that its rule accesses no more than the body does. Enzyme.jl sets\nit for @easy_rule, whose rule only combines the inputs the way the body\ndoes.\n\n\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\nCo-authored-by: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "ae388a550c27d3c3b9d8110fbfdb5f433ab743c6",
      "tree": "eeb2735ae02ee04b0cf1cca3c140169c5c796df0",
      "parents": [
        "b792072756521d0b12b8dec7c0613994f62742ea"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Thu Oct 01 02:41:46 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 21:41:46 2026 -0500"
      },
      "message": "Do not treat local writes or combined-mode origins as overwriting callee data (#3325)\n\n* Do not treat local writes or combined-mode origins as overwriting callee data\n\nWhen computing which callee arguments may be overwritten, a callsite\nchecked the origin of each argument even if nothing can write after the\ncaller returns, unlike is_load_uncacheable which only checks origins when\nsubsequent calls may write. A pointer loaded from memory has an unknown\norigin, so in a top-level combined gradient such an argument was still\npassed down as overwritten.\n\nIn addition, any write after the callsite made subsequent calls in the\ncallee count as writing, including writes to an uncaptured alloca or\nnoalias argument, which no pointer loaded from memory can point to. The\ncallee then had to cache every value loaded through such pointers.\n\nOnly check origins at a callsite if subsequent calls may write, and do not\ncount writes to uncaptured local memory as subsequent writes. As the\ncallee only considers overwritten arguments if subsequent calls may write,\nstill set that when a later write overwrites an argument.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_015RAaewsVwF5wyRBfErBEEr\n\n* Track local writes as overwritten arguments rather than unknown writes\n\nPreviously, a write after a callsite to uncaptured local memory that\noverwrote an argument of the callee also made subsequent calls count as\nwriting, as the callee only honored overwritten arguments if they did. The\ncallee then cached everything loaded through pointers loaded from memory,\nalthough such pointers cannot reach the written local memory.\n\nKeep the two apart: `subsequent_calls_may_write` means an unknown write that\nmay reach any memory, while writes to uncaptured local memory are only\nreflected in the callee\u0027s overwritten arguments. Without unknown writes, a\nload is overwritten only if its origin is an overwritten argument, including\nfor invariant loads.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_015RAaewsVwF5wyRBfErBEEr\n\n* Use notCaptured for local writes, and cover allocations and lifetime markers\n\nReplace the capture walk added here with the existing notCaptured utility\n(Utils.cpp), which the read-only-or-throw detection already uses and whose\nsemantics are the same: comparisons and loads are not captures, stores of\nthe pointer and unknown calls are, nocapture call parameters are not.\n\nTwo fixes to notCapturedBefore that this exposed: a call that did not\ncapture the value returned \"not captured\" for the whole query without\nvisiting the remaining users, and a query on an Argument with no bounding\ninstruction dereferenced a null pointer. It also now takes an optional\nTargetLibraryInfo so that passing the value to a deallocation function is\nnot a capture even when the declaration lacks nocapture.\n\nwritesOnlyUncapturedLocalMemory additionally accepts memory allocated in\nthis function (isAllocationCall), and treats lifetime markers as writing\nnothing at all.\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n---------\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "b792072756521d0b12b8dec7c0613994f62742ea",
      "tree": "a03d9e97563ce60e94cb84b868fc37d3193a33bf",
      "parents": [
        "30d2472f993f62bfe221b1f1c279bc079cb96e7d"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Thu Oct 01 02:39:54 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 20:39:54 2026 -0500"
      },
      "message": "Pass the Fortran ierr argument through forward-mode MPI_Bcast/Send/Recv (#3337)\n\n* Pass the Fortran ierr argument through forward-mode MPI_Bcast/Send/Recv\n\nThe Fortran MPI ABI (mpi_bcast_, mpi_send_, mpi_recv_) appends an ierr\nargument, so the forward-mode calls built with a fixed C arity fail with\n\"Calling a function with bad signature\". Pass all arguments of the\noriginal call, with the shadow in place of the buffer, as MPI_Reduce and\nMPI_Allreduce already do.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01M5d6m8eQfhUdHDMXaDuYq6\n\n* Test forward mode of mpi_bcast_/mpi_send_/mpi_recv_ with the Fortran ABI\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01M5d6m8eQfhUdHDMXaDuYq6\n\n---------\n\nCo-authored-by: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "30d2472f993f62bfe221b1f1c279bc079cb96e7d",
      "tree": "b687c93df760fbc3e2c61c41d02b2906aff645f7",
      "parents": [
        "1e03475740218756ad3c0e00831fd7db248ee501"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Thu Oct 01 02:38:28 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 20:38:28 2026 -0500"
      },
      "message": "Add a derivative for llvm.sincos (#3338)\n\n* Add a derivative for llvm.sincos\n\nLLVM 20 added the llvm.sincos intrinsic, {sin(x), cos(x)}, and forms it\nfrom sin(x) and cos(x) of the same x. Enzyme stopped on it (\"cannot\nhandle unknown intrinsic\").\n\nGive it the rule of __fd_sincos_1: in reverse mode the derivative is\ncos(x) d(sin) - sin(x) d(cos); in forward mode the tangent is\n{cos(x) dx, -sin(x) dx}.\n\nFound differentiating MITgcm (sea-ice dynamics) with LLVM flang.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01KAShV5MVjxfdffSwdhhAVB\n\n* Compute the sincos derivative from one sincos call\n\nReuse the called intrinsic (SameFunc) and extract sin and cos from its\nresult instead of emitting separate llvm.sin and llvm.cos calls.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n---------\n\nCo-authored-by: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "1e03475740218756ad3c0e00831fd7db248ee501",
      "tree": "3cbf578f0f59894626f8f3a5fd56fa0e7d63d095",
      "parents": [
        "0eb888c120da5421e1756d3919832db1966513fb"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Thu Oct 01 02:34:26 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 20:34:26 2026 -0500"
      },
      "message": "Look up the index of an alloca-cached load at the load\u0027s scope (#3348)\n\n* Look up the index of an alloca-cached load at the load\u0027s scope\n\nIn combined mode, lookupM may cache a load from an array alloca inside a\nloop by copying the whole alloca before the loop (EnzymeLoopInvariantCache).\nThe reverse-pass lookup of such a load looked up the GEP indices without the\nrequested scope, i.e. at the insertion block. When the load was looked up\nwhile unwrapping the limit of a later loop nest (getSubLimits in the reverse\npass), the insertion block corresponds to that later nest: fixLCSSA put a\nLCSSA phi of the index into the nest, caching that phi needs the limit of the\nnest again, and lookupM/unwrapM/getSubLimits recursed until the stack\noverflowed. Pass the scope on.\n\nThis made differentiating a checkpointed MITgcm time step in combined mode\nrecurse without end.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n* Make the allocacache-scope test pass on LLVM 16\n\nLLVM 16 lit runs load Enzyme with -opaque-pointers\u003d0 unless the test uses\n%OPnewLoadEnzyme, and name the cache of the load differently.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n* Update GradientUtils.cpp\n\n---------\n\nCo-authored-by: William Moses \u003cgh@wsmoses.com\u003e"
    },
    {
      "commit": "0eb888c120da5421e1756d3919832db1966513fb",
      "tree": "90ce346e311641c2c5becd80c6d1717d4fec89ac",
      "parents": [
        "8f5800ebc951617d4290c1a4d1e0239ca23e6e8d"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Wed Sep 30 21:46:28 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 16:46:28 2026 -0500"
      },
      "message": "Zero the forward shadow of a memcpy from a runtime-inactive source (#3344)\n\nWith runtime activity, a source whose shadow equals its primal is\ninactive, so its float data has a zero derivative. The forward memcpy\nrule copied the primal into the destination shadow instead. Select\nbetween the copy and a memset on that comparison.\n\n\nClaude-Session: https://claude.ai/code/session_015RAaewsVwF5wyRBfErBEEr\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "8f5800ebc951617d4290c1a4d1e0239ca23e6e8d",
      "tree": "3e1b41f34c8c3117382600364143ee2aa93c270a",
      "parents": [
        "3b73bb58c2ae41fff1607baad5b2573381f2d753"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Wed Sep 30 19:17:38 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 14:17:38 2026 -0500"
      },
      "message": "Pass the memcpy\u0027s volatility to the forward shadow memset (#3345)\n\nThe forward rule passed the i1 volatile operand, a Value*, as the bool\nisVolatile argument of CreateMemSet, so the zeroing memset was always\nvolatile. Use the operand\u0027s constant value instead.\n\n\nClaude-Session: https://claude.ai/code/session_015RAaewsVwF5wyRBfErBEEr\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "3b73bb58c2ae41fff1607baad5b2573381f2d753",
      "tree": "0c632336b967b2c0a3f6ce1350ef3bc1a6e8764a",
      "parents": [
        "38520af52dfee92e659144e6ed87bc7b78bda96a"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Wed Sep 30 15:22:00 2026 +0100"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 09:22:00 2026 -0500"
      },
      "message": "Know aligned_alloc as an allocation function (#3339)\n\n* Know aligned_alloc as an allocation function\n\naligned_alloc(alignment, size) is freed by free, like malloc. Its size\nis its second argument: zero the shadow and type a constant-size\nallocation from it.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01M5d6m8eQfhUdHDMXaDuYq6\n\n* Test forward mode through an aligned_alloc buffer\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01M5d6m8eQfhUdHDMXaDuYq6\n\n---------\n\nCo-authored-by: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "38520af52dfee92e659144e6ed87bc7b78bda96a",
      "tree": "2da7448a4ab2777885278d54c7a0de714b68cbd2",
      "parents": [
        "c70b6b4aabbb9c754e0706ee144ba2e9ed3b255c"
      ],
      "author": {
        "name": "Valentin Churavy",
        "email": "v.churavy@gmail.com",
        "time": "Wed Sep 30 06:49:45 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 06:49:45 2026 +0000"
      },
      "message": "Use the shadow of each argument for the shadow of todense (#3281)\n\nThe shadow of `__enzyme_todense(load, store, args...)` passed the shadow of\nthe first argument (the loader) for every extra argument. Pass the shadow\nof each active argument instead, and inactive arguments such as indices as\nthey are.\n\nAssisted-by: Claude Code (Opus 5.5)"
    },
    {
      "commit": "c70b6b4aabbb9c754e0706ee144ba2e9ed3b255c",
      "tree": "d2e30c5b05743a6003d23831dc0e8f6dd9ce2bdb",
      "parents": [
        "302f1aa9e5b752b26f9cd812ce499417b32157d0"
      ],
      "author": {
        "name": "min xu",
        "email": "149007967+minansys@users.noreply.github.com",
        "time": "Wed Sep 30 01:34:50 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Wed Sep 30 01:34:50 2026 +0000"
      },
      "message": "support-clang-21-cuda (#3198)\n\n* support-clang-21-cuda\n\n* Add lit coverage for LLVM 21 NVVM barrier arguments\n\n---------\n\nCo-authored-by: mixu \u003cmixu@synopsys.com\u003e\nCo-authored-by: mixu \u003cmin.xu.8824@gmail.com\u003e"
    },
    {
      "commit": "302f1aa9e5b752b26f9cd812ce499417b32157d0",
      "tree": "c21131db29677a6787e2b3b02b91b0b9176539ed",
      "parents": [
        "b5f52ee55bb20c90d4bb3c3dd17541c62cab7074"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Wed Sep 30 01:31:34 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 29 20:31:34 2026 -0500"
      },
      "message": "Memset to start of block (#3323)"
    },
    {
      "commit": "b5f52ee55bb20c90d4bb3c3dd17541c62cab7074",
      "tree": "6d78a522bb3042c702f1f11670fad527e709122b",
      "parents": [
        "d342169d9d82ccccd27a13d6cde16e95ea341cde"
      ],
      "author": {
        "name": "Joe Wallwork",
        "email": "22053413+joewallwork@users.noreply.github.com",
        "time": "Tue Sep 29 21:54:52 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 29 21:54:52 2026 +0000"
      },
      "message": "Forward mode for Fortran array assignment (#3192)\n\n* Forward mode rule for _FortranAAssign\n\n_FortranAAssign(to, from, sourceFile, sourceLine) is flang\u0027s assignment\nbetween descriptors. It moves data which may include reals, so it cannot be\ndeclared inactive; its derivative is the same assignment applied to the\nshadows.\n\nPassing the shadows straight to the runtime does not work. A shadow is only\nshadow storage: element length, rank, type and the derived type addendum are\nnever written to it, because none of that is differentiated, so the runtime\nreads a zeroed rank and walks off the end. That segfaults inside\nDerivedAssignTicket::Begin.\n\nCopy the primal descriptor over the shadow first, keeping the shadow\u0027s own\nbase_addr, so the runtime is handed a well formed descriptor addressing the\nshadow data. The size comes from the underlying alloca, which is how flang\nemits these; if it cannot be determined the rule declines to handle the call\nand it is reported as underivable rather than guessed at.\n\nWhat this does not do: make Fortran derived type assignment differentiate\ncorrectly end to end. On the DVODE reproducer the program now links and runs to\ncompletion where it previously crashed, but the result is still wrong. That is\nupstream of this rule -- disabling just the shadow call leaves the primal\ntrace equally corrupt (garbage rather than zeros), so the generated code is\nbeing broken by the surrounding type ambiguity that -enzyme-loose-types papers\nover, not by the assignment.\n\nRelated: EnzymeAD/Enzyme#2963, which scaffolds Fortran intrinsic dispatch but\nleaves descriptor handling as a TODO.\n\nCo-Authored-By: Claude Opus 5 \u003cnoreply@anthropic.com\u003e\n\n* Add norm test for forward mode to test _FortranAAssign\n\n* Apply clang-format\n\n* Fix signature for norm and its derivative\n\n* Update test notes\n\n* Initialize _FortranAAssign shadow descriptor metadata\n\nflang builds descriptors from a constant struct template, whose integer\nfields type analysis only knows as Anything. The shadow of that template\nzeroes them, so the shadow descriptor reached the runtime with a zero\nelement length, version, rank and type. Instead of copying the primal\ndescriptor over the shadow before the call, make the shadow correct when\nit is written:\n\n- Type analysis rule for _FortranAAssign marking the descriptor header,\n  and the dims when the rank is known from the allocation type, as\n  integral.\n- In forward mode, a store into memory known to hold only integers\n  writes the primal value to the shadow, as its shadow mirrors the\n  primal.\n\nThe forward norm tests seeded dx \u003d 1, for which dy is exactly zero and\na broken shadow assignment still passed; seed a single direction so the\nexpected derivative is nonzero.\n\nAssisted-by: Claude Code (Opus 5.5)\n\n* Trim comments\n\nAssisted-by: Claude Code (Opus 5.5)\n\n---------\n\nCo-authored-by: Valentin Churavy \u003cv.churavy@gmail.com\u003e\nCo-authored-by: Claude Opus 5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "d342169d9d82ccccd27a13d6cde16e95ea341cde",
      "tree": "dd1fd8d224f362e36074926c17328eb391cf4950",
      "parents": [
        "535d7b4a9b4f89b8f2e3586f1b84a3cc7ced409d"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Tue Sep 29 21:18:20 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 29 16:18:20 2026 -0500"
      },
      "message": "Rewrite negating loop recurrences in closed form during preprocessing (#3322)\n\nA header phi that is negated every iteration, x_{i+1} \u003d -x_i (the\nalternating sign of a cofactor expansion), is not an add recurrence, so\nscalar evolution cannot classify it and the reverse pass cached the value\n(or a condition on it) once per iteration. Its value at iteration I is\nx_0 * (1 - 2 * (I mod 2)); RemoveRedundantIVs now rewrites it in that\nform, built from the canonical induction variable in the phi\u0027s own type,\nso it is recomputed instead.\n\nIn GradBench\u0027s det eval (recursive cofactor expansion) this removes one\nof the five tape allocations per recursive call and makes the gradient\nabout 1.5x faster at ell\u003d9.\n\n\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "535d7b4a9b4f89b8f2e3586f1b84a3cc7ced409d",
      "tree": "e73fe73ab920d1b4c0d9b708330fcfafd8ce1383",
      "parents": [
        "842c5da17afd84686d88c04546eea24a4c4f07eb"
      ],
      "author": {
        "name": "aokblast",
        "email": "aokblast@FreeBSD.org",
        "time": "Tue Sep 29 17:21:43 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 29 12:21:43 2026 -0500"
      },
      "message": "[MLIR] Map maximum and maxnum op to shadow space (#3313)\n\nSame as minimum, ConstantFP should use the shadow type of x instead of\nthe primal type. If not, MLIR verification fails in batched mode (i.e.\nwidth \u003e 1)."
    },
    {
      "commit": "842c5da17afd84686d88c04546eea24a4c4f07eb",
      "tree": "83f03e33763ee8e8fd39df631170ea03b69f59da",
      "parents": [
        "3385960d55741929f15ef3ab5e5b7c4f149c8bcc"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Tue Sep 29 17:21:30 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 29 12:21:30 2026 -0500"
      },
      "message": "Mark statically known loop limits as required in the min-cut cache (#3320)\n\ncomputeMinCache marks loop limits as required values, but it ran before any\nloop context existed, so no limit was ever marked. When SCEV expanded a limit\nto a different value than the one the loop\u0027s exit compare used (e.g. `add %n,\n0` folded to `%n`), the split reverse pass recomputed the limit from values\nthat had been erased, such as an inactive Julia allocation, leading to\n\"Illegal replace ficticious phi\".\n\nCompute the contexts of loops with a statically known limit before the\nmin-cut. Loops with a dynamic limit are skipped, as creating their limit cache\nrequires the recompute heuristic the min-cut computes. The limit computation\nis factored out of getContext into computeLoopLimit for this.\n\n\nClaude-Session: https://claude.ai/code/session_015RAaewsVwF5wyRBfErBEEr\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "3385960d55741929f15ef3ab5e5b7c4f149c8bcc",
      "tree": "cf307cf9eebdf1263c8bdb61e39e448f10d36d7e",
      "parents": [
        "dbf841057177040efe806b5cd49290eaf79f4ea7"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Tue Sep 29 05:33:35 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Tue Sep 29 00:33:35 2026 -0500"
      },
      "message": "Propagate Lookup types for constant-size allocation functions in TypeAnalysis (#3312)"
    },
    {
      "commit": "dbf841057177040efe806b5cd49290eaf79f4ea7",
      "tree": "a88907380aea4396a9b1224698cdfdcb423202fc",
      "parents": [
        "cdc99eff60b4df63bd9dbf0103bb064c96061a71"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Tue Sep 29 00:06:57 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 19:06:57 2026 -0500"
      },
      "message": "Define host_mem_type in customglob.cpp integration test (#3309)\n\nThe test JITs the module with lli, and square() loads host_mem_type to\npass it to the noinline alloc(). With only an extern declaration the\nsymbol is never defined, so lli fails with\n\u0027Symbols not found: [ host_mem_type ]\u0027."
    },
    {
      "commit": "cdc99eff60b4df63bd9dbf0103bb064c96061a71",
      "tree": "0a36bf5771808b0ee05812428e515a8bf316d49c",
      "parents": [
        "7be99cd9489e30c8ca5730b4b1b1a26c753bdd76"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Mon Sep 28 23:47:18 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 18:47:18 2026 -0500"
      },
      "message": "Carry enzyme_truetype onto forward-mode shadow memset/memcpy/memmove (#3277)\n\nThe shadow of an annotated memset/memcpy/memmove was emitted without the\nannotation, so differentiating a forward-mode derivative again (e.g.\nreverse-over-forward) could not type a shadow copy past the type analysis\noffset limit. Since the shadow is emitted per run of like-typed bytes, each\nshadow call gets the part of the annotation covering its own bytes, rebased to\nwhere it starts.\n\n\nClaude-Session: https://claude.ai/code/session_015RAaewsVwF5wyRBfErBEEr\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "7be99cd9489e30c8ca5730b4b1b1a26c753bdd76",
      "tree": "12913118a8be2dd397f6343838b7a45f08c3c75e",
      "parents": [
        "b645d425865a5bbe9ff64e2f0d6a948bce334204"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Mon Sep 28 23:45:07 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 18:45:07 2026 -0500"
      },
      "message": "Do not require the start value of a select reduction in the reverse pass (#3308)\n\nThe loopy-reduction check marks the start (preheader) value of a header\nphi as needed in the reverse pass when the phi\u0027s only active user is an\nfdiv or a select that forms the next iteration\u0027s value. The fdiv form\u0027s\nreverse (z_i \u003d z_start / prod) reads the start value, but the select\nform\u0027s reverse only uses the index of the last iteration that selected a\nnew element and never reads the start value\u0027s primal. Requiring it for\nselects caches a value nothing uses (e.g. the start of a running max that\ncannot be recomputed), so restrict the check to the fdiv form.\n\n\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "b645d425865a5bbe9ff64e2f0d6a948bce334204",
      "tree": "3ae167bc7bf92676b51d9c3924264985c3513d1a",
      "parents": [
        "32f0af0dec46b50b90bde1dc4b738192e85e7c14"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Mon Sep 28 23:44:27 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 18:44:27 2026 -0500"
      },
      "message": "Backstack lowering: cast the moved object back into a derived phi (#3293)\n\nLowerAllocAddr moves an allocation marked enzyme_backstack back to the stack\nafter differentiation and rewrites the users of its Julia-address-space\npointer. A phi was only rewritten when all its incoming values derive from the\nmoved object; one that also merges pointers from elsewhere was rejected with\n\"Illegal address space propagation\". When the phi is a derived (not tracked)\npointer, cast the moved object back to its address space in the incoming\nblock: Julia\u0027s GC lowering treats a cast from the default address space as an\nuntracked base. A tracked phi would root the stack memory, so stays an error.\n\nFixes EnzymeAD/Enzyme.jl#3701.\n\n\nClaude-Session: https://claude.ai/code/session_015RAaewsVwF5wyRBfErBEEr\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "32f0af0dec46b50b90bde1dc4b738192e85e7c14",
      "tree": "52ae8ff12e74f1b54163bdeabed61553c0dae236",
      "parents": [
        "dd8ea95cb9607aa0c54baec192a8e37bb86e79cf"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Mon Sep 28 23:43:31 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 18:43:31 2026 -0500"
      },
      "message": "Do not reuse a cached load across nested loops (#3298)\n\n* Do not reuse a cached load across nested loops\n\nlookupM reuses the cache of an earlier load from the same object when both\naddresses are add recurrences with the same start, step and trip count. That\nmatches their values iteration by iteration only when the recurrences are over\nthe same loop or over loops that do not contain one another. For nested loops\n-- x[i] and x[j] in `for i, for j` -- the outer recurrence stays fixed while\nthe inner one moves, so the reverse pass read x[i] where it needed x[j]. The\nsame check guards the shared-memory store forwarding.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_015RAaewsVwF5wyRBfErBEEr\n\n* Leave the shared-memory store forwarding unchanged\n\nIts loop walk already rejects a store whose loop is the load\u0027s loop or an\nancestor of it, and forwarding from a store in a loop nested inside the\nload\u0027s is valid there: the stored value is recomputed with the inner\ninduction variable replaced by the outer one.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_015RAaewsVwF5wyRBfErBEEr\n\n---------\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "dd8ea95cb9607aa0c54baec192a8e37bb86e79cf",
      "tree": "47b952c0b0f58ed0e30472eaf8f36000b50be627",
      "parents": [
        "619b0ada41c746ef96c69412ae5d011449edb1c4"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Mon Sep 28 20:25:23 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 15:25:23 2026 -0500"
      },
      "message": "Backstack lowering: rewrite a select like a phi (#3301)\n\n* Backstack lowering: rewrite a select like a phi\n\nLowerAllocAddr moves an allocation marked enzyme_backstack back to the stack\nafter differentiation and rewrites the users of its Julia-address-space\npointer. A select was rejected with \"Illegal address space propagation\". This\narises when the reverse pass recomputes a two-way phi as a select.\n\nHandle it as the phi is: when both operands derive from the moved object,\ncreate a new select in the new address space and continue from its users;\notherwise, once only merges remain pending, cast the moved object back to the\nselect\u0027s address space when that is a derived (not tracked) one.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_015RAaewsVwF5wyRBfErBEEr\n\n* Keep the select\u0027s partial case an error, as for the phi\n\nOnly rewrite a select whose operands both derive from the moved object;\ncasting the moved object back into a select that also chooses a pointer from\nelsewhere is left to the separate phi change.\n\nCo-Authored-By: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_015RAaewsVwF5wyRBfErBEEr\n\n---------\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "619b0ada41c746ef96c69412ae5d011449edb1c4",
      "tree": "488a7052c808a8864b08f5a8021476c9e63e3bfd",
      "parents": [
        "f706b654865f3e2e123b1046b7b374d55070a3fd"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Mon Sep 28 19:38:04 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 14:38:04 2026 -0500"
      },
      "message": "Type untyped bytes of a constant store from the stored value in forward mode (#3300)\n\nSince the constant type analysis no longer ORs a data sequential\u0027s\nelement types into the whole value, the zero lanes of a constant vector\nsuch as \u003c2 x double\u003e \u003c10.0, 0.0\u003e are typed Anything, which is not\npropagated to memory. A forward-mode store of that constant into memory\nthat nothing else types then failed with \u0027Cannot deduce type of store\u0027.\nFall back to the stored value\u0027s own type for bytes the destination does\nnot type.\n\n\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\nCo-authored-by: Claude Opus 5.5 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "f706b654865f3e2e123b1046b7b374d55070a3fd",
      "tree": "9b0cddedf07b6ab62ce17621cfccc0577ca992b8",
      "parents": [
        "211923c20b6b70851f69ceeb25009a9338d1af8f"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Mon Sep 28 18:25:06 2026 +0000"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Mon Sep 28 13:25:06 2026 -0500"
      },
      "message": "Fix Bazel layering, -Warray-bounds/-Wparentheses; run activity.c via clang plugin (#3297)\n\n- BUILD: add missing llvm:TargetParser deps (Utils.h now includes\n  llvm/TargetParser/Triple.h), export Enzyme/PassUtils.h from EnzymeMLIR\n  (included by TypeAnalysis/TypeAnalysisPrinter.h), and add\n  mlir:AffineUtils / mlir:DataLayoutInterfaces deps used by the MLIR\n  implementations. Required when building with layering_check.\n- PreserveNVVM.cpp: use `else if constexpr` for the ForwardMode /\n  ForwardModeSplit branches so Fs[2] is not instantiated when numargs\u003d\u003d2\n  (-Warray-bounds).\n- RemovalUtils.h: parenthesize assignment in while condition\n  (-Wparentheses).\n- test/Integration/ForwardMode/activity.c: run Enzyme through the clang\n  plugin (%loadClangEnzyme -mllvm ...) instead of piping to opt, so the\n  --enzyme-load-inactive-file options reach the Enzyme pass that actually\n  differentiates the program (e.g. when clang has Enzyme linked in)."
    },
    {
      "commit": "211923c20b6b70851f69ceeb25009a9338d1af8f",
      "tree": "d6d182144c7dbd3d47051c9897de31283977d397",
      "parents": [
        "003a476a619aba5ec4a90483316abc5eeb6b1683"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Sun Sep 27 20:44:27 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 27 20:44:27 2026 -0500"
      },
      "message": "Rewrite counted-loop accumulators in closed form during preprocessing (#3271)\n\n* Rewrite counted-loop accumulators in closed form during preprocessing\n\nA running index into a triangle,\n\n  int idx \u003d 0;\n  for (i \u003d 0; i \u003c d; i++)\n    for (j \u003d i + 1; j \u003c d; j++)\n      ... l[idx++] ...\n\nreaches the outer header, after loop rotation, through a phi that merges\n\"inner loop skipped\" with the inner loop\u0027s exit value. Scalar evolution\ncannot classify that phi, and legalRecompute rejects it as a recursive\nheader phi, so the reverse pass stored idx once per outer iteration: on\nGradBench\u0027s GMM that was a d*k*n int32 tape (26 MB at d\u003d64) for a value\nthat is a quadratic in i.\n\nRemoveRedundantIVs already rewrites header phis SCEV can express in terms\nof the canonical induction variable. When SCEV gives up, now derive the\nrecurrence ourselves: take each arm of the latch phi at the scope of the\nloop, so an inner loop\u0027s value becomes its exit value, subtract the phi,\nand require the difference to be one step that is invariant or affine in\nthe loop\u0027s counter. An arm that carries the phi unchanged must contribute\nzero, shown in two halves: the step is never negative (SCEV\u0027s induction\nproof, or monotonicity checked at the last iteration), and on the skipping\nedge it is non-positive, because it equals the guard\u0027s own difference up to\na constant. To make the latter visible the skipping edge is split into its\nown block before scalar evolution is built. The resulting {Init,+,A,+,B} is\nexpanded as Init + A*i + B*i*(i-1)/2 in the accumulator\u0027s type, with the\ntriangular term formed as (i/2)*(i-1) + (i%2)*((i-1)/2) so no wider type is\nneeded; going through evaluateAtIteration instead produces an i65 binomial\nthat IndVarSimplify turns straight back into a loop-carried phi.\n\nBoth steps have flags (enzyme-split-skip-edges, enzyme-rewrite-accumulators).\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n* Restrict the accumulator rewrite to integer phis and use the portable branch helpers\n\nA pointer-typed header phi (the LSTM benchmark carries a running pointer)\nmade getMinusSCEV return CouldNotCompute, which SCEVExprContains then\nrefused to walk. Only integer counters have a closed form to expand, so\nrequire that, and also skip an arm whose difference is CouldNotCompute.\n\nLLVM 24 split BranchInst into CondBrInst and UncondBrInst and renamed\nSCEV::FlagAnyWrap to FlagNone; use Enzyme\u0027s isConditionalBranch and\ngetBranchCondition helpers and guard the flag spelling.\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n* Close quadratic recurrences before SCEVExpander expands them\n\nSCEVExpander expands an add recurrence with more than two operands\nliterally, as nested loop-carried phis, because the closed form through\nevaluateAtIteration would need a canonical IV one bit wider than the\nvalue. When RemoveRedundantIVs rewrites an inner-loop phi whose start is\nquadratic in the outer induction variable (e.g. i*(2*d-i-1)/2 for a\nrunning index into a triangle), the expansion therefore introduces a new\nouter-loop phi with a varying step, which the reverse pass then caches\nonce per outer iteration.\n\nFactor the wide-type-free closed form used for counted accumulators into\nclosedFormOfRecurrence and apply it, through a SCEV rewriter, to every\nquadratic recurrence inside a phi\u0027s expression before expanding it.\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n* Build with SCEVUse operands and run the accumulator test in opaque-pointer mode\n\nRecent LLVM represents add recurrence operands as SCEVUse, so the\nquadratic rewriter now delegates operand rewriting to SCEVRewriteVisitor\ninstead of assembling a SmallVector\u003cconst SCEV *\u003e itself, and the no-wrap\nflag type is named through decltype since its enumerator was renamed in\nLLVM 24. The test uses opaque pointers, so it must not run with\n-opaque-pointers\u003d0 on LLVM 16.\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n* Read the skip guard off the edge instead of splitting it\n\nThe accumulator rewrite only needed the skipping edge to have its own\nblock so that the branch guarding it could be found through the block\u0027s\nsingle predecessor. Look at the terminator of the incoming block itself,\nwhich is that branch whenever the edge is a direct one, and keep the\npredecessor lookup for blocks that merely carry the edge. This removes\nthe enzyme-split-skip-edges preprocessing and its option.\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n* Add evaluateAtIterationWithoutExt and use it for recurrences up to degree three\n\nSCEVAddRecExpr::evaluateAtIteration forms I*(I-1)/2 through\nBinomialCoefficient in a type one bit wider than the recurrence, and\nSCEVExpander then materializes a canonical induction variable of that\nwider type, a new loop-carried phi that the reverse pass has to cache.\nThe closed form the accumulator rewrite used instead is now a shared\nhelper in Utils that stays in the wider of the recurrence\u0027s and the\niteration number\u0027s own types: it halves whichever of I and I-1 is even\nand divides by three through the multiplicative inverse, so degree two\nand three are exact without widening. Higher degrees fall back to LLVM.\n\nThe rewriter of non-affine recurrences now covers cubic ones, and the\nother places that evaluated a recurrence at an iteration (loop bound\ncomputation in Utils and evaluateAtLoopIter in FunctionUtils) go through\nthe helper as well, which is identical to LLVM\u0027s for affine recurrences.\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n---------\n\nCo-authored-by: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "003a476a619aba5ec4a90483316abc5eeb6b1683",
      "tree": "b91026c180721829839043210069a221e99c4367",
      "parents": [
        "6c9e0859d7e5464d2598b314445d1af9a0e3687c"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Sun Sep 27 20:32:46 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 27 20:32:46 2026 -0500"
      },
      "message": "Read-only-or-throw: account for what a local callee writes through its sret (#3276)\n\n* Account for what a local read-only-or-throw callee writes through\n\nDetectReadonlyOrThrowFn skipped every call to a callee marked\nenzyme_LocalReadOnlyOrThrow, although such a callee writes through its\nsret-like arguments and those writes land in the caller\u0027s memory. When a\ncaller passes its own sret straight through (which call-slot optimization\nproduces from an alloca plus memcpy), it was marked fully read-only-or-throw:\nmemory(read, inaccessiblemem: readwrite) and, since its sret was writeonly,\na readnone sret. LLVM then dropped the result (Enzyme.jl\u0027s Comrade\nintegration test computed an all-zero gradient, Molly a garbage one).\n\nClassify the memory behind each sret-like argument of such a call the way a\nstore of the caller\u0027s own is classified: an alloca or an allocation of the\ncaller\u0027s is fine, the caller\u0027s own sret-like argument makes it local, and\nanything else disqualifies it.\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01Ea7crZWWVZquQK6aqPdZCq\n\n* Activity: an sret-like value not local to the function is judged by its own activity\n\nThe induction that proves a call to a local read-only-or-throw callee\nconstant from a lack of active users of its sret-like arguments only makes\nsense when that memory is local to the function (an alloca or an\nallocation). When the base is the function\u0027s own sret argument passed\nstraight through, a global, or a loaded pointer, whoever owns it reads it\nafter we return, so its users here say nothing: a wrapper that forwarded\nits sret to the callee had that call found constant (its sret argument\u0027s\nonly user was the call itself) and Enzyme.jl\u0027s Comrade integration test got\nan all-zero gradient. Go by the value\u0027s own activity for such bases.\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01Ea7crZWWVZquQK6aqPdZCq\n\n---------\n\nCo-authored-by: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "6c9e0859d7e5464d2598b314445d1af9a0e3687c",
      "tree": "64eee63e21ef7cc6f5771e13e1cf866a51e77445",
      "parents": [
        "411fc52c790f104b9c52245d4f5dfd9a82bec419"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Sun Sep 27 19:09:45 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 27 19:09:45 2026 -0500"
      },
      "message": "Do not cache loads because of a call that only writes on paths that throw (#3273)\n\n* Do not cache loads because of a call that only writes on paths that throw\n\nDeciding whether a load\u0027s value must be taped for the reverse pass ends in\nLLVM alias analysis: does any later instruction modify the location? For\na call, that fails as soon as the callee has no memory attributes and the\nlocation\u0027s pointer is not an identified object. Both hold in GradBench\u0027s\nGMM: log_wishart_prior is never inferred readonly by LLVM (its lgamma call\nis only attributed inside Enzyme\u0027s own preprocessing), and every buffer is\na std::vector, whose data pointer is a phi of the allocation and null. So\nthe one call after the loop nest forced every load of Qdiags, sum_qs,\nmain_term and Qxcentered inside the nest to be taped: an extra n*k*d\ndoubles, 51 MB at d\u003d64, for arrays that are never written there.\n\nEnzyme\u0027s own DetectReadonlyOrThrow had already concluded the callee only\nwrites pre-existing memory on paths that then throw. For a plain call that\nis as good as readonly for this question: the throw leaves the function,\nso nothing after the call runs, including the reverse pass. (An invoke\u0027s\nlanding pad could observe such a write, so invokes are left to alias\nanalysis.) Consult that attribute in writesToMemoryReadBy.\n\nGMM at d\u003d64, k\u003d100, n\u003d1000 drops from 190 ms to 166 ms, now below\nTapenade\u0027s 194 ms in the same run; d\u003d10 from 5.0 ms to 4.6 ms. Identical\noutput.\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n* Update three tests for loads no longer taped across ReadOnlyOrThrow calls\n\nconst_value_active_call: the pointer loaded before the call to g is now\nreloaded in the reverse pass instead of taped, so augmented_f\u0027s tape loses\nthat entry and diffef reloads it.\n\ninsertshadow: the caching decision now consults enzyme_ReadOnlyOrThrow\ndirectly, so LLVM 15 produces the same reloads as LLVM 16 and later; fold\nthe two version-specific blocks back into one.\n\nptrstoreuse: with the blocking helpers known not to write, the min-cut\nrecomputes the loop guards from reloaded values rather than taping them,\nand the tape keeps the two promoted allocations and one block size instead.\nThe Eigen program this was extracted from (eigensumsqdyn.cpp) still runs\ncorrectly with the plugin on LLVM 15 and 20 at -O1, -O2 and -O3.\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n* Run the ReadOnlyOrThrow tests in opaque-pointer mode\n\nBoth tests are written with opaque pointers. The LLVM 16 CI forces\n-opaque-pointers\u003d0 through %newLoadEnzyme, so they could not parse there;\nuse %OPnewLoadEnzyme instead. The attrs test also passed -opaque-pointers\nexplicitly, a flag that no longer exists on recent LLVM, so it failed to\nrun at all on LLVM 17 and later.\n\nCo-Authored-By: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_01RzKKhifUUoQ4icPtPHwWY1\n\n---------\n\nCo-authored-by: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "411fc52c790f104b9c52245d4f5dfd9a82bec419",
      "tree": "c0076269af46b8593ce92bc9fa5e664e3009cfbd",
      "parents": [
        "49237ae21ee0cf8197d8ebd829b576bb48f4ef5d"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Sun Sep 27 16:05:01 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 27 16:05:01 2026 -0500"
      },
      "message": "Julia calling convention: drop no-write memory attributes when adding an sret (#3270)\n\nA reverse-pass callee that only reads the shadow it receives through an\nenzyme_sret argument can legitimately be readonly (argmemonly readonly on\nLLVM 15, memory(argmem: read) later). The fixup then returns that shadow\ntogether with the result through an sret, so the rewritten function\nwrites argument memory, but its function attributes and those of the\nrewritten call sites were copied verbatim. LLVM subsequently treated the\ncall as readonly and forwarded the caller\u0027s zero-initialization of the\nsret buffer past it, so the result read back as zero.\n\nThis is EnzymeAD/Enzyme.jl#3679: on Julia 1.10, jacobian(Reverse, ...)\nof `a \u0026\u0026 b ? (log(x), log(y)) : ...` returned 0 while gradient (combined\nmode) and Julia 1.11+ were right. On 1.11 the callee still stored zeros\ninto the shadow, so it was memory(argmem: readwrite) to begin with.\n\nWhen the rewrite adds an sret or roots parameter, allow argument-memory\nwrites in the function\u0027s memory effects (add argmem: mod on LLVM 16+;\ndrop readnone, readonly and inaccessiblememonly before), both on the\nfunction and on the rewritten calls. Reads are unchanged, so writeonly\nstays valid. enzyme_ReadOnlyOrThrow, which rules out writes visible to\nthe caller, becomes enzyme_LocalReadOnlyOrThrow, which the detection\npass itself uses for functions that write an sret or returnRoots.\n\n\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\nCo-authored-by: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e"
    },
    {
      "commit": "49237ae21ee0cf8197d8ebd829b576bb48f4ef5d",
      "tree": "66a4d0380acdd03d1884f900d9f638ff5e7170a3",
      "parents": [
        "b75494d5324fc21fbca98d0293161dbeb2276c15"
      ],
      "author": {
        "name": "William Moses",
        "email": "gh@wsmoses.com",
        "time": "Sun Sep 27 14:30:04 2026 -0500"
      },
      "committer": {
        "name": "GitHub",
        "email": "noreply@github.com",
        "time": "Sun Sep 27 14:30:04 2026 -0500"
      },
      "message": "Type analysis: check a callee\u0027s parameter enzyme_type against the parameter (#3272)\n\nconsiderTBAA checks that an enzyme_type annotation only names offsets\nwithin the annotated value. For the annotations carried by the called\nfunction\u0027s parameters it compared against the size of the call\u0027s result\ninstead of the parameter, so a by-value aggregate parameter (a 64-byte\nJulia struct passed to setproperty!) failed against the 8-byte pointer\nthe call returns and aborted the process with \"Canonicalization failed\"\n(EnzymeAD/Enzyme.jl#3604).\n\nUse the argument\u0027s size there, as the call-site attributes already do,\nand fold the five copies of the check into one helper that reports a\ngenuine violation through the error handler as an IllegalTypeAnalysis\nerror before failing, so a frontend can turn it into a catchable error.\n\n\nClaude-Session: https://claude.ai/code/session_01G84mmXoaait2MBqCH5BKNb\n\nCo-authored-by: Claude Fable 5.1 \u003cnoreply@anthropic.com\u003e"
    }
  ],
  "next": "b75494d5324fc21fbca98d0293161dbeb2276c15"
}
