Mettle

Reading the report

A diagnostic says the program is wrong. The report says what the optimizer did with a program that is right, and what stopped it where it stopped.

mettle example.mettle --release --explain -o example.exe
── optimization report: example.mettle ────────────────────────────────

  where to start (1 of 1 missed optimization has a fix)
    1. proven main:18  bind the array to a pointer once before the loop
       proven = applied to a clone and re-checked

  sum (loop @ line 7): vectorized → vpaddd, 8-wide int32 sum (AVX2)
  main (loop @ line 18): NOT vectorized  [store-only-fill]
      18 │ for i in 0..8 {
      19 │     data[i] = (int32)i + 1;
      └─ reason: the loop fills the stack array `data`, whose address is
         retaken on every iteration; the fill kernel indexes off one
         invariant base pointer, and a fresh base each iteration is not one
      └─ fix: bind the array to a pointer once before the loop
         (`var p: int32* = &data[0];`) and write `p[i]` in the body
      └─ verified: simulated that fix and re-ran the optimizer: this loop
         then vectorizes → 8-wide int32 element-wise map (AVX2, bit-exact)
  main (22 calls, lines 81-119): inlined
      └─ calls: println (x9), array_sum, gcd, lo_byte, print (x8)

The verdict line

main (loop @ line 18): NOT vectorized  [store-only-fill]
└──┬─┘ └──────┬──────┘  └──────┬─────┘  └───────┬───────┘
function    what it is       verdict       decision code

The decision code appears only on a refusal, because on a success the verdict already says what happened. It names the specific rule that declined, and it is a link: mettle explain store-only-fill, or its page here.

The detail lines

One line per fact, so a pattern that matches a whole reason keeps matching one line.

Where to start

The findings are in source order, which is the right order to read a file in and the wrong order to decide what to do. The block at the top answers "what do I change", ranked by what the compiler can stand behind:

Whole-function codegen fallbacks lead the ranking. A loop remark is a prediction about one loop; a fallback is a measurement over a whole function that already happened, and it costs every value in that function a register.

The other sections

The memory report repeats the memory and lifetime findings, and is printed only when there are any. The backend report says how much of the program reached the register-allocating backend, and groups whatever fell back to baseline codegen by cause, largest first.

Narrowing it down

--explain=matvec              one function
--explain=store-only-fill     one decision code
--explain=missed              only the refusals
--explain=fixable             only findings with a fix
--explain=proven              only fixes the compiler proved
--explain=loops               only loop verdicts
--explain=calls               only call verdicts

The selector hides prose only. The machine-readable sidecar and the tallies stay whole-file, so a filtered run and an unfiltered one produce the same document.

For tools

--explain-json also writes <output-stem>.explain.json: the same findings as structured data, plus a startHere array carrying the ranking above. --explain-all covers every file rather than the one being compiled.

A long report goes to <output-stem>.explain.txt and stderr gets a digest with the path. METTLE_EXPLAIN_REPORT_LINES sets the threshold; 0 keeps everything on stderr.

The rule it follows

Every fix the report suggests has been applied to a clone and re-checked before printing. If the compiler cannot prove the advice works, it either says so or says nothing.