# Support matrix (/docs/support-matrix)

<!-- Generated by scripts/gen.mjs from docs/support-matrix.md in the marmot repo. Do not edit by hand. -->

Generated from marmot's test results of 2026-11-12. Every test builds a program with marmot and with Go and compares the output and exit status.

Status words: **works** (every test passes), **partial** (some fail), **missing** (not implemented), **untested**.

## Conformance numbers [#conformance-numbers]

Every test compares stdout, stderr (up to the first panic line) and exit status with the stock Go toolchain.

| Tier | Passing | Total | What it covers |
| --- | --- | --- | --- |
| run/core | 134 | 134 | language core, no imports, `println` only |
| run/gc | 13 | 13 | allocation heavy programs |
| run/sched | 15 | 15 | goroutines, channels, deadlock |
| run/std | 235 | 238 | standard library by package |
| run/opt | 21 | 22 | optimizer and specializer targets |
| run/mem | 50 | 50 | use after free and lifetime hunting (every way a slice stays reachable) |
| run/layout | 49 | 49 | struct layouts: every field mix, every access path |
| run/audit | 33 | 41 | counterexamples from the spec and verify audits |
| run/apps | 12 | 12 | 200 to 600 line real programs |
| goroot | 98 | 108 | single file programs from the Go project's own test suite |
| world | 29 | 32 | real open source modules (vendored, pinned) |
| **total (dev build)** | **689** | **714** | |

Other build modes in the same run:

| Mode | Passing | Total |
| --- | --- | --- |
| dev | 689 | 714 |
| gcstress | 50 | 50 |
| lifetime | 49 | 50 |

## Language [#language]

| Feature | Status | Tests |
| --- | --- | --- |
| Integers: wraparound, shifts, division, conversions | works | 13 of 13 |
| Floats: NaN, infinities, conversions, printing | works | 6 of 6 Fused multiply-add follows gc on arm64. |
| Complex numbers | works | 2 of 2 |
| Strings, runes, UTF-8 iteration and conversion | works | 7 of 7 |
| Slices: append, copy, aliasing, capacity | works | 10 of 10 Growth capacities may differ from gc. |
| Arrays and structs: copy, compare, embedding | works | 9 of 9 |
| Maps, all key kinds, iteration with deletion | works | 8 of 8 Iteration order is random, as in gc. |
| Methods, method values and expressions | works | 2 of 2 |
| Closures and Go 1.22 loop variables | works | 4 of 4 |
| Interfaces, assertions, type switches | works | 12 of 12 |
| Generics: functions, types, constraints | works | 5 of 5 |
| defer, panic, recover | works | 18 of 18 |
| Runtime panics: bounds, nil, divide, assertions | works | 8 of 8 Message text matches gc; the stack trace format differs. |
| Control flow: labels, goto, switch, range over int and func | works | 10 of 10 |
| Constants and iota | works | 2 of 2 |
| Initialization order and init functions | works | 2 of 2 |
| Evaluation order | works | 2 of 2 Variables are read after calls in the same expression, as gc does. |
| Goroutines, channels, select | works | 26 of 26 |
| Garbage collection (allocation heavy programs) | works | 13 of 13 |
| unsafe | works | 5 of 5 |
| Compiler optimizations preserve semantics | partial | 21 of 22 Loop, specialization and float tests; run at -O0, -O2, -Oz and -release. |
| Real programs (parsers, interpreters, simulations) | works | 12 of 12 |
| cgo | missing | non-goal for v1 |
| Race detector (-race) | missing | non-goal for v1 |
| plugin package | missing | non-goal for v1 |
| DWARF debug info | missing | non-goal for v1 |
| Windows | missing | non-goal for v1 |

## Standard library [#standard-library]

Each row is a directory under `tests/run/std`. Packages not listed have no test yet.

| Packages | Status | Tests |
| --- | --- | --- |
| sync/atomic | works | 10 of 10 |
| bufio | works | 11 of 11 |
| bytes | works | 10 of 10 |
| compress/* | works | 1 of 1 |
| encoding/{base32,base64,hex,binary,csv,xml,gob,asn1,pem,ascii85} | works | 4 of 4 |
| errors | works | 10 of 10 |
| path, path/filepath | works | 5 of 5 |
| fmt | works | 14 of 14 |
| container/{heap,list,ring} | works | 3 of 3 |
| net/http, httptest, cookiejar, crypto/tls | works | 8 of 8 |
| io | works | 11 of 11 |
| encoding/json | works | 8 of 8 |
| log | partial | 1 of 2 |
| maps | works | 10 of 10 |
| math, math/bits, math/cmplx | works | 12 of 12 |
| net, net/netip | works | 6 of 6 |
| os, os/user | works | 12 of 12 |
| math/rand | works | 3 of 3 |
| reflect | partial | 7 of 8 |
| regexp | works | 6 of 6 |
| runtime, runtime/debug | missing | 0 of 1 |
| slices, cmp | works | 10 of 10 |
| log/slog | works | 1 of 1 |
| sort | works | 10 of 10 |
| database/sql | works | 1 of 1 |
| strconv | works | 10 of 10 |
| strings | works | 10 of 10 |
| sync | works | 12 of 12 |
| text/template | works | 5 of 5 |
| time, time/tzdata | works | 14 of 14 |
| unicode, unicode/utf8, unicode/utf16 | works | 10 of 10 |

### Stock standard library tests under `marmot test` [#stock-standard-library-tests-under-marmot-test]

Results of `marmot test -short` on stock packages (darwin/arm64 laptop, 2026-11-12, before the fixes). "alloc counts only" means every failure is a `testing.AllocsPerRun` count.

| package | result | pass | fail | rate |
| --- | --- | --- | --- | --- |
| fmt | ok | 79 | 0 | 100% |
| strings | FAIL | 146 | 5 | 97% |
| bytes | FAIL | 175 | 3 | 98% |
| strconv | FAIL | 69 | 11 | 86% |
| sort | ok | 81 | 0 | 100% |
| slices | FAIL | 162 | 3 | 98% |
| maps | ok | 24 | 0 | 100% |
| math | ok | 111 | 0 | 100% |
| unicode | ok | 42 | 0 | 100% |
| unicode/utf8 | FAIL | 30 | 1 | 97% |
| time | FAIL | 46 | 2 | 96% |
| sync | build | 0 | 0 | - |
| sync/atomic | ok | 107 | 0 | 100% |
| context | FAIL | 68 | 1 | 99% |
| errors | ok | 92 | 0 | 100% |
| io | FAIL | 77 | 2 | 97% |
| bufio | FAIL | 88 | 1 | 99% |
| os | FAIL | 3525 | 11 | 100% |
| os/exec | FAIL | 23 | 57 | 29% |
| os/signal | FAIL | 5 | 1 | 83% |
| path | ok | 16 | 0 | 100% |
| path/filepath | FAIL | 59 | 1 | 98% |
| encoding/json | FAIL | 0 | 1 | 0% |
| encoding/binary | build | 0 | 0 | - |
| encoding/base64 | ok | 23 | 0 | 100% |
| encoding/hex | ok | 18 | 0 | 100% |
| encoding/csv | ok | 77 | 0 | 100% |
| encoding/xml | FAIL | 332 | 3 | 99% |
| encoding/pem | ok | 21 | 0 | 100% |
| regexp | ok | 75 | 0 | 100% |
| text/template | FAIL | 58 | 1 | 98% |
| html/template | FAIL | 0 | 0 | - |
| text/tabwriter | ok | 6 | 0 | 100% |
| text/scanner | ok | 22 | 0 | 100% |
| net/url | FAIL | 89 | 5 | 95% |
| net/http | build | 0 | 0 | - |
| net/http/httptest | FAIL | 51 | 3 | 94% |
| net | FAIL | 9 | 0 | 100% |
| mime | FAIL | 24 | 1 | 96% |
| mime/multipart | FAIL | 49 | 4 | 92% |
| crypto/sha256 | FAIL | 33 | 2 | 94% |
| crypto/md5 | FAIL | 17 | 1 | 94% |
| crypto/sha1 | FAIL | 17 | 1 | 94% |
| crypto/hmac | ok | 233 | 0 | 100% |
| crypto/rand | FAIL | 14 | 2 | 88% |
| crypto/aes | ok | 58 | 0 | 100% |
| crypto/tls | FAIL | 0 | 0 | - |
| crypto/x509 | FAIL | 0 | 0 | - |
| hash/crc32 | ok | 18 | 0 | 100% |
| hash/fnv | ok | 62 | 0 | 100% |
| container/heap | ok | 9 | 0 | 100% |
| container/list | ok | 11 | 0 | 100% |
| container/ring | ok | 15 | 0 | 100% |
| math/rand | FAIL | 25 | 2 | 93% |
| math/rand/v2 | ok | 25 | 0 | 100% |
| math/big | FAIL | 266 | 1 | 100% |
| math/bits | build | 0 | 0 | - |
| reflect | build | 0 | 0 | - |
| runtime | build | 0 | 0 | - |
| log | FAIL | 9 | 2 | 82% |
| log/slog | FAIL | 225 | 29 | 89% |
| flag | FAIL | 28 | 1 | 97% |
| embed | build | 0 | 0 | - |
| io/fs | FAIL | 5 | 0 | 100% |
| compress/gzip | ok | 23 | 0 | 100% |
| compress/flate | ok | 128 | 0 | 100% |
| archive/tar | FAIL | 1 | 2 | 33% |
| archive/zip | FAIL | 0 | 0 | - |
| html | ok | 6 | 0 | 100% |
| go/token | FAIL | 25 | 1 | 96% |
| go/scanner | ok | 25 | 0 | 100% |
| go/parser | FAIL | 42 | 0 | 100% |
| go/ast | FAIL | 23 | 1 | 96% |
| go/format | ok | 5 | 0 | 100% |
| go/types | FAIL | 70 | 1 | 99% |
| iter | FAIL | 10 | 10 | 50% |
| unique | build | 0 | 0 | - |

## Real world modules [#real-world-modules]

Vendored at a pinned version under `tests/world` (see `tests/world/README.md`), each with a small deterministic program checked against stock Go.

| Module test | Status |
| --- | --- |
| base58 | works |
| blackfriday | works |
| cobra | works |
| decimal | works |
| difflib | works |
| doublestar | works |
| embedfs | works |
| fuzzysearch | works |
| gjson | works |
| gocmp | works |
| godiff | works |
| goldmark | works |
| gotoml | works |
| govaluate | works |
| humanize | works |
| ini | works |
| levenshtein | works |
| lru | works |
| mapstructure | fails |
| pflag | works |
| pkgerrors | works |
| rate | works |
| semver | works |
| strcase | works |
| tablewriter | works |
| testify | fails |
| toml | works |
| ulid | fails |
| uuid | works |
| xtext | works |
| xxhash | works |
| yaml | works |

29 of 32 world programs pass.

## Build modes [#build-modes]

- **dev** (default, `-O2`): the safe pipeline; every transform below that is marked off stays off.
- **`-release`**: whole program optimization, `-O3`, loop and library specializations.
- **`-O0` `-O1` `-O2` `-O3` `-Os` `-Oz`**: LLVM level; the conformance runner can run any program in `-O0`, `-O2`, `-Oz` and `-release` (`-modes`).
- **Opt-in lifetime and memory transforms**, each behind an environment switch. A transform is on by default only after a proof review and a full conformance matrix plus fuzz round with it forced on; until then it is off.

| Transform | Switch | Default |
| --- | --- | --- |
| In-place reuse (reuse.go) | MARMOT_REUSE | off |
| Capture by value (escape.go allocSettled) | MARMOT_BYVALUE | off |
| Region inference (region.go) | MARMOT_REGIONS | off |
| Frame regions (frameregion.go) | MARMOT_FRAME_REGIONS | off |
| Allocation sinking (allocsink.go) | MARMOT_ALLOCSINK | off |
| Escape summaries, cross package, extended rules | MARMOT_ESCAPE_SUMMARY, MARMOT_XPKG_ESCAPE, MARMOT_ESCAPE_EXT | off |
| Conversion and make frame buffers (stackconv.go) | MARMOT_STACKCONV | off |
| Intraprocedural escape (default path) | on | on |
| go-strings S3 no-copy (backend) | -no-strings-nocopy | on |
| Defer record elision (panics.go) | MARMOT_DEFERELIDE | off |
| Dead initializer removal (staticinit.go) | MARMOT_DEADINIT | off |
| Allocation without zeroing (rtcore rt_alloc_nozero, 569d095; poison fill c8e0a15) | callers only | on |

Stress modes used by the conformance runner: `gcstress` (`MARMOT_GCSTRESS=1`), `poison` (`MARMOT_POISON=1`), `lifetime` (`MARMOT_LIFETIME=all`).

## Targets [#targets]

| Target | Status | Tested |
| --- | --- | --- |
| darwin/arm64 | primary | all tiers above |
| linux/amd64 | cross compiled on macOS, run on a Linux test host | 99 of 99 conformance tests pass (tree `2c645f1`) |
| linux/arm64 | not tested | |

## Tools [#tools]

- `marmot build [flags] [packages or files]`: `-o`, `-O {0,1,2,3,s,z}` (default 2), `-release` (whole program, `-O3`, loop and library specializations), `-emit {mlir,llvm,obj,exe}`, `-dialect {llvm,go}`, `-gc {precise,none}`, `-target`, `-tags`, `-nocache`, `-v`, `-x`, `-work`.
- `marmot run [flags] file.go [args]`: build and run.
- `marmot test [-v] [-run RE] [-skip RE] [-bench RE] [-count N] [-timeout D] [packages]`: builds the `go list -test` main and runs it in the package directory.
- `marmot version`.

## Known differences from gc [#known-differences-from-gc]

- Panic output prints the same message and exits with status 2; the traceback below `goroutine N [running]:` is gc style but frames of inlined functions do not appear.
- Floating point uses the same fused multiply-add rule as gc on arm64 (`x*y+z` fuses, an explicit conversion does not).
- Variables are read after calls in the same expression, as gc does (the spec leaves this unspecified).
- `runtime.Caller` and friends work from a pc table; binaries built with `-s` have none.
- **NaN payloads.** Where the Go specification only says the result is a NaN, marmot may return a different NaN (payload and sign bits) than gc: the builtin `min` and `max` (also over slices, so `slices.Min` and `slices.Max`), `math.Max`, `math.Min`, and `math.Floor`, `Ceil`, `Trunc`, `Round` and `RoundToEven` of a signaling NaN (gc quiets it, marmot may return it unchanged). The value is a NaN in every case; only `math.Float64bits`, `math.Float32bits` or `unsafe` shows the difference, and gc itself differs here across architectures. Values that are not NaN are bit identical to gc on the same architecture; a difference there is a bug. Programs: `tests/run/audit/minmax_nan_payload`, `tests/run/audit/math_exp_log_bits`.
- Slice growth capacities and map iteration order are not guaranteed to equal gc's.
- Evaluation order: variables are read after the calls of the same expression; open cases are tracked in `tests/run/audit/evalorder_gaps`.
- Unexported methods of embedded types from different packages with the same name: see `world/audit_unexported` under open failures.
- cgo, the race detector, plugins, DWARF and Windows are not supported.
- `reflect`: see the open failures below for the current gaps.

## Open failures [#open-failures]

Listed in `tests/known_failures.txt`; a test that passes is removed from the list.

- `goroot/genmeth1`: 
- `goroot/range4`: 
- `goroot/reflectmethod1`: 
- `goroot/reflectmethod2`: 
- `goroot/reflectmethod3`: 
- `goroot/reflectmethod4`: 
- `goroot/reflectmethod5`: 
- `goroot/reflectmethod6`: 
- `goroot/reflectmethod7`: 
- `goroot/shift3`: 
- `run/std/reflect/kinds_names`: 
- `run/opt/fma_fusion_gc`: gc fuses x*y+z on arm64, marmot does not (spec allows both)
- `run/opt/panic_in_loop@Oz`: recovered panic then nil deref panic is not recoverable at -Oz
- `run/std/runtime/goroutines_gc`: runtime.Caller unsupported (no pc to file:line table yet)
- `run/std/log/basic`: runtime.Caller unsupported, log.Lshortfile prints ???:0
- `world/ulid`: return id, parse(&id): gc reads variables after calls (see core/eval_order_var_after_call)
- `run/mem/regionstore@lifetime`: MARMOT_LIFETIME=all: region store use-after-free, expected until fixed
- `world/audit_unexported`: unexported methods of different packages are confused in itabs
- `run/audit/deadinit_bigmake`: huge make: fatal "out of memory" instead of the makeslice panic (dead initializer removal)
- `run/audit/defer_builtin_recover`: recover() result lost for a deferred builtin
- `run/audit/evalorder_gaps`: map index evaluation order differs from gc
- `run/audit/fma_complex_mul`: complex multiply: fused multiply-add bits differ from gc
- `run/audit/make_huge_const`: make with a huge constant length does not panic like gc
- `run/audit/math_exp_log_bits`: math.Exp(-745.13) returns 0x1, gc 0x0 (value difference, not a NaN payload)
- `run/audit/method_value_nil_iface`: method value of a nil interface panics with the wrong message
- `run/audit/tempstring_write`: temporary string written through (no-copy conversion)