ttsem 0.1.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (182) hide show
  1. ttsem-0.1.0/.gitignore +36 -0
  2. ttsem-0.1.0/CITATION.cff +19 -0
  3. ttsem-0.1.0/CONTRIBUTING.md +25 -0
  4. ttsem-0.1.0/LEDGER.md +133 -0
  5. ttsem-0.1.0/LICENSE +21 -0
  6. ttsem-0.1.0/PKG-INFO +386 -0
  7. ttsem-0.1.0/README.md +353 -0
  8. ttsem-0.1.0/audits/kernelbench/README.md +116 -0
  9. ttsem-0.1.0/audits/kernelbench/prepare.py +192 -0
  10. ttsem-0.1.0/audits/kernelbench/table.py +156 -0
  11. ttsem-0.1.0/audits/tritonbench/README.md +124 -0
  12. ttsem-0.1.0/audits/tritonbench/agree.py +87 -0
  13. ttsem-0.1.0/audits/tritonbench/device.py +194 -0
  14. ttsem-0.1.0/audits/tritonbench/device_runner.py +174 -0
  15. ttsem-0.1.0/audits/tritonbench/manifest.py +54 -0
  16. ttsem-0.1.0/audits/tritonbench/prepare.py +133 -0
  17. ttsem-0.1.0/audits/tritonbench/table.py +116 -0
  18. ttsem-0.1.0/docs/AGENTS.md +48 -0
  19. ttsem-0.1.0/docs/DESIGN.md +425 -0
  20. ttsem-0.1.0/docs/INDUCTOR.md +113 -0
  21. ttsem-0.1.0/docs/JUDGE.md +159 -0
  22. ttsem-0.1.0/docs/OVERVIEW.md +118 -0
  23. ttsem-0.1.0/docs/RESULTS.md +850 -0
  24. ttsem-0.1.0/docs/SEMANTICS.md +565 -0
  25. ttsem-0.1.0/examples/ci/test_scale.py +22 -0
  26. ttsem-0.1.0/examples/e11601_min.mlir +19 -0
  27. ttsem-0.1.0/examples/e11601_repro.py +42 -0
  28. ttsem-0.1.0/examples/e11612_kernel_min.mlir +35 -0
  29. ttsem-0.1.0/examples/e11612_repro_min.mlir +22 -0
  30. ttsem-0.1.0/examples/e15_11519_main_e1f944a7a.json +635 -0
  31. ttsem-0.1.0/examples/e15_11519_min.mlir +33 -0
  32. ttsem-0.1.0/examples/e15_repro.py +48 -0
  33. ttsem-0.1.0/examples/e2_repro.py +41 -0
  34. ttsem-0.1.0/examples/inductor_models.py +100 -0
  35. ttsem-0.1.0/examples/inductor_models2.py +144 -0
  36. ttsem-0.1.0/examples/witness_e8m0_nan.py +41 -0
  37. ttsem-0.1.0/examples/witness_interp_bf16_add.py +38 -0
  38. ttsem-0.1.0/pyproject.toml +139 -0
  39. ttsem-0.1.0/tests/conftest.py +201 -0
  40. ttsem-0.1.0/tests/fixtures/agents/accumulate_into_empty.py +23 -0
  41. ttsem-0.1.0/tests/fixtures/agents/add_no_load_mask.py +35 -0
  42. ttsem-0.1.0/tests/fixtures/agents/add_no_store_mask.py +35 -0
  43. ttsem-0.1.0/tests/fixtures/agents/add_ok.py +35 -0
  44. ttsem-0.1.0/tests/fixtures/agents/cuda_script.py +22 -0
  45. ttsem-0.1.0/tests/fixtures/agents/suite_big_launch.py +24 -0
  46. ttsem-0.1.0/tests/fixtures/agents/suite_big_tiled.py +26 -0
  47. ttsem-0.1.0/tests/fixtures/agents/suite_no_mask.py +29 -0
  48. ttsem-0.1.0/tests/fixtures/gluon_copy.py +19 -0
  49. ttsem-0.1.0/tests/fixtures/inductor/channel_share_output_code.py +129 -0
  50. ttsem-0.1.0/tests/fixtures/inductor/safe_share_output_code.py +126 -0
  51. ttsem-0.1.0/tests/fixtures/inductor/split_scan_output_code.py +166 -0
  52. ttsem-0.1.0/tests/fixtures/inductor/user_kernel_clone_removed_output_code.py +151 -0
  53. ttsem-0.1.0/tests/fixtures/judge/answer_config_asserts.py +29 -0
  54. ttsem-0.1.0/tests/fixtures/judge/answer_config_faults.py +42 -0
  55. ttsem-0.1.0/tests/fixtures/judge/answer_config_pruned.py +46 -0
  56. ttsem-0.1.0/tests/fixtures/judge/answer_forges.py +48 -0
  57. ttsem-0.1.0/tests/fixtures/judge/answer_lookback_helper.py +50 -0
  58. ttsem-0.1.0/tests/fixtures/judge/answer_nested_grid.py +28 -0
  59. ttsem-0.1.0/tests/fixtures/judge/answer_no_config_fits.py +42 -0
  60. ttsem-0.1.0/tests/fixtures/judge/answer_no_kernel.py +23 -0
  61. ttsem-0.1.0/tests/fixtures/judge/answer_ok.py +27 -0
  62. ttsem-0.1.0/tests/fixtures/judge/answer_patch_restore.py +50 -0
  63. ttsem-0.1.0/tests/fixtures/judge/answer_prewrites.py +42 -0
  64. ttsem-0.1.0/tests/fixtures/judge/answer_protocol_big.py +44 -0
  65. ttsem-0.1.0/tests/fixtures/judge/answer_protocol_marker.py +44 -0
  66. ttsem-0.1.0/tests/fixtures/judge/answer_race_unchecked.py +43 -0
  67. ttsem-0.1.0/tests/fixtures/judge/answer_swallows.py +30 -0
  68. ttsem-0.1.0/tests/fixtures/judge/answer_tampers.py +41 -0
  69. ttsem-0.1.0/tests/fixtures/judge/answer_thread_flip.py +51 -0
  70. ttsem-0.1.0/tests/fixtures/judge/answer_unsafe.py +29 -0
  71. ttsem-0.1.0/tests/fixtures/judge/answer_wrong.py +27 -0
  72. ttsem-0.1.0/tests/fixtures/judge/task_matmul.py +25 -0
  73. ttsem-0.1.0/tests/fixtures/judge/task_relu.py +28 -0
  74. ttsem-0.1.0/tests/fixtures/membar_11325.generic +57 -0
  75. ttsem-0.1.0/tests/fixtures/p1.npy +0 -0
  76. ttsem-0.1.0/tests/fixtures/p1.py +55 -0
  77. ttsem-0.1.0/tests/fixtures/p1.ttgir +64 -0
  78. ttsem-0.1.0/tests/fixtures/p1.ttgir.generic +33 -0
  79. ttsem-0.1.0/tests/fixtures/p1.ttir +63 -0
  80. ttsem-0.1.0/tests/fixtures/p1.ttir.generic +33 -0
  81. ttsem-0.1.0/tests/fixtures/p2.npy +0 -0
  82. ttsem-0.1.0/tests/fixtures/p2.py +57 -0
  83. ttsem-0.1.0/tests/fixtures/p2.ttgir +332 -0
  84. ttsem-0.1.0/tests/fixtures/p2.ttgir.generic +222 -0
  85. ttsem-0.1.0/tests/fixtures/p2.ttir +317 -0
  86. ttsem-0.1.0/tests/fixtures/p2.ttir.generic +217 -0
  87. ttsem-0.1.0/tests/fixtures/p3.npy +0 -0
  88. ttsem-0.1.0/tests/fixtures/p3.py +95 -0
  89. ttsem-0.1.0/tests/fixtures/p3.ttgir +166 -0
  90. ttsem-0.1.0/tests/fixtures/p3.ttgir.generic +91 -0
  91. ttsem-0.1.0/tests/fixtures/p3.ttir +163 -0
  92. ttsem-0.1.0/tests/fixtures/p3.ttir.generic +84 -0
  93. ttsem-0.1.0/tests/fixtures/p4.npy +0 -0
  94. ttsem-0.1.0/tests/fixtures/p4.py +87 -0
  95. ttsem-0.1.0/tests/fixtures/p4.ttgir +160 -0
  96. ttsem-0.1.0/tests/fixtures/p4.ttgir.generic +116 -0
  97. ttsem-0.1.0/tests/fixtures/p4.ttir +72 -0
  98. ttsem-0.1.0/tests/fixtures/p4.ttir.generic +27 -0
  99. ttsem-0.1.0/tests/fixtures/tritonbench/answer_cheats.py +40 -0
  100. ttsem-0.1.0/tests/fixtures/tritonbench/answer_no_kernel.py +5 -0
  101. ttsem-0.1.0/tests/fixtures/tritonbench/answer_ok.py +18 -0
  102. ttsem-0.1.0/tests/fixtures/tritonbench/answer_peeks.py +29 -0
  103. ttsem-0.1.0/tests/fixtures/tritonbench/answer_plants.py +32 -0
  104. ttsem-0.1.0/tests/fixtures/tritonbench/answer_prewrites.py +34 -0
  105. ttsem-0.1.0/tests/fixtures/tritonbench/answer_protocol_marker.py +30 -0
  106. ttsem-0.1.0/tests/fixtures/tritonbench/answer_race_unchecked.py +32 -0
  107. ttsem-0.1.0/tests/fixtures/tritonbench/answer_raises.py +18 -0
  108. ttsem-0.1.0/tests/fixtures/tritonbench/answer_swallows.py +25 -0
  109. ttsem-0.1.0/tests/fixtures/tritonbench/answer_unsafe.py +17 -0
  110. ttsem-0.1.0/tests/fixtures/tritonbench/answer_wrong.py +18 -0
  111. ttsem-0.1.0/tests/fixtures/tritonbench/task_relu.py +37 -0
  112. ttsem-0.1.0/tests/fixtures/ws_desc.py +66 -0
  113. ttsem-0.1.0/tests/test_audits.py +392 -0
  114. ttsem-0.1.0/tests/test_bot.py +131 -0
  115. ttsem-0.1.0/tests/test_demo.py +124 -0
  116. ttsem-0.1.0/tests/test_gluon_compile.py +25 -0
  117. ttsem-0.1.0/tests/test_harness.py +973 -0
  118. ttsem-0.1.0/tests/test_interp.py +603 -0
  119. ttsem-0.1.0/tests/test_judge.py +745 -0
  120. ttsem-0.1.0/tests/test_judge_integrity.py +909 -0
  121. ttsem-0.1.0/tests/test_judge_tritonbench.py +500 -0
  122. ttsem-0.1.0/tests/test_layout_checks.py +311 -0
  123. ttsem-0.1.0/tests/test_layouts.py +1511 -0
  124. ttsem-0.1.0/tests/test_lost_updates.py +121 -0
  125. ttsem-0.1.0/tests/test_minimize.py +183 -0
  126. ttsem-0.1.0/tests/test_mlir.py +415 -0
  127. ttsem-0.1.0/tests/test_nvws.py +59 -0
  128. ttsem-0.1.0/tests/test_ops.py +3801 -0
  129. ttsem-0.1.0/tests/test_parser_scope.py +105 -0
  130. ttsem-0.1.0/tests/test_pidraces.py +200 -0
  131. ttsem-0.1.0/tests/test_plugin_warnings.py +78 -0
  132. ttsem-0.1.0/tests/test_races.py +290 -0
  133. ttsem-0.1.0/tests/test_sanitize.py +775 -0
  134. ttsem-0.1.0/tests/test_scaled_dot.py +504 -0
  135. ttsem-0.1.0/tests/test_scheduler.py +86 -0
  136. ttsem-0.1.0/tests/test_torch_demo.py +28 -0
  137. ttsem-0.1.0/tests/test_torch_demo_ledger.py +56 -0
  138. ttsem-0.1.0/tests/test_validate.py +62 -0
  139. ttsem-0.1.0/tests/test_validate_corpus.py +40 -0
  140. ttsem-0.1.0/ttsem/__init__.py +137 -0
  141. ttsem-0.1.0/ttsem/__main__.py +92 -0
  142. ttsem-0.1.0/ttsem/_compile_runner.py +65 -0
  143. ttsem-0.1.0/ttsem/_fakedriver.py +129 -0
  144. ttsem-0.1.0/ttsem/_guard.py +1045 -0
  145. ttsem-0.1.0/ttsem/_install.py +26 -0
  146. ttsem-0.1.0/ttsem/_interp_runner.py +85 -0
  147. ttsem-0.1.0/ttsem/_judge_runner.py +791 -0
  148. ttsem-0.1.0/ttsem/_tritonbench_runner.py +234 -0
  149. ttsem-0.1.0/ttsem/bot.py +143 -0
  150. ttsem-0.1.0/ttsem/bot.sh +57 -0
  151. ttsem-0.1.0/ttsem/campaign_target.py +188 -0
  152. ttsem-0.1.0/ttsem/check_fixtures.py +91 -0
  153. ttsem-0.1.0/ttsem/defuse.py +109 -0
  154. ttsem-0.1.0/ttsem/demo.py +334 -0
  155. ttsem-0.1.0/ttsem/dump_corpus.py +60 -0
  156. ttsem-0.1.0/ttsem/harness.py +1671 -0
  157. ttsem-0.1.0/ttsem/inductor_trace.py +88 -0
  158. ttsem-0.1.0/ttsem/interp.py +336 -0
  159. ttsem-0.1.0/ttsem/interp2.py +146 -0
  160. ttsem-0.1.0/ttsem/ir_types.py +93 -0
  161. ttsem-0.1.0/ttsem/judge.py +1068 -0
  162. ttsem-0.1.0/ttsem/judge_io.py +537 -0
  163. ttsem-0.1.0/ttsem/judge_shapes.py +287 -0
  164. ttsem-0.1.0/ttsem/judge_tritonbench.py +724 -0
  165. ttsem-0.1.0/ttsem/layout_checks.py +285 -0
  166. ttsem-0.1.0/ttsem/layouts.py +976 -0
  167. ttsem-0.1.0/ttsem/linear_layout.py +676 -0
  168. ttsem-0.1.0/ttsem/memory.py +372 -0
  169. ttsem-0.1.0/ttsem/minimize.py +523 -0
  170. ttsem-0.1.0/ttsem/mlir.py +1028 -0
  171. ttsem-0.1.0/ttsem/ops.py +2634 -0
  172. ttsem-0.1.0/ttsem/pass_stress.py +83 -0
  173. ttsem-0.1.0/ttsem/pidraces.py +221 -0
  174. ttsem-0.1.0/ttsem/py.typed +0 -0
  175. ttsem-0.1.0/ttsem/pytest_ttsem.py +264 -0
  176. ttsem-0.1.0/ttsem/races.py +1081 -0
  177. ttsem-0.1.0/ttsem/races_corpus.py +132 -0
  178. ttsem-0.1.0/ttsem/sanitize.py +1036 -0
  179. ttsem-0.1.0/ttsem/torch_demo.py +130 -0
  180. ttsem-0.1.0/ttsem/validate.py +425 -0
  181. ttsem-0.1.0/ttsem/validate_corpus.py +118 -0
  182. ttsem-0.1.0/ttsem/values.py +430 -0
ttsem-0.1.0/.gitignore ADDED
@@ -0,0 +1,36 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.so
5
+ .Python
6
+ build/
7
+ dist/
8
+ *.egg-info/
9
+ .eggs/
10
+
11
+ # Environments
12
+ .venv/
13
+ venv/
14
+ env/
15
+
16
+ # Tooling caches
17
+ .pytest_cache/
18
+ .mypy_cache/
19
+ .ruff_cache/
20
+ .coverage
21
+ htmlcov/
22
+
23
+ # Run output
24
+ ttsem_out/
25
+ *.jsonl
26
+ /out/
27
+ /results/
28
+ /tb/
29
+ /kb/
30
+ /TritonBench/
31
+
32
+ # Editors and OS
33
+ .vscode/
34
+ .idea/
35
+ *.swp
36
+ .DS_Store
@@ -0,0 +1,19 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use ttsem in your work, please cite it with the metadata below."
3
+ type: software
4
+ title: "ttsem: an executable semantics of Triton's TTIR and TTGIR, with a per-pass validator"
5
+ authors:
6
+ - family-names: Potenza
7
+ given-names: Alessandro
8
+ version: 0.1.0
9
+ # date-released is set when 0.1.0 is tagged and published
10
+ license: MIT
11
+ repository-code: "https://github.com/alepot55/ttsem"
12
+ url: "https://github.com/alepot55/ttsem"
13
+ keywords:
14
+ - triton
15
+ - mlir
16
+ - compiler
17
+ - semantics
18
+ - gpu
19
+ - interpreter
@@ -0,0 +1,25 @@
1
+ # Contributing
2
+
3
+ 1. **Run the tests**: `python -m pytest -q tests`. No GPU and no `triton-opt` are needed, and
4
+ without the Triton wheel the tests that need it are skipped. CI also runs `ruff check .`,
5
+ `ruff format --check .` and `mypy`, at the versions pinned in `.github/workflows/ci.yml`, with
6
+ the settings in `pyproject.toml`.
7
+ 2. **Add an op** in `ttsem/ops.py`: one function per op name, registered in `OPS`, with the
8
+ signature `fn(interp, op, args) -> list[Value]`. Region-carrying ops call
9
+ `interp.run_region(region, args)`; numpy only, no torch.
10
+ 3. **Every op gets a test** in `tests/`, a two-line module in generic MLIR form that the parser and
11
+ the interpreter run end to end. Prefer the smallest module that pins the choice you made.
12
+ 4. **If the answer is not obvious from the docs**, it is a semantic choice: add one line to
13
+ `SEMANTICS.md` saying what was picked and why, with the tie-breakers in order (the device, then
14
+ the shipped interpreter, then LLVM's equivalent scalar op).
15
+ 5. **Never guess**: an op you do not model raises `Unsupported(name)`, which is counted, rather
16
+ than a value that happens to look right.
17
+ 6. **Device deviations stay mismatches.** When the device disagrees and the IR does not determine
18
+ the answer, add it to "Device deviations" in `SEMANTICS.md` with the launch that shows it, and
19
+ leave it a `mismatch`. The semantics is not changed to agree with the hardware.
20
+ 7. **Reporting a mismatch**: open an issue with the IR dump (`MLIR_ENABLE_DUMP=1`, or the module
21
+ the stage received), the input buffers or the seed that generates them, the Triton commit or
22
+ wheel version, and the device. Without the IR and the inputs a mismatch cannot be reproduced,
23
+ and an unreproducible mismatch cannot be triaged.
24
+ 8. **A smaller witness is a better one**: `python -m ttsem.minimize <program>` reduces a module
25
+ while the pass still changes its meaning, with no GPU involved.
ttsem-0.1.0/LEDGER.md ADDED
@@ -0,0 +1,133 @@
1
+ # Bug ledger
2
+
3
+ One row per upstream defect found in this project: the compiler, the guilty pass or rewrite, the
4
+ symptom, how it was found, the state and the fix. Where the first column links an issue or a pull
5
+ request, that report holds the reproducer. Nothing enters without a minimal reproducer; the "found
6
+ by" column says where the semantics was involved.
7
+
8
+ The state column is the state on 8 October 2026, in words: filed (an issue or PR is open),
9
+ confirmed by a maintainer, fixed by an upstream commit, closed without a fix, or not reported.
10
+
11
+ Tools referred to in the "found by" column:
12
+
13
+ - **validator**: `ttsem/validate.py`, the per-pass validator that names the culprit pass.
14
+ - **minimiser**: `ttsem/minimize.py`, the delta minimiser (`--reads` and `--crash` variants).
15
+ - **race detector**: two checks under one name. `ttsem/races.py` (level 3) finds races between the
16
+ warps of a CTA in shared memory; `ttsem/pidraces.py` finds races between the program instances of
17
+ a launch, the check behind the PyTorch rows.
18
+ - **memory model**: `ttsem/memory.py`, the flat memory of the semantics, which reports every access
19
+ outside a bound buffer.
20
+ - **layout fuzzer**: the companion differential fuzzer over layouts, dtypes and descriptors.
21
+ - **static witness**: the companion static check of whether code motion keeps the mask or guard a
22
+ load had in the source.
23
+ - **program fuzzer**: the companion generator of well-formed SIMT and tile programs with a
24
+ lock-step interpreter as oracle.
25
+ - **LLVM continuation**: the companion lock-step interpreter of the LLVM dialect and NVVM, which
26
+ takes over at the first `llvm.func`.
27
+ - **AxisInfo oracle**: the runtime oracle and transfer-function sweep for Triton's `AxisInfo`.
28
+ - **random program generator** (for `torch.compile`): the companion generator of PyTorch programs
29
+ that update a tensor in place with something read from it, run on a device against eager and,
30
+ with no GPU, under the race detector. Its **fourth tier** adds aliased inputs, integers,
31
+ freezing and autograd.
32
+ - **OpInfo sweep**: the companion sweep of PyTorch's OpInfo samples with transposed and gapped
33
+ layouts and other scalar values, compiled and compared with eager.
34
+
35
+ The validator, the minimiser, both race detectors and the memory model ship in this package; the
36
+ other tools above do not.
37
+
38
+ ## Upstream defects
39
+
40
+ ### Triton and LLVM
41
+
42
+ | # | date | compiler | pass or rewrite | symptom | found by | state (2026-10-08) | fix |
43
+ |---|---|---|---|---|---|---|---|
44
+ | [triton#11328](https://github.com/triton-lang/triton/issues/11328) | 2026-08-16 | Triton `main` | `ClusterBarrierInsertion`, `ClusterBarrierAnalysis::update`, scratch branch | a multicast TMA through a `memdesc` view gets no `cluster_barrier`, because the scratch branch uses `getBufferIds`, which ignores aliases | by hand, reading `Membar.cpp` and counting barriers on IR | fixed, closed by Jokeren on 23 Aug | [#11411](https://github.com/triton-lang/triton/pull/11411) by Jokeren, `c55f21c06`, with a 4-CTA reproducer that failed 1000/1000 on `main`; the `LocalAtomicScatterRMWOp` carve-out in [#11396](https://github.com/triton-lang/triton/pull/11396) by whutsunxu, `dff2f7d03` |
45
+ | [triton#11326](https://github.com/triton-lang/triton/issues/11326) | 2026-08-16 | Triton `main` | `Membar` at a call boundary (`BufferRegionAnalysis`) | no barrier between a pending shared access in the caller and the first shared access in the callee | by hand | fixed; closed by us on 29 Aug after running `triton-opt` at `9628c80f2` on the reproducer: the mid-August rework of `Membar.cpp` compares the pending state against the callee's `entryBlockInfo`, which is the shape the issue asked for | the `BufferRegionAnalysis` rework; no targeted PR ([#11384](https://github.com/triton-lang/triton/pull/11384) by lorenzozanee was closed unmerged on 22 Aug) |
46
+ | [triton#11325](https://github.com/triton-lang/triton/pull/11325) | 2026-08-16 | Triton `main` | `Membar`, comparison of subslice offsets | **missing barrier**: two subslices with the same numeric offset but from different buffers are treated as the same byte range, because the comparison is on the digit and not on the frame it came from | by hand | **fixed** on `main` by another PR. Filed as a PR on 16 Aug; Jokeren called it "just a workaround" on 20 Aug. lezcano's [#11431](https://github.com/triton-lang/triton/pull/11431), merged 25 Aug, requires the same indexed descriptor before index differences can prove two subslices disjoint; its test `layout_changed_reinterpret_subslice` is our reproducer and expects the barrier. Jokeren closed our PR unmerged on 30 Aug, "as it's solved in main". The class is re-found automatically: with that one barrier removed, the race detector reports the race in `subslice_offsets_after_reinterpret` and its element-type twin, 12 warp pairs each, and nothing in the two controls | [#11431](https://github.com/triton-lang/triton/pull/11431) by lezcano, not by us |
47
+ | [triton#11404](https://github.com/triton-lang/triton/issues/11404) | 2026-08-23 | Triton `main` | `Membar`, `ttng.cluster_barrier {relaxed}` | a relaxed `cluster_barrier` was treated as a full sync and cleared the memory state, while 25 lines above in the same file a fence is placed before the relaxed one: the pass contradicted itself | by hand | fixed, closed by lezcano on 26 Aug | [#11462](https://github.com/triton-lang/triton/pull/11462) by gaoxiaomo, `c0901bf1c` |
48
+ | [triton#11405](https://github.com/triton-lang/triton/issues/11405) | 2026-08-23 | Triton `main` | `ttg.warp_specialize` capturing a tensor | `report_fatal_error` with no diagnostic on valid IR, reachable from Gluon | by hand | filed, open, 9 comments, has an owner | candidate: [#11457](https://github.com/triton-lang/triton/pull/11457) by Sadik00789, a verifier for `WarpSpecializeOp`, open |
49
+ | [triton#11407](https://github.com/triton-lang/triton/issues/11407) | 2026-08-22 | Triton `main` and the 3.8.0 wheel | `tritongpu-pipeline`, `predicateOp` | the pipeliner moves the next iteration's address arithmetic into the current one and predicates the load but not the `arith.divsi` that computes its address, so `(i * BLOCK) // (n - i)` divides by zero on a trip the source never takes | by hand, then the validator on the reproducer: `match` up to the pipeliner, `poison` (integer division by zero) from pipeliner step 2 to the final TTGIR, `match` again with the fix re-applied | **fixed and then reverted**: closed by lezcano on 23 Aug, reverted on 24 Aug as "causes regressions and doesn't really solve any practical problem"; the issue stays closed and the UB stayed on `main`: last checked on 8 Sep, at `27964b601`, 33 `match` up to the pipeliner, 30 `poison` after it | [#11410](https://github.com/triton-lang/triton/pull/11410) by FU-max-boop, `ad81746db`, reverted by [#11427](https://github.com/triton-lang/triton/pull/11427) by ThomasRaoux, `bf9ad8723` |
50
+ | [triton#11519](https://github.com/triton-lang/triton/issues/11519) | 2026-08-30 | Triton `main` (`e1f944a7a`) | `tritongpu-fuse-nested-loops`, `matchPositiveTripCount` | accepts an `llvm.assume` that does not dominate the loop: on `m=4, n=0` the device writes 256 elements into a buffer the source never touches (`out = [4, 8, 12, ...]` instead of zeros) | hand analysis, then the validator named the pass on its own (320 elements mismatching in every dump up to "Before FuseNestedLoops", `match` from the next decided dump on); the minimiser produced a 39-line witness in 14 s | **fixed**, closed by peterbell10 on 8 Sep | [#11521](https://github.com/triton-lang/triton/pull/11521) by LiRunGuo, merged 8 Sep, `8f80860f1` |
51
+ | [triton#11544](https://github.com/triton-lang/triton/issues/11544) | 2026-09-02 | Triton `main` (`d4eb2dd39`) | `AxisInfo`, `remsi` / `remui` visitor | the divisibility of a remainder is declared on every element instead of on the group bases: `misaligned address` from a valid kernel | AxisInfo oracle: transfer-function sweep, then a device witness | **fixed**, closed by lezcano three hours after the issue | [#11546](https://github.com/triton-lang/triton/pull/11546) by lezcano, `4af25c84e` |
52
+ | [triton#11548](https://github.com/triton-lang/triton/pull/11548) | 2026-09-02 | Triton `main` (`d4eb2dd39`) | `AxisInfo`, constancy of `tt.load` with `other` | a masked load inherits the pointer's constancy and ignores `other`; the following `addi` deduplication copies registers and the device writes `[65,65,65,65,69,...]` for `[65,66,67,68,69,...]`, 48 elements of 128 | AxisInfo oracle: sweep plus a device witness | **fixed before our report went out**: lezcano found and fixed it the same afternoon, an hour after our neighbouring issue | [#11548](https://github.com/triton-lang/triton/pull/11548) by lezcano, `36cb2499e` |
53
+ | [triton#7749](https://github.com/triton-lang/triton/issues/7749) | 2026-09-02 (issue opened 2025-08-02) | Triton `main` (`d4eb2dd39`) | `AxisInfo`, `divsi` / `remsi` visitors on negative dividends | the group rules for `divsi` / `remsi` hold only for non-negative dividends: with `x = offs - 64`, `x // 32` takes constancy 32 and register deduplication copies one register into four, 6 elements of 128 wrong; `x % 32` reads `x_ptr[0..3]` instead of `x_ptr[0], x_ptr[-31], x_ptr[-30], x_ptr[-29]` | matthias-springer's 2025 issue made observable on device by us, with a Lean witness showing the ungated rules are unsatisfiable on the kernel | confirmed, assignee Jokeren, label `bug` | in review: [#11569](https://github.com/triton-lang/triton/pull/11569) by alepot55 (a non-negativity bit in the lattice, gates on `divsi` / `remsi`, entry-block `assume`); the maintainer asked to keep it open without further commits, wanting the sign from a range analysis; our question about the acceptable shape is unanswered |
54
+ | [triton#11581](https://github.com/triton-lang/triton/issues/11581) | 2026-09-04 | ptxas 12.9.86 (the one Triton pins for sm_90), through Triton `main` | `add.s16x2`, immediate of the second one | LLVM narrows the second register group to i16x2 and ptxas 12.9.86 emits `VIADD.16x2 R4, R4, 0x0`, losing the immediate: 16 of 256 elements wrong on an H100; ptxas 13.3.33 is correct | layout fuzzer, 2 programs of 1,000 | filed; closed as not planned by peterbell10 on 23 Sep | none: NVPTX makes i16x2 legal on sm_90 with no option, so the fix is on the LLVM side or in the pinned ptxas |
55
+ | [triton#11583](https://github.com/triton-lang/triton/issues/11583) | 2026-09-04 | Triton `main` and the 3.8.0 wheel, H100 and sm_120 | `desc.store` (TMA), `TensorDescriptor` | a descriptor store writes past the inner extent up to the 16-byte boundary (columns `N..ceil16(N)`), host-side and in-kernel, int8/16/32; the documentation says "ignored" and the shipped interpreter clips per element | layout fuzzer, `tma` profile (241, 328 and 324 `pad_write` programs over three campaigns) | filed, open; lezcano asked a colleague on 4 Sep; on 21 Sep peterbell10 opened [#11893](https://github.com/triton-lang/triton/pull/11893), which documents the 16-byte limitation and closes the issue (open on 8 Oct) | none in the compiler; the documentation PR #11893 |
56
+ | [triton#11586](https://github.com/triton-lang/triton/issues/11586) | 2026-09-04 | Triton `main` | `NVGPUWarpSpecialization`, `WGMMAOpPattern::getPtxAsm` | an int8 `tl.dot` in a `warp_specialize=True` loop with TMA operands asserts (s8 wgmma without transposition): the shared layout warp specialization picks for operand B | layout fuzzer, `tma` floating-point profile | filed, open; reproduced independently by a third-party contributor on `main` `20e6ba864` on 7 Sep, with an analysis of operand B's layout; re-confirmed by us on 8 Sep at `27964b601` (B's encoding goes from `transposed = true` to `false` inside `nvgpu-warp-specialization`, assert at `NVGPUToLLVMPass.cpp:460`), with a question to the maintainers about which shape of fix they want | diagnostic instead of the assertion: [#11728](https://github.com/triton-lang/triton/pull/11728) by alepot55, open; the layout fix: [#11796](https://github.com/triton-lang/triton/pull/11796) by Vaisman, open |
57
+ | [triton#11587](https://github.com/triton-lang/triton/issues/11587) | 2026-09-04 | Triton `main` | `NVGPUWarpSpecialization`, tile partitioning | host descriptors plus `warp_specialize=True` plus `BLOCK_M=128`: an `async_tma_copy_global_to_local` of 8192 elements against 4096 | layout fuzzer, `tma` floating-point profile | filed, open, 0 comments | candidate: [#11596](https://github.com/triton-lang/triton/pull/11596) by layahaasini, "Don't data-partition tiles fed by host-side tensor descriptors", open |
58
+ | [triton#11584](https://github.com/triton-lang/triton/issues/11584) | 2026-09-04 | Triton, shipped interpreter (`TRITON_INTERPRET=1`) | `tl.dot` on bf16 | the interpreter multiplies raw bf16 bit patterns instead of values | layout fuzzer, interpreter oracle against the device | wontfix: closed by Jokeren on 5 Sep, "we just don't support it yet"; our PR [#11585](https://github.com/triton-lang/triton/pull/11585) was closed with it | none |
59
+ | [triton#11600](https://github.com/triton-lang/triton/issues/11600) | 2026-09-05 | Triton wheel 3.8.0 (release/3.8.x), sm_120 | `setOptimizedGatherLayout` (`tl.gather`) | a small gather with `num_warps >= 2` lays the leftover warps along the gather axis and then `isWarpLocal` asserts: 8 of 1,600 fuzzer programs, 15 of 81 combinations in the 2-D sweep | layout fuzzer; the level-2 gather check separates the two layouts and reproduces the boundary over 81 two-dimensional and 8,192 four-dimensional combinations | fixed on `main`, not in 3.8.0; closed by Jokeren on 5 Sep | [#10838](https://github.com/triton-lang/triton/pull/10838) by Jokeren, `2c008494e` (13 Jul), already on `main` before the issue |
60
+ | [triton#11730](https://github.com/triton-lang/triton/issues/11730) | 2026-09-12 | Triton wheel 3.8.0 (release/3.8.x), sm_120 | `ClusterBarrierInsertion` (multi-CTA kernels) | a multi-CTA kernel whose lowering reads a peer CTA's shared memory (the scalar atomic broadcast through `mapa.shared::cluster`) has no cluster barrier before `ret`; CTA 0 exits while the others still read, the launch fails with `unspecified launch failure` and the error is sticky for the process (932 of the release's 937 `test_core` failures on sm_120) | the release suite under the validator: 14,979 launches, 0 unexplained mismatches, and a failure class the verdicts did not explain; confirmed by patching the barrier into the wheel's PTX with `TRITON_KERNEL_OVERRIDE` | filed; backport built and verified on sm_120 | on `main` since [#10656](https://github.com/triton-lang/triton/pull/10656) (9 Jul); backport to 3.8.x in [#11731](https://github.com/triton-lang/triton/pull/11731); the skip #10825 had put on the test lifted in [#11732](https://github.com/triton-lang/triton/pull/11732) |
61
+ | [triton#11733](https://github.com/triton-lang/triton/issues/11733) (a) | 2026-09-12 | Triton wheel 3.8.0 (release/3.8.x), sm_120 | `ScaledBlockedToMMA` (`tl.dot_scaled`, mxfp4 packed along M/N) | the SM120 blocked-scale MMA needs K packing; 3.8.0 does not guard the MN-packed case, compiles it and returns wrong results (`test_block_scale_fp4`, six configurations, 524,214 of 524,288 elements off) | the release suite under the validator (second corpus): the semantics agree with the test's torch reference, the device with neither | filed; backport built and verified on sm_120 | on `main` since [#10726](https://github.com/triton-lang/triton/pull/10726) (7 Jul, described there as a codegen crash); backport [#11734](https://github.com/triton-lang/triton/pull/11734) |
62
+ | [triton#11733](https://github.com/triton-lang/triton/issues/11733) (b) | 2026-09-12 | Triton wheel 3.8.0 (release/3.8.x), sm_120 | `combineCtaCgaWithShape` (`LinearLayoutConversions.cpp`, SM120 scaled-dot scale layouts) | a batched scaled dot has a rank-3 scale tensor; the SM120 scale layout assumed rank 2 and the assertion `ctaLayout.getNumOutDims() == rank` fails inside `PassManager::run` (`test_batched_mxfp`, all 36) | the same corpus | filed; backport built and verified on sm_120 | on `main` since [#11262](https://github.com/triton-lang/triton/pull/11262) (11 Aug); backport [#11734](https://github.com/triton-lang/triton/pull/11734) |
63
+ | [triton#11735](https://github.com/triton-lang/triton/issues/11735) | 2026-09-12 | Triton wheel 3.8.0 (release/3.8.x), sm_120 | eleven fixes that landed on `main` after the 23 Jun branch point: `DecomposeScaledBlocked` E8M0 decoding, `OptimizeThreadLocality`, `FuseNestedLoops` empty inner loops, the descriptor-to-TMA conversion of unaligned tensors, `AccelerateMatmul` k_pack forwarding, gather locality, and five frontend rewrites (`if` filters in list comprehensions, `-0.0` constants, `while` conditions, the `tl.softmax` axis, the `tl.histogram` input contract) | six wrong results, one device fault (`misaligned address`, sticky for the process), four crashes or missing diagnostics; every one reproduced on the pure wheel | the method reversed: `main`'s own `python/test/unit/language` (18,491 tests) run against the 3.8.0 wheel, one process per failing test, the fixing commit found with `git log -S` on the test's name; 443 failures in 67 functions, eleven of them the release's, the rest features and declared changes | filed; backports built and verified on sm_120 and opened as [#11736](https://github.com/triton-lang/triton/pull/11736), [#11737](https://github.com/triton-lang/triton/pull/11737), [#11739](https://github.com/triton-lang/triton/pull/11739), [#11740](https://github.com/triton-lang/triton/pull/11740), [#11741](https://github.com/triton-lang/triton/pull/11741); a second run on sm_89 confirmed nine of the eleven (the TMA and cluster classes are not reachable on that board) | on `main` since #10898, #11624, #11613, #11186, #10838, #11607, #11688, #10888, #11426, #11234, #11409, #10891 |
64
+ | [triton#11747](https://github.com/triton-lang/triton/issues/11747) | 2026-09-13 | Triton `main` 972d18aa0, sm_120 (RTX PRO 6000), `TRITON_INSTRUMENTATION_MODE=consan` | the concurrency sanitizer's lowering on a target without tcgen05 | compiling a Gluon tcgen05 kernel for sm_120a under consan aborts the process with `LLVM ERROR: Cannot select: intrinsic %llvm.nvvm.tcgen05.wait.st` (exit 134), where the plain compile gets a clean `PTXASError`; under pytest the abort kills the xdist worker and every test queued on it fails with `BrokenPipeError` | running `python/test/gluon` under the validator on sm_120 and reading the 326 failures back to their first error | filed with a 9-line reproducer; **fixed**, closed by lezcano on 29 Sep | [#11973](https://github.com/triton-lang/triton/pull/11973) by saiyambharara, merged 29 Sep (`6f8c7040c`) |
65
+ | [#11752](https://github.com/triton-lang/triton/pull/11752) | 2026-09-13 | Triton `main` 972d18aa0, `third_party/nvidia/lib/Dialect/NVWS/IR/Ops.cpp` | the custom assembly format of `nvws.warp_group` prints and parses the partitions but not the result types | a warp group with results prints as `%r:5 = nvws.warp_group ...` and that text fails to parse (`cannot name an operation with no results`), so the MLIR_ENABLE_DUMP stages between `nvws-lower-aref` and `nvws-lower-warp-group` cannot be fed back to `triton-opt` | the per-pass validator on sm_120: the stage before `nvws-lower-warp-group` of every warp-specialized fuzz program came back as a parse error | filed as a fix with a round-trip lit case | merged on 2026-09-14 (`59eaaff96`), five hours after filing |
66
+ | [#11831](https://github.com/triton-lang/triton/pull/11831) | 2026-09-17 | Triton `main`, `python/triton_kernels/tests/conftest.py` | the xdist hook maps worker `gw<n>` to `n % torch.cuda.device_count()` and overwrites `CUDA_VISIBLE_DEVICES` with it | under an outer `CUDA_VISIBLE_DEVICES=1`, `device_count()` is 1, every worker gets `"0"`, and that string names the physical GPU 0 the caller excluded | running `triton_kernels/tests` under the validator on a shared two-GPU box: all eight workers landed on the other GPU | filed as a fix that indexes into the caller's list | open |
67
+ | [#11859](https://github.com/triton-lang/triton/issues/11859) | 2026-09-18 | Triton `main`, `python/triton_kernels/triton_kernels/target_info.py` | `has_tma_gather()` is `cuda_capability_geq(10, 0)`, so `matmul.py` selects the TMA gather and scatter paths on consumer Blackwell (capability 12.0) | ptxas answers `Feature '.tile::scatter4' not supported on .target 'sm_120a'`: 288 cases of `test_matmul.py::test_op` fail to compile on an RTX PRO 6000 | running `triton_kernels/tests` under the validator: the failures were upstream's, the same without the plugin | filed as an issue, then the gate as [#11862](https://github.com/triton-lang/triton/pull/11862) after the device check (280 of 288 pass, the other 8 are #11860); **fixed** 21 Sep | [#11862](https://github.com/triton-lang/triton/pull/11862) by alepot55, merged 2026-09-21 (`3fb26ceee`) |
68
+ | [#11860](https://github.com/triton-lang/triton/issues/11860) | 2026-09-18 | Triton `main`, `OptimizePartitionWarps::relayoutWarps` and `relayout-tritongpu` | the relayout clears every tensor encoding of a partition; a `ttg.convert_layout` already there stays unencoded because the TTG dialect is legal as a whole in the conversion | `remove-layout-conversions` dereferences the null encoding in `isConvertTrivial`: a segfault under `triton-opt`, `PassManager::run failed` from Python (8 fp4 x fp4 `_p_matmul` cases of `triton_kernels` on sm_120) | the device check of the #11859 gate: the 8 cases it did not fix; reduced by hand to ten lines after the crash minimiser converged on a different failure | filed with the fix, [#11861](https://github.com/triton-lang/triton/pull/11861); **fixed** 21 Sep by another fix, ours closed unmerged | [#11878](https://github.com/triton-lang/triton/pull/11878) by rohitsalla, merged 2026-09-21 (`0043f3822`) |
69
+ | [#11751](https://github.com/triton-lang/triton/pull/11751) | 2026-09-13 | Triton `main`, `python/triton/runtime/interpreter.py` | the interpreter copies `round_f32_to_tf32` from a host `TensorDescriptor` and then drops it: `_implicit_cvt` builds the handle without the flag and `create_descriptor_load` returns the raw bits | under `TRITON_INTERPRET=1` a kernel loading through such a descriptor sees unrounded f32 where the TMA unit (and the pointer rewrite for targets without TMA) rounds to tf32; 13 of 16 elements differ in the new test | modelling the flag in the semantics (`Descriptor.tf32`) and checking what the shipped interpreter, the CPU reference of the harness, does with it | filed as a fix with a test that runs on the device and under the interpreter | merged on 2026-09-14 (`87b827728`), a day after filing |
70
+ | [#11746](https://github.com/triton-lang/triton/pull/11746) | 2026-09-13 | Triton `main`, `python/test/gluon` | none: the tests' gating, not the compiler | 61 tests (326 cases) fail on sm_120: tcgen05 tests gated with `capability[0] < 10`, cluster-op tests where `TargetFeatures::supportClusterOps` is false for sm_12x, two TMA tests needing 131,072 bytes of shared memory against 101,376 | the same run; with the gating patch 6,099 passed, 6,212 skipped, 0 failed | filed as a test-only PR; open on 8 Oct, review requested on 13 Sep and not given | [#11746](https://github.com/triton-lang/triton/pull/11746) |
71
+ | [#11738](https://github.com/triton-lang/triton/pull/11738) | 2026-09-12 | Triton `main`, `python/test/unit/language/test_annotations.py` | none: the test, not the compiler | `test_int_annotation` stores `v = 3` at `X + v` into a one-element buffer, three elements past the allocation; the device lets the write through and the test only inspects the TTIR | the memory model of the semantics, which reports every write outside a bound buffer (the 9 `error` launches of the release corpus) | filed as a one-line PR; approved and merged by peterbell10 on 18 Sep | [#11738](https://github.com/triton-lang/triton/pull/11738), merged 2026-09-18 (`93825b7`) |
72
+ | [triton#11601](https://github.com/triton-lang/triton/issues/11601) | 2026-09-05 | Triton `main` | `tritongpu-fuse-nested-loops`, `flatten=True` | the inner bound load is hoisted above a zero-trip outer loop and dereferences a pointer the source never reads | a companion static witness plus the validator's read-set (`extra_reads=4`); the minimiser's `--reads` mode produced a 15-line witness, verified on the 3.7.1 wheel | filed, fix PR open | [#11692](https://github.com/triton-lang/triton/pull/11692) by alepot55, which masks the hoisted load with the outer loop's trip test |
73
+ | [triton#11612](https://github.com/triton-lang/triton/issues/11612) | 2026-09-06 | Triton 3.8.0 and 3.7.1 | `tritongpu-fuse-nested-loops` | a `flatten=True` loop whose body is a single inner `for` with a loop-carried value used afterwards (9 lines of Python) brings the pass down: assertion `!NodePtr->isKnownSentinel()`, or on a larger kernel an `scf.if` with a non-conforming yield. Without `flatten` it compiles | program fuzzer, `TILE_DOT` campaign, seed 1316: the first compiler bug the fuzzer found unaided; the minimiser's `--crash` mode reduced the TTGIR witness to 19 lines that crash the pass on its own | fixed; verified by us on 8 Sep on an sm_89 build: with #11617 the reproducer compiles and returns 6, without it the assert fires | [#11617](https://github.com/triton-lang/triton/pull/11617) by sweiglbosker, a bail-out when LICM hoists the inner loop, merged 2026-09-18 |
74
+ | [triton#11614](https://github.com/triton-lang/triton/issues/11614) | 2026-09-06 | Triton 3.8.0, cross-warp reduction codegen | epilogue of `tt.reduce`, unpredicated store of the warp partial to shared memory | the epilogue writes the partial from **all** lanes of the warp into the same shared word (`warp * 4`), which is correct only if the butterfly left the same bits in every lane; with the Welford combine that `torch.compile` emits for `var` the 32 lanes write 32 different values and the one the hardware serialises last survives. A **regression from 3.7.1 to 3.8.0**: 3.7.1 predicated the store on lane 0, 3.8.0 goes through a path with `pred = true` | LLVM continuation on the generated-kernel corpus: 4 reduction kernels, 6 launches, 54 `poison` stages ("two lanes of one store wrote `global_smem[byte 0]` with 90 and 91"); the tile level grades them `approx` or `match` | **fixed** 2 Oct, closed by peterbell10; verified by us on 8 Sep on an sm_89 build that #11630 at `20365b7` predicated the store (`shfl.sync.idx` from lane 0 on the three values; result bits unchanged over 1,000 launches) | [#12045](https://github.com/triton-lang/triton/pull/12045) by peterbell10, merged 2 Oct, `0888aa798`, which makes the lanes of a noncommutative reduction agree; [#11630](https://github.com/triton-lang/triton/pull/11630) by YuvrajSinghBhadoria2 was closed unmerged the same day |
75
+ | `test_core.py::test_if_call` | 2026-09-06 | Triton, upstream test kernel | the kernel itself | the kernel reads `Out`, derives an address from it and writes `Out` with no barrier: a cross-warp read-after-write race. With warp 0 writing first, warp 1 reads 1 instead of 0 and addresses one element past a one-element buffer. The observable output does not change, so the test passes | LLVM continuation, read-after-write detection per barrier phase: it was the only `error` of one pass over the suite | not reported; a race in the test, not in the compiler | none |
76
+ | [llvm#222127](https://github.com/llvm/llvm-project/pull/222127) | 2026-09-05 | MLIR `convert-gpu-to-nvvm` | `LowerGpuOpsToNVVMOps.cpp` | `gpu.subgroup_id` and `gpu.subgroup_size` have no NVVM lowering: `populateGpuSubgroupIdPatterns` exists but only a test pass calls it, while ROCDL lowers them itself | program fuzzer, dynamic MLIR side, 443 programs | filed, PR open since 8 Sep | [llvm#222127](https://github.com/llvm/llvm-project/pull/222127) by alepot55 |
77
+ | MLIR `gpu.subgroup_reduce` | 2026-09-05 | MLIR `gpu-lower-to-nvvm-pipeline` | `gpu.subgroup_reduce` | not lowerable by the pipeline, with or without `uniform`: `nvvm.redux` sits behind `has-redux`, and the expansion to shuffles lives only in the test pass `-test-gpu-subgroup-reduce-lowering` | program fuzzer, dynamic MLIR side | not reported; [llvm#221393](https://github.com/llvm/llvm-project/pull/221393) derives `has-redux` from the chip, which leaves the pre-sm_80 case open | partial |
78
+ | [llvm#221532](https://github.com/llvm/llvm-project/pull/221532) | 2026-09-05 | MLIR `gpu-lower-to-nvvm-pipeline` | `AllReduceLowering.cpp`, `createSubgroupReduce` | with a non-power-of-two warp count (3) the butterfly leaves different values in the lanes and the final store into `buffer[0]` is not guarded by `isFirstLane`: an intra-op race, UB by the lowering's own contract ("all others return values are undefined"). Latent on the card tested, where the surviving write happens to be the right one | LLVM continuation, 7 of 501 programs `poison`, all at 3 warps | filed 6 Sep; patch verified (`check-mlir-dialect-gpu` 40/40, GPUToNVVM 12/12, no regressions); fabianmcg requested changes on 13 Sep; open, our answer of 17 Sep still the last word when last checked, on 29 Sep | [llvm#221532](https://github.com/llvm/llvm-project/pull/221532) by alepot55 |
79
+
80
+ ### PyTorch
81
+
82
+ | # | date | compiler | pass or rewrite | symptom | found by | state (2026-10-08) | fix |
83
+ |---|---|---|---|---|---|---|---|
84
+ | [pytorch#197829](https://github.com/pytorch/pytorch/issues/197829) | 2026-09-20 | TorchInductor 2.14.0, 2.15.0.dev | `remove_noop_ops` then `reinplace_inplaceable_ops` | `x[1:] = x[:-1].clone()` compiles to a copy over overlapping memory: silent wrong values, a race on CUDA and wrong at every size on the CPU backend | race detector, on the Triton that Inductor emitted for a 3 x 16 x 16 input, where the device is right | fixed | [`0f9fcefa1e62`](https://github.com/pytorch/pytorch/pull/198010), merged 2026-09-22 |
85
+ | [pytorch#198031](https://github.com/pytorch/pytorch/issues/198031) | 2026-09-21 | TorchInductor 2.14.0, 2.15.0.dev | the same two passes, on custom ops and user-defined Triton kernels | `y = x.clone(); op(y, x)` becomes `op(x, x)`: the op reads what it writes | race detector on the emitted code, after reasoning about the cause of #197829 | filed | [#198260](https://github.com/pytorch/pytorch/pull/198260), closed unmerged on 25 Sep |
86
+ | [pytorch#198033](https://github.com/pytorch/pytorch/issues/198033) | 2026-09-21 | TorchInductor 2.9.1 to 2.15.0.dev | `register_foreach_inplace`, `mutate_to(..., unsafe_alias=True)` | `torch._foreach_add_([x], [x.flip(0)])` reads the mirrored row in the kernel that writes it | race detector on the emitted code | fixed 1 Oct 2026 | [#198549](https://github.com/pytorch/pytorch/pull/198549), merged |
87
+ | pytorch, no issue: reported with its fix, [#198242](https://github.com/pytorch/pytorch/pull/198242) | 2026-09-23 | TorchInductor 2.14.0, 2.15.0.dev | `MutationLayoutSHOULDREMOVE.realize_into`: a view of an unrealized computation is inlined into the copy that writes its destination | `x.copy_((x.transpose(0, 1) + 1.0).reshape(x.shape))` reads `x` transposed while the copy writes it: silent wrong values, at every size on the CPU and on CUDA | random program generator, device against eager; delta-debugged on the CPU backend | filed as the second commit of the fix PR; the foreach part of that PR landed with #198549, and on 1 Oct the PR was cut down to this case | [#198242](https://github.com/pytorch/pytorch/pull/198242), open |
88
+ | [pytorch#198270](https://github.com/pytorch/pytorch/issues/198270) | 2026-09-22 | TorchInductor 2.14.0, 2.15.0.dev | scheduler, `fusable_weak_dep` compares buffer names without going through `mutation_real_name` | `x.index_put_(...)` then `x.add_(x.flip(0))`: the copy back into `x` is fused with a read of `x` at other positions, silent wrong values on CUDA and CPU | random program generator, device against eager | fixed 29 Sep 2026 | [#198325](https://github.com/pytorch/pytorch/pull/198325), merged |
89
+ | [pytorch#198280](https://github.com/pytorch/pytorch/issues/198280) | 2026-09-22 | TorchInductor 2.14.0, 2.15.0.dev (regression) | scheduler, `_prune_redundant_deps` then `shared_data_after_reordering_loop` | `x.copy_(x.transpose(-1, -2) * 1.0)` wrong on CUDA: loop reordering puts the read of one node after the write of another | random program generator on the device; reproduced without a GPU by scheduling the CPU Triton nodes as CUDA ones | filed, labelled high priority; open on 8 Oct, with our fix open | [#198328](https://github.com/pytorch/pytorch/pull/198328), open |
90
+ | [pytorch#198332](https://github.com/pytorch/pytorch/issues/198332) | 2026-09-23 | TorchInductor 2.14.0, 2.15.0.dev | the lowering of `prims.copy_strided` gives `require_stride_order` a fill order where it expects a stride order | wrong intermediate layouts for permutations that are not their own inverse; under `dynamic=True` a CPU kernel stores past its output and the heap is corrupted | the random program generator with non-contiguous inputs and dynamic shapes, while checking a fix of ours | filed | [#198335](https://github.com/pytorch/pytorch/pull/198335), closed unmerged on 25 Sep |
91
+ | [pytorch#198343](https://github.com/pytorch/pytorch/issues/198343) | 2026-09-23 | TorchInductor 2.13, 2.14.0, 2.15.0.dev (regression from #176804) | the `lerp` decompositions: with a weight of 0.5 or more they start from `end` | the result takes `end`'s strides where eager lays it out like `start`, so `x.lerp_(end_t, 0.75); x.view(-1)` fails to compile | a sweep of OpInfo samples with other layouts and scalar values, then the random program generator (inputs with gaps) | filed | [#198348](https://github.com/pytorch/pytorch/pull/198348), closed unmerged on 25 Sep |
92
+ | [pytorch#198364](https://github.com/pytorch/pytorch/issues/198364) | 2026-09-23 | TorchInductor 2.14.0, 2.15.0.dev | the meta functions of `copysign`, `floor_divide`, `div(rounding_mode="floor")`, `addr(beta=0)`; Inductor's `put` decomposition | with the first input stored transposed, eager keeps its layout and the compiled op returns contiguous strides, so `op(a_t, b).mT.view(-1)` fails to compile | the sweep of OpInfo samples with other layouts | filed | none yet |
93
+ | [pytorch#198533](https://github.com/pytorch/pytorch/issues/198533) | 2026-09-24 | TorchInductor 2.14.0, 2.15.0.dev, CPU and CUDA (regression after 2.9.1) | `mutate_to`'s fast path swings the StorageBox of an already realized buffer | `y.index_put_((mask,), v)` with a mask that reads `y` through a transposed view reads the update's own output: silent wrong values | the fourth tier of the torch.compile fuzzer (aliased inputs, integers, freezing), every earlier fix loaded | fixed 1 Oct 2026; confirmed by a third party | [#198549](https://github.com/pytorch/pytorch/pull/198549), merged |
94
+ | [pytorch#198539](https://github.com/pytorch/pytorch/issues/198539) | 2026-09-24 | TorchInductor 2.9.1 to 2.15.0.dev, CPU with `freezing` | `GraphLowering.run_node` rebinds a node with an mkldnn convolution among its users to a channels-last copy | `x.copy_(self.conv(x))` leaves the input `x` unchanged, silently | the fourth tier of the torch.compile fuzzer (aliased inputs, integers, freezing), every earlier fix loaded | closed by a maintainer as expected under freezing; we asked whether that covers a user input | none |
95
+ | [pytorch#198545](https://github.com/pytorch/pytorch/issues/198545) | 2026-09-24 | TorchInductor 2.14.0, CUDA | `TritonOverrides.floordiv` negates both operands for a negative divisor, and `0 - min` is `min` | `iinfo.min // b` with `b < 0` has the wrong sign, silently | the fourth tier of the torch.compile fuzzer (aliased inputs, integers, freezing), every earlier fix loaded | fixed 8 Oct 2026: the fix was approved by jansel on 3 Oct and by eellison on 8 Oct, and merged that day | [#198598](https://github.com/pytorch/pytorch/pull/198598), merged (`dc75580976b0`) |
96
+ | [pytorch#198553](https://github.com/pytorch/pytorch/issues/198553) | 2026-09-24 | TorchInductor 2.14.0, CUDA | a fused mask indexed as `(x0 + 4*((x5 + 1) % 4) - 1) % 4`, whose base can be negative (a case of #119883) | wrong values, silently | the fourth tier of the torch.compile fuzzer (aliased inputs, integers, freezing), every earlier fix loaded | filed | none yet |
97
+ | [pytorch#198555](https://github.com/pytorch/pytorch/issues/198555) | 2026-09-24 | TorchInductor 2.14.0, CPU | the C++ `neg` and `abs` of int32/int64 are signed overflow (UB) | on `iinfo.min`, gcc folds `abs(x) >= 0`, an argmax picks other indices than eager, a SIGFPE takes the process down | the fourth tier of the torch.compile fuzzer (aliased inputs, integers, freezing), every earlier fix loaded | filed; confirmed by a third party; the fix was approved by jansel on 3 Oct, and its merge of 4 Oct stopped on a failing macOS trunk job; open on 8 Oct | [#198601](https://github.com/pytorch/pytorch/pull/198601), open |
98
+ | [pytorch#198609](https://github.com/pytorch/pytorch/issues/198609) | 2026-09-25 | AOTAutograd 2.9.1 to 2.15.0.dev | `create_functionalized_fn` writes `flat_outs[i]` with `i` the index in `meta.output_info`, while `flat_outs` starts with the inputs mutated outside the graph | with `keep_inference_input_mutations`, `w.mul_(2); x.add_(1); return x` leaves `w` equal to the new `x`, silently, under aot_eager and Inductor | the fourth tier of the torch.compile fuzzer (`grad` feature) | fixed 29 Sep 2026 | [#198622](https://github.com/pytorch/pytorch/pull/198622), merged |
99
+ | [pytorch#198606](https://github.com/pytorch/pytorch/issues/198606) | 2026-09-25 | ATen's CPU vector code under TorchInductor 2.14.0 and 2.15.0.dev, AVX2 | `at::vec::Vectorized<int64_t>::operator*` multiplies the lanes as signed `int64_t`, which overflows (UB), while the scalar code goes through the unsigned type | `(x * x) % 72` on `x = 2**62 + 1` gives 9 compiled and 65 in eager, silently; right on CUDA, with scalar code, or with `-fwrapv` | the fourth tier of the torch.compile fuzzer (integers) | filed; open on 8 Oct, labelled `module: correctness (silent)`; a third party offered a fix, and our fix is linked from the issue, not yet a PR | none yet |
100
+ | [pytorch#198613](https://github.com/pytorch/pytorch/issues/198613) | 2026-09-25 | TorchInductor 2.9.1 to 2.15.0.dev, CPU | `CppVecOverrides.masked`: a vectorized bool whose base is not a float (an int64 comparison, a bitwise op on bools) loaded under a scalar mask gives a `?:` with two different `VecMask` types | the generated C++ does not compile | the fourth tier of the torch.compile fuzzer (integers) | fixed 4 Oct 2026 by another contributor | [#199560](https://github.com/pytorch/pytorch/pull/199560) by syerva-g, merged 4 Oct (`d499620`) |
101
+ | [pytorch#198624](https://github.com/pytorch/pytorch/issues/198624) | 2026-09-25 | AOTAutograd 2.9.1 to 2.15.0.dev, CPU and CUDA | an output recorded as an alias of an input is regenerated by replaying its `detach`, which drops the history the in-place update gave it | `y = x.detach(); y.add_(x); return y` returns `y` without a `grad_fn` under `aot_eager` and Inductor, so a loss over it does not reach `x` | the fourth tier of the torch.compile fuzzer (`grad` feature) | filed; open on 8 Oct | none yet |
102
+
103
+ ## Defects of our own tool, found by the same method
104
+
105
+ These defects were in our own tools, and the same method found them. They are listed so a reader
106
+ can see how often the method misled us.
107
+
108
+ | what | found by | outcome |
109
+ |---|---|---|
110
+ | The tile-program generator allowed a slot to be re-read after a store when a `Dot` puts a second layout in the kernel, which is a race in the tile family: counts of 448/496/528 that changed between runs, 0 once the re-read was removed | `TILE_DOT` campaign, seed 680 | refuted as a compiler bug; the generator gained a rule |
111
+ | The LLVM continuation bound scalar record arguments **by position** against the compiled signature, which drops every `constexpr` and every integer specialised to a constant, so each argument after the first dropped one took the previous parameter's value. The symptom depended on where the wrong stride pointed: mismatch, poison, or an address error | the third pass over the test suite: 410 errors, 30 of 38 mismatches, 4 poisons in `test_dot` | refuted; fixed by binding by name |
112
+ | `nvvm.redux.sync` read with its operands in `shfl.sync` order (mask, value); `NVVMOps.td` says (val, mask_and_clamp). The unit test wrote the op in the same wrong order, so it agreed with itself | a fuzzer campaign: 18 minimised findings, all stage mismatches below `llvm.func`, never device against oracle | refuted; fixed, and it explained part of a `poison` column too |
113
+ | Two soundness holes in the program generator's static checker (the survivors of a `Break` describe the whole loop body from the second iteration; a `While` condition evaluated at the entry scope) and one wrong triage | the dynamic mask check in the interpreter, plus an independent review | refuted; fixed and pinned by tests |
114
+ | Shared stores at a lane- or warp-derived index under divergent trip counts: 6 mismatches in 40,000 programs, a race in the generator and not in the compiler | the first nvcc campaign | refuted; the next campaign ran 35,400 programs with 0 |
115
+ | Two gaps in our own not-yet-upstream MLIR uniformity checker: it did not check the *execution* of `gpu.shuffle` / `rotate` under a divergent condition, and it was more permissive than the rule that a shuffle result is warp-uniform only when the lane index is | the fuzzer's static comparison | fixed in our branches before submission |
116
+ | `run_launch` registered the record's pre-launch arrays in the memory model **without copying**, so the first stage's stores leaked into the inputs of every later stage: 2,557 mismatches in 32 programs, exactly those whose stores are not idempotent | the first per-pass corpus run, by its own inconsistency | fixed; the rerun is clean |
117
+ | `split_dump` left the header line of a pass's next intermediate dump at the end of the previous module, so two identical modules differed by a comment and the pipeliner appeared to fire on every program | a cross-check of the pass-firing tables | fixed; the tables were re-measured |
118
+ | `math.fma` computed the exact product and sum as a rational and then returned it through `float64`, so the cast to `float32` rounded a second time | a cycle on a second machine, against a new upstream test built exactly on the inputs where two roundings and one disagree | fixed; the rounding now goes straight into the result format |
119
+ | The descriptor binder assumed 2r+1 block arguments per host descriptor; on a device without TMA the frontend flattens a `TensorDescriptor` into 4r+3 fields | the same cycle, 10 launches of one test | fixed; all ten now `match` |
120
+ | A tuple argument (`shape=(M, N)`, a descriptor inside a tuple) was bound as one value where the frontend gives one block argument per leaf, so strides were misbound and 477 launches stopped at `arg count mismatch` | the second release corpus on sm_120 (`test_tensor_descriptor`) | fixed; the recorder and the binder walk the leaves by path |
121
+ | An fp8 result that rounds to zero took the sign the stable sort happened to give the two zero codes (+0 for a tiny negative, -0 for a tiny positive); the upstream test cannot see it because `torch.equal` treats the zeros as equal | `test_typeconvert_downcast`, 66 launches | fixed; a zero keeps the sign of the input |
122
+ | `tt.fp_to_fp` downcasts did not saturate: an infinity became the NaN code of e4m3 or the infinity of e5m2 where `cvt.rn.satfinite` gives the largest finite value | `test_typeconvert_downcast_clamping`, 12 launches | fixed; downcasts saturate and round toward zero when asked |
123
+ | `tl.make_tensor_descriptor(padding_option="nan")` was read as zero: the generic printer spells the attribute `#tt.padding_option<nan>` on TTGIR and by its value on TTIR | `test_tensor_descriptor_padding` | fixed |
124
+ | `ttng.async_tma_reduce` / `tt.descriptor_reduce` were not modelled | `test_tensor_descriptor_reduce`, 384 launches | fixed for add, min, max, and, or, xor |
125
+ | A narrow float scalar argument (`val: tl.bfloat16 = 42.0`) was bound as the integer 42 | `test_float_annotation` | fixed; scalars travel as bit patterns like every value of their type |
126
+ | The TMA unit writes the whole 16-byte granule of the last element inside the inner extent (triton#11583); the semantics clip per element and called every such buffer a mismatch | `test_tensor_descriptor_store3d`, 34 launches | fixed; `approx` with a note naming the issue, and only when no other byte differs |
127
+
128
+ A negative result belongs here too. Comparing compilers on the same source, over more than 100,000
129
+ generated programs across nvcc 12.9 and 13, clang CUDA, Numba/libNVVM and the MLIR pipeline, with a
130
+ lock-step interpreter as oracle, produced **zero compiler bugs**: every disagreement was ours. The
131
+ generator is too mild for mature frontends. The real findings on that lane came from the MLIR
132
+ lowering path and from the LLVM continuation, not from comparing compilers, and campaigns of that
133
+ kind were stopped.
ttsem-0.1.0/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Alessandro Potenza
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.