Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 30 additions & 11 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -223,17 +223,36 @@ Per-phase deliverables and the open-work priority queue live in

19. **Backends expose hardware-free Target IR before hardware-specific lowering.** Each backend defines an ODS dialect of abstract target ops (`tessera_rocm.mfma`, `tessera_apple.cpu.accelerate_gemm`, `tessera_apple.gpu.metal_kernel`) between Tile IR and final hardware emission. The hardware-free layer is what makes backends lit-testable; validated by `test_target_ir_contract.py`.

**`tessera_x86` exists but does not load — the compliance claim below is
SUSPENDED (2026-08-12, `X86-DIALECT-LOAD-CRASH-2026-08-12`).** As soon as CI
was configured to build the dialect (PR #555), `tessera-opt` was shown to
**segfault inside `TesseraX86Dialect::initialize()` while registering
`TileType`** — it dies on load, before parsing any op (run 31648897366; all
14 x86 fixtures). Nothing below that depends on the dialect being loadable
is proven: in particular the `!tessera_x86.tile` verifier described here
**has never executed**, so read the paragraph as the *intended* contract,
not a demonstrated one. It stayed hidden because no CI lane built the
dialect between 2026-08-02 and 2026-08-12. Status and remediation:
[`docs/audit/backend/x86/todo.md`](docs/audit/backend/x86/todo.md) P0.
**`X86-DIALECT-LOAD-CRASH-2026-08-12` was a build-flag leak, not an IR
defect — root-caused 2026-08-15.** The dialect and its `TileType`
registration were always correct. The x86 kernel project applied its
detected AVX-512/AMX flags with **`add_compile_options`**, which is
*directory* scoped, and `add_subdirectory(lib/IR)` sat below that call — so
the hardware-free Target IR dialect was compiled `-mavx512f … -mamx-tile …`
and the compiler emitted an AVX-512-only encoding into dialect registration
itself. On a host with AVX-512 that runs fine; on the CI runner it does not,
and `tessera-opt` died the first time it touched the dialect. **The tell was
the signal: all 14 fixtures failed with SIGILL (signal 4) at one identical
address, not SIGSEGV** — an illegal instruction is a build-configuration
fact, and `Dialect::addType<TileType>()` was merely the first code from that
translation unit to execute. Flags are now applied per-target to the kernel
targets only, and `lib/IR/CMakeLists.txt` **fails configure** if any
host-specific ISA flag is in scope.

**Standing lesson, because it will recur: a host that has the ISA cannot
falsify a host-portability claim.** This P0 was closed once on Zen 5 —
correctly, for that host — and CI reopened it. Decision #19's "lit-testable
on any host" is only evidenced by a host *without* AVX-512.

**Separately, still open: `TileToX86Pass` loads `tessera_x86` from inside
`runOnOperation()`** (`src/transforms/lib/TileToX86Pass.cpp:1045`, a by-name
`getOrLoadDialect` used to avoid linking the optional backend). MLIR forbids
loading a dialect during pass execution; on an **assertions-enabled** LLVM
this is a hard `LLVM ERROR` that fails 12 of the x86 fixtures, and on an
NDEBUG build (what CI uses) it is silently undefined behavior. CI cannot see
it. Fixing it means declaring the dialect in `getDependentDialects()`, which
couples `TesseraPasses` to the optional `TesseraX86IR` — a layering call.
Status: [`docs/audit/backend/x86/todo.md`](docs/audit/backend/x86/todo.md) P0.

**`tessera_x86` now exists — x86 complies (built 2026-08-02, W0.10).** It was previously the one backend with no Target IR dialect at all: `TileToX86Pass` lowered Tile IR to 21 `func::CallOp`s into a hand-written C shim, and the Python emitter named a `tessera_x86.func` op no dialect defined. **No carve-out was granted.** The dialect lives at `src/compiler/codegen/tessera_x86_backend/include/TesseraX86/IR/`, is registered in `tessera-opt`, and splits into value-carrying ops (`amx_tile_load`/`amx_tile_zero`/`amx_dpbf16ps`/`amx_dpbusd`/`amx_tile_store` over a real `!tessera_x86.tile` type, so the verifier rejects a tile dot-product whose operands never came from a tile load) and directives (`avx512_gemm_microkernel`, `pack_b_panel`, `elementwise`, `kernel`, `kv_cache_read`, `unsupported`). `abi_call` **models the C-shim boundary instead of hiding it**, so Decision #28's arbiter can tell compiler-generated work from delegated work. Fixtures: `tests/tessera-ir/phase2/x86_target_ir{,_invalid}.mlir` — including a negative case, since a dialect that only ever accepts proves nothing. **Remaining follow-on is `x86vector.*` (AVX-512) lowering only; the AMX half is optional** — per project direction (2026-08-02) AMX is expected to be superseded by the ACE matrix instructions jointly agreed by Intel and AMD, so the AMX ops stay as the IR-level contract without an `amx.*` lowering. That also removes the hardware blocker: AVX-512 runs on the primary box, while no fleet machine has AMX.

Expand Down
87 changes: 78 additions & 9 deletions docs/audit/backend/x86/todo.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
---
last_updated: 2026-08-14
last_updated: 2026-08-15
audit_role: plan
plan_state: open
owner: x86 backend
Expand Down Expand Up @@ -43,14 +43,83 @@ pair from frontend through physical manifests. Accumulator-compatible dtypes
derived from target-wide AVX-512 legality remain `legal_only`; only explicit
x86 per-operation rows can claim a physical consumer or execution evidence.

## P0 closed — x86 dialect load and combined-driver proof

`X86-DIALECT-LOAD-CRASH-2026-08-12` is closed on the owning Strix Halo host.
A fresh Release build against apt LLVM/MLIR 23 loads `!tessera_x86.tile`; the
positive Target-IR fixture and its verifier-negative sibling pass. The named
`x86_dialect_load.mlir` regression now isolates dialect initialization from
operation lowering, so a future `TileType` registration failure cannot hide
behind the larger lit suite.
## P0 root-caused — x86 dialect load was a build-flag leak, not an IR defect

`X86-DIALECT-LOAD-CRASH-2026-08-12` was **reopened by CI on 2026-08-15** (run
31893492411) after being closed on the Strix Halo host, and is now root-caused.
Both observations were correct; the host is what differed.

The dialect and its `TileType` registration were never at fault. The x86 kernel
project applied its detected AVX-512/AMX flags with **`add_compile_options`**,
which is *directory* scoped, and `add_subdirectory(lib/IR)` sat below that call
— so the hardware-free Target IR dialect was compiled with `-mavx512f
-mavx512bw … -mamx-tile …`. The compiler was then entitled to emit an AVX-512
encoding into dialect registration itself (confirmed by disassembly:
`vpbroadcastq %rgpr, %xmm`, a GPR-source broadcast that exists only under
AVX-512). On Zen 5 that instruction is legal, so the Strix Halo build ran
clean and the P0 read as closed. On the GitHub runner it is not, and
`tessera-opt` died the first time it touched the dialect.

The tell was in the exit status all along: **all 14 fixtures failed with signal
4 (SIGILL) at one identical address**, not SIGSEGV. An illegal instruction is a
build-configuration fact, not a memory-safety one — a crash *inside*
`Dialect::addType<TileType>()` was the first code from that translation unit to
execute, not the code that was wrong.

Fix: the flags are collected into `TESSERA_X86_ARCH_FLAGS` and applied with
`target_compile_options` to this directory's kernel targets only, enumerated via
`BUILDSYSTEM_TARGETS` so a later kernel target is covered automatically while
subdirectories are structurally excluded. `lib/IR/CMakeLists.txt` additionally
**fails configure** if any host-specific ISA flag is in scope, so the next
occurrence is a build error naming the cause rather than a runtime SIGILL that
reads as a corrupt MLIR install (Decision #21a, fail closed).

Standing lesson for this backend: a host that *has* the ISA cannot falsify a
host-portability claim. Decision #19's "lit-testable on any host" is only
evidenced by a host without AVX-512 — which, in the current fleet, means CI.

The named `x86_dialect_load.mlir` regression isolates dialect initialization
from operation lowering, so a future `TileType` registration failure cannot hide
behind the larger lit suite. Acceptance evidence for this fix is the green
`Validate / lit` lane on a non-AVX-512 runner, not a local rebuild.

## P0 open — `TileToX86Pass` loads a dialect during pass execution

Found while verifying the fix above, on an **assertions-enabled** LLVM/MLIR 23.
Distinct defect, same code path, and **CI structurally cannot see it**.

`src/transforms/lib/TileToX86Pass.cpp:1045` calls
`getContext().getOrLoadDialect("tessera_x86")` from inside `runOnOperation()`,
by name, to avoid linking the optional backend library. MLIR forbids loading a
dialect during pass execution:

```
LLVM ERROR: Loading a dialect (tessera_x86) while in a multi-threaded execution
context (maybe the PassManager): this can indicate a missing `dependentDialects`
in a pass for example.
```

That guard is `#ifndef NDEBUG`. The CI lit lane builds Release against apt
LLVM/MLIR 23 (assertions off), so the check is compiled out and the load becomes
silent undefined behaviour that happens to survive. On an assertions-enabled
build it is a hard error that fails **12 of the 15** x86 fixtures — i.e. the
whole x86 lit suite is currently unrunnable on a normal assert-enabled developer
toolchain, which is the second reason this backend's Decision #19 claim has been
easy to overstate.

Not fixed here, because the fix is a layering decision rather than a bug edit:
the canonical remedy is declaring the dialect in `getDependentDialects()`, which
needs the C++ type and therefore couples `TesseraPasses` to the optional
`TesseraX86IR`. `TesseraPasses` links **no** backend Target IR library today, so
this would establish a new dependency direction (core passes → optional backend)
and wants an explicit owner decision under Decisions #19/#31. The narrower
alternative — a `TESSERA_HAS_X86_TARGET_IR` compile guard around both the
`registry.insert<TesseraX86Dialect>()` and the existing fail-closed diagnostic —
keeps the coupling optional and is the recommended shape.

Note for whoever picks this up: `Pass::initialize(MLIRContext*)` is **not** an
escape hatch. Its contract explicitly forbids loading dialects and redirects to
`getDependentDialects()`.

The production HIP build was also rebuilt with both
`TESSERA_BUILD_ROCM_BACKEND=ON` and `TESSERA_BUILD_X86_BACKEND=ON`. Its feature
Expand Down
46 changes: 44 additions & 2 deletions src/compiler/codegen/tessera_x86_backend/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -17,13 +17,29 @@ target_compile_options(tessera_x86_base PRIVATE
-march=x86-64 -mno-avx -mno-avx2 -mno-avx512f
)

# Try to detect and add compiler flags for AVX-512 / AMX
# Try to detect compiler flags for AVX-512 / AMX.
#
# These are COLLECTED here and applied per-target at the end of the kernel
# section -- deliberately NOT via `add_compile_options`, which is directory
# scoped and therefore leaks into every `add_subdirectory` below it. That leak
# is what made `tessera-opt` die with SIGILL inside
# `TesseraX86Dialect::initialize()` on any host without AVX-512
# (`X86-DIALECT-LOAD-CRASH-2026-08-12`): the hardware-free Target IR dialect in
# `lib/IR` was compiled with `-mavx512f`, so the compiler was free to emit an
# AVX-512 encoding (e.g. `vpbroadcastq %rgpr, %xmm`, which is AVX-512-only) into
# dialect registration -- code that by contract must run on any host at all.
#
# Position-independence is the point: the earlier arrangement was correct only
# as long as nobody added a subdirectory after this block, and that is not a
# property a build system should ask a reader to maintain by hand.
include(CheckCXXCompilerFlag)

set(TESSERA_X86_ARCH_FLAGS "")

macro(try_add_flag flag var)
check_cxx_compiler_flag(${flag} ${var})
if(${var})
add_compile_options(${flag})
list(APPEND TESSERA_X86_ARCH_FLAGS ${flag})
endif()
endmacro()

Expand Down Expand Up @@ -217,6 +233,32 @@ add_library(tessera_x86_elementwise SHARED
src/kernels/kv_cache_f32.cpp
)

# ------------------------------------------------------------------
# Apply the detected AVX-512 / AMX flags to the KERNEL targets only.
#
# Enumerating this directory's targets keeps the rule automatic: a kernel target
# added later is covered without anyone remembering to extend a hand-written
# list, while targets in subdirectories -- the hardware-free Target IR dialect
# in `lib/IR` -- are structurally excluded, because BUILDSYSTEM_TARGETS is
# per-directory.
#
# `tessera_x86_base` is excluded on purpose: it already pins itself to baseline
# x86-64 via PRIVATE options, and appending `-mavx512f` after those would
# silently re-enable exactly what it opted out of.
# ------------------------------------------------------------------
if(TESSERA_X86_ARCH_FLAGS)
get_property(_tessera_x86_kernel_targets
DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}" PROPERTY BUILDSYSTEM_TARGETS)
foreach(_tgt IN LISTS _tessera_x86_kernel_targets)
if(NOT _tgt STREQUAL "tessera_x86_base")
target_compile_options(${_tgt} PRIVATE ${TESSERA_X86_ARCH_FLAGS})
endif()
endforeach()
message(STATUS
"tessera_x86 kernel arch flags: ${TESSERA_X86_ARCH_FLAGS} "
"(kernel targets only; lib/IR stays baseline)")
endif()

# ------------------------------------------------------------------
# tessera_x86 Target IR dialect (Decision #19, built by W0.10)
#
Expand Down
21 changes: 21 additions & 0 deletions src/compiler/codegen/tessera_x86_backend/lib/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
# The tessera_x86 Target IR dialect is HARDWARE-FREE by contract (Decision #19):
# its whole reason to exist is that lit can check it "on any host, including
# hosts with no AMX". A host-specific ISA flag reaching this translation unit
# breaks that contract in the worst possible way -- not at build time, but as a
# SIGILL the first time the dialect registers itself, which reads as a corrupt
# MLIR install rather than a build misconfiguration
# (`X86-DIALECT-LOAD-CRASH-2026-08-12`).
#
# Fail the CONFIGURE instead. Per Decision #21a this is a semantic key, so it
# fails closed and says why rather than quietly building something that only
# runs on some machines.
get_directory_property(_tessera_x86_ir_dir_opts COMPILE_OPTIONS)
if(_tessera_x86_ir_dir_opts MATCHES "-mavx|-mamx|-march=|-mtune=")
message(FATAL_ERROR
"tessera_x86 Target IR dialect would be compiled with host-specific ISA "
"flags (${_tessera_x86_ir_dir_opts}). The dialect must stay baseline so it "
"loads on hosts without AVX-512/AMX. Apply arch flags with "
"target_compile_options() on the kernel targets, never add_compile_options() "
"in a directory that has subdirectories.")
endif()

set(LLVM_TARGET_DEFINITIONS ${CMAKE_CURRENT_SOURCE_DIR}/../../include/TesseraX86/IR/TesseraX86Ops.td)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../include/TesseraX86/IR)
mlir_tablegen(TesseraX86Ops.h.inc -gen-op-decls)
Expand Down
Loading