)]}'
{
  "commit": "7feb6b16ae99fb8b342b92b7f63b311ffc5d3574",
  "tree": "2eefa0bb3373d4b46eb1a6a6447ede89241c7b70",
  "parents": [
    "dd8ea95cb9607aa0c54baec192a8e37bb86e79cf"
  ],
  "author": {
    "name": "Valentin Churavy",
    "email": "v.churavy@gmail.com",
    "time": "Mon Sep 28 23:24:40 2026 +0200"
  },
  "committer": {
    "name": "Valentin Churavy",
    "email": "v.churavy@gmail.com",
    "time": "Mon Sep 28 23:32:48 2026 +0200"
  },
  "message": "Cache only the last-iteration value of loop PHIs used after loop exit\n\nIn split mode (augmented forward + reverse), a loop header PHI chosen to be\ncached is stored once per iteration of its loop. When the loop is not rotated,\na running reduction (e.g. `s` in `for (...) s +\u003d x[i]*x[i]; return sqrt(s);`)\nis the header PHI itself and is used after the loop exits. The reverse pass\nthen only ever reads the entry of the final iteration, yet the tape holds\ntrip-count + 1 values (per iteration of any enclosing loop). For a mag() call\ninside an O(n) loop this made the tape O(n^2) (2 GB at n \u003d 16000).\n\nA use outside the PHI\u0027s loop can only observe the value of the PHI\u0027s last\nexecution before the loop was exited (by dominance the use follows the loop\nwithin the same iteration of every enclosing loop, and the loop cannot be\nre-entered without a new iteration of the enclosing loop), independent of\nthe number of exits. So, if no reverse-pass computation inside the loop needs\nthe PHI, it suffices to keep one slot per iteration of the enclosing loops\nthat is overwritten on every iteration; the slot holds the exit value.\n\ncomputeMinCache (augmented pass only) records such PHIs in\ncacheOnlyLastIteration: cached (knownRecomputeHeuristic \u003d\u003d false), non-pointer\nheader PHIs, not needed for loop bounds, all of whose in-loop users are\nnon-terminator, non-memory, non-pointer instructions that neither use the PHI\ndirectly in their adjoint nor are needed in the reverse pass. For these,\ncacheForReverse uses the loop preheader as cache scope (a plain tape value if\nthe loop is outermost). The decision is stored in AugmentedReturn and reused\nby the reverse pass and the split forward-mode derivative, so all tape users\nagree on the layout. Anything else keeps the previous behaviour. Combined\nmode is unaffected (it already uses fixLCSSA\u0027s manual_lcssa phi).\n\nOn the reproducer (normalize/mag with only SROA before Enzyme, n \u003d 16000):\npeak RSS 1956 MB -\u003e 12 MB, gradient/primal time 5.9x -\u003e 1.2x, identical\ngradient.\n\nCo-Authored-By: Claude Opus 5.5 (1M context) \u003cnoreply@anthropic.com\u003e\nClaude-Session: https://claude.ai/code/session_019RNZGgCdK1fbT2WPQpR7Br\n",
  "tree_diff": [
    {
      "type": "modify",
      "old_id": "b259d3c1cbb6c4caa5791887b21616adc43f03ee",
      "old_mode": 33188,
      "old_path": "enzyme/Enzyme/EnzymeLogic.cpp",
      "new_id": "07d3475c1c2fee2eaaaedf511158422a524b8408",
      "new_mode": 33188,
      "new_path": "enzyme/Enzyme/EnzymeLogic.cpp"
    },
    {
      "type": "modify",
      "old_id": "5491e0bc38d04fe664727a7e2fdb84499f15bfdc",
      "old_mode": 33188,
      "old_path": "enzyme/Enzyme/EnzymeLogic.h",
      "new_id": "b30045a9d142c69e86a8f467e5a53225a5c9f245",
      "new_mode": 33188,
      "new_path": "enzyme/Enzyme/EnzymeLogic.h"
    },
    {
      "type": "modify",
      "old_id": "1b2838cee85cd4b2aa2339b293f17b581d68693b",
      "old_mode": 33188,
      "old_path": "enzyme/Enzyme/GradientUtils.cpp",
      "new_id": "18660b41d7e797ed2afc846321e524093de106a6",
      "new_mode": 33188,
      "new_path": "enzyme/Enzyme/GradientUtils.cpp"
    },
    {
      "type": "modify",
      "old_id": "f023b8f97ad24b29eb1968ad9d6c74e6a5625d75",
      "old_mode": 33188,
      "old_path": "enzyme/Enzyme/GradientUtils.h",
      "new_id": "d517f7d4bf1d633445fc18be1a3fe5cb5c87665e",
      "new_mode": 33188,
      "new_path": "enzyme/Enzyme/GradientUtils.h"
    },
    {
      "type": "add",
      "old_id": "0000000000000000000000000000000000000000",
      "old_mode": 0,
      "old_path": "/dev/null",
      "new_id": "e0fe37d1a096c843a3538ae562a83550fba500a5",
      "new_mode": 33188,
      "new_path": "enzyme/test/Enzyme/ReverseMode/loopexitcache.ll"
    },
    {
      "type": "modify",
      "old_id": "414ee1d9f8554eb565c1638fc6917fd5a2e81d5a",
      "old_mode": 33188,
      "old_path": "enzyme/test/Enzyme/ReverseMode/mincutoneneed.ll",
      "new_id": "0e01bc44c8f0b0b3eb068eaa1a6b1fe20d8d4181",
      "new_mode": 33188,
      "new_path": "enzyme/test/Enzyme/ReverseMode/mincutoneneed.ll"
    }
  ]
}
