ADR-0042: Fail-Closed Tail and Control-Flow Encoding Policy 1.3

Status: accepted; encoder policy 1.3.0 implemented and locally validated; Gate B remains open

Date: 2026-07-30

Visibility: private NAUX architecture/governance record. This ADR is not public roadmap material.

Supersedes: the encoder-policy version and unconditional two-phase tail-copy rule of ADR-0037 only

Preserves: the R1-S7a target schema, lowering policy, ABI, Machine IR semantics, source provenance, target-plan evaluator relation, numeric policy, and all R1-S7b/R1-S8 authority boundaries

Related: ADR-0037, ADR-0038, ADR-0039, ADR-0040, ADR-0041

Context

ADR-0037 deliberately chose a simple stack-home encoder. Every tail transfer staged the complete argument vector into a non-aliasing outgoing area and then copied it into callee parameter homes. This gave an obvious simultaneous-assignment proof and constant native stack usage, but it made the frozen BranchMix lighthouse spend most of its runtime moving values that were already in their destination homes.

The pre-optimization BranchMix target contained:

functions                 121
blocks                    139
tail terminators          127
raw target code        43,124 bytes
frame                     240 bytes

A static audit of those 127 tail transfers found:

exact-identity arguments                    969
machine words occupied by those identities 1,100
non-identity immediate words                 17
non-identity Home words                     172
non-identity words with a direct schedule   177
non-identity words requiring fallback        12
cyclic transfers                               2

The target also contained 28 empty exact-identity tail blocks and nine exact I64Setcc -> TailJump -> empty Branch shapes. A broader audit found 90 composable tail sites, 189 non-identity hops, and a maximum chain length of eight.

The fixed Gate B trace confirmed that this was a dynamic problem. Before empty-tail composition it executed 99,410,299 blocks and 86,827,257 tail jumps per measured invocation.

The encoder needs a deterministic policy that removes provably redundant transfers and control edges while retaining simultaneous-assignment semantics. It must remain owned, dependency-free, bounded, replayable, and fail closed.

Decision drivers

  • Reduce dominant stack-home and tail-transfer traffic before introducing a general register allocator.
  • Preserve exact typed simultaneous assignment, including arrays and cycles.
  • Keep Machine IR, target-plan semantics, source origins, and ABI unchanged.
  • Make every byte change deterministic and part of target identity.
  • Refuse an optimization whenever its structural proof is incomplete.
  • Retain a conservative correct path for every already admitted valid program.
  • Introduce no assembler, linker, SMT solver, optimizer framework, or other external dependency.
  • Accept or reject performance work using exact evidence, not expected speedup.

Options considered

OptionBenefitCost
Keep encoder policy 1.0Smallest proof surfaceGate B remains dominated by redundant tail traffic
Change Machine IR or specialization outputCould expose a simpler graph earlierExpands the semantic boundary before the encoder-local problem is understood
Introduce a general register allocator immediatelyMay remove more memory trafficAdds liveness, interference, spills, and verification obligations too early
Elide identities onlyLarge safe first reductionLeaves acyclic transfers and redundant control edges
Compose every empty-tail chainRemoves the most jumpsCan turn cheap transfers into an expensive cyclic two-phase copy
Adopt layered encoder policy 1.3Measurable speedup with conservative fallbackIncreases encoder complexity and current code size

Decision

1. Encoder identity and migration

The accepted encoder policy is:

X64_TARGET_ENCODER_POLICY_VERSION = 1.3.0

The version participates in target-plan and artifact identity. No policy-1.0, experimental 1.1/1.2, or naive-composition artifact is reinterpreted as policy 1.3. R1-S7a, R1-S7b, R1-S8, process, IPC, standalone, and correspondence identities must migrate together and replay independently.

This change affects raw realization only. It does not authorize a change to source Core, Residual Core, SSA, Machine IR, target ABI, effects, numeric semantics, or result semantics.

2. Validate before optimizing

Every tail transfer first validates:

  • callee existence;
  • exact argument arity;
  • argument and parameter types;
  • source and destination homes;
  • complete outgoing-area extent;
  • checked offset arithmetic.

Optimization is never used to make malformed input appear admissible.

3. Exact identity elision

An argument is an identity only when it is a typed Home operand exactly equal to the corresponding callee parameter home, including slot, offset, width, and machine type.

Exact identities emit no load, stage, store, or commit. Mere value equivalence, overlapping storage, equal offsets with different types, and partial array overlap do not qualify.

4. Deterministic destructive-copy scheduling

After identities are removed, policy 1.3 attempts a direct parallel-copy schedule.

For every pending move, the encoder expands source and destination homes into 64-bit word locations. It repeatedly chooses the first pending move, in canonical argument order, whose destination words do not occur in any remaining source home. The move is emitted and removed from the pending set.

A direct schedule is accepted only when:

  • all destination word sets are unique and non-overlapping;
  • every pending move can be removed by the rule;
  • the complete schedule is deterministic;
  • typed aggregate movement preserves its source before any overlapping write.

F64Array remains one typed {pointer, length} value. Both source words are loaded before either destination word is stored.

If no candidate exists, the complete direct schedule is refused. The encoder uses the conservative two-phase path for every non-identity argument: stage all sources, then commit all destinations. This preserves swaps, longer cycles, and simultaneous assignment.

5. Exact compare-tail-branch fusion

The encoder may fuse only this closed shape:

  1. the source block contains exactly one signed I64Setcc;
  2. its terminator tail-jumps to the declared entry of a callee;
  3. the callee entry contains no instruction and ends in BranchRel32;
  4. the branch condition is one callee Bool parameter;
  5. the compare result is the only non-identity tail argument and maps exactly to that condition parameter;
  6. every sibling argument is an exact typed identity;
  7. the comparison is signed less-than or signed greater-or-equal.

The fused template loads both I64 operands, emits cmp, canonicalizes the Bool with setl/setge plus zero extension, stores it directly in the callee condition home, and emits the signed conditional branch plus the else jump. The dead source-result home, tail copy, condition reload, and test are not emitted. setcc, zero extension, and the store preserve the comparison flags.

Any additional instruction, non-identity sibling, immediate branch condition, type mismatch, different entry route, or unsupported comparison refuses fusion and retains ordinary encoding.

6. Exact no-op target threading

Entry transfer, ordinary branch arms, ordinary tail targets, and fused branch arms may thread transitively through an empty block only when its sole action is an exact typed identity tail transfer to the declared callee entry.

Traversal is deterministic and bounded by the finite target program. Missing labels fail validation. A detected cycle returns the caller’s original target; it never invents a cycle exit.

7. Direct-acyclic empty-tail composition

Policy 1.3 may compose a tail route through transitive empty callee entries. At each hop it substitutes the current caller-side operand for the uniquely matching callee parameter home.

Composition requires:

  • exact declared entry labels at every hop;
  • empty intermediate entries;
  • a tail terminator at every traversed intermediate entry;
  • exact arity and type preservation;
  • unique parameter-home lookup;
  • bounded traversal no longer than the function count;
  • no repeated callee, ambiguous home, unbound home, malformed target, or arithmetic failure.

A structurally valid composed route is selected only when its final parallel transfer has a complete direct destructive-copy schedule under section 4. If the final transfer would require two-phase staging, the encoder retains the complete original route.

This final gate is normative. Fewer jumps alone is not sufficient evidence that a route is cheaper.

8. Fail-closed behavior

There are two conservative outcomes:

  • malformed target input produces the existing typed raw-encoding error and exposes no artifact;
  • a valid target that does not satisfy an optimization proof uses its original encoding or the two-phase copy fallback.

No classifier may weaken type, bounds, numeric, effect, ABI, fixup, or source-provenance validation.

Evidence

Static artifact evidence

The accepted policy-1.3 lighthouse shapes are:

FieldBranchMixBounds
Functions1219
Blocks1399
Labels14212
Fixups16214
Plan bytes34,7421,653
Semantic artifact bytes44,8632,654
Raw target code bytes8,070726
Frame bytes240144

The BranchMix code-size history was:

Encoder experimentCode bytes
Original unconditional two-phase encoding43,124
Identity elision only7,924
Identity elision plus acyclic direct scheduling5,092
Compare fusion plus no-op threading5,002
Naive unrestricted empty-tail composition, rejected10,854
Direct-acyclic composition, accepted policy 1.38,070

Direct-acyclic composition accepts 78 of 90 statically composable sites and 165 of 189 non-identity hops. Twelve sites are conservatively uncomposed. Policy 1.3 is 1.6134x larger than policy 1.2 for BranchMix, but 81.29% smaller than the original target.

Dynamic composition evidence

For the frozen BranchMix Gate B workload:

MetricBefore compositionNaive compositionDirect-acyclic policy 1.3
Executed blocks99,410,29942,678,51251,067,120
Executed tail jumps86,827,25730,095,47038,484,078
Tail copy words141,354,178161,590,215128,035,793
Tail memory operations265,195,925305,667,998238,559,154

Naive composition bypassed more jumps but added 20,236,037 copy words and 40,472,073 tail memory operations. Its native benchmark regressed, so it is rejected.

The direct-acyclic gate produces:

accepted dynamic composition events       21,706,861
non-identity hops bypassed                 48,343,179
tail jumps removed                         48,343,179
tail copy words removed                    13,318,385
tail memory operations removed             26,636,771

Relative to the pre-composition trace, it reduces tail jumps by 55.68%, copy words by 9.42%, and tail memory operations by 10.04%.

Gate B observation history

All values below are exact local median*2 integers from the frozen paired sampler. Each row has its own paired baseline observation.

Encoder stateNAUX median x2 (ns)Baseline median x2 (ns)Ratio
Original policy 1.01,051,667,14012,799,04382.1676x
Identity-only experiment157,223,01212,744,32812.3367x
Identity plus direct scheduler95,815,43512,742,8127.5192x
Policy 1.2 fusion/threading83,250,49012,718,2356.5458x
Naive composition, rejected87,242,87412,754,2486.8403x
Accepted policy 1.375,040,13312,783,6745.869997x

The accepted policy-1.3 observation additionally records:

NAUX p95                 39,549,080 ns
baseline p95              6,472,724 ns
NAUX CV admission                  true
baseline CV admission              true
Gate B <= 2.0x threshold          false

Policy 1.3 lowers the NAUX median by 9.862% relative to policy 1.2, a 1.1094x incremental speedup. Relative to the original policy-1.0 observation, the cumulative speedup is 14.0147x.

These are local engineering observations. They do not close Gate B: the ratio is above 2.0x and claim-bearing clean-revision and host-admission requirements remain separate.

Consequences

Positive

  • Exact identity traffic disappears without changing Machine IR.
  • Most acyclic parallel transfers no longer use outgoing staging.
  • Cycles retain the original simultaneous-assignment proof.
  • Exact compare/branch continuations avoid redundant materialization.
  • Direct-acyclic composition reduces both control and memory traffic.
  • The change remains deterministic, bounded, source-replayable, and free of third-party backend dependencies.
  • Gate B distance falls from 82.1676x to 5.869997x locally.

Negative

  • BranchMix policy-1.3 code is larger than policy 1.2 because composed direct copies are emitted at source sites while bypassed bodies remain encoded.
  • The raw encoder has a larger proof and adversarial-test surface.
  • Every target, native, IPC, standalone, and ELF identity changes together.
  • The direct-acyclic predicate may reject profitable cyclic compositions.
  • The measured gain is lighthouse-specific, not a universal performance claim.

Risks and mitigations

  • Code growth may increase instruction-cache pressure. Retain exact code-size evidence and make future cost policies account for dynamic traffic and emitted bytes.
  • Operand substitution could confuse equal-looking homes. Require unique exact typed-home identity and retain the original route otherwise.
  • Destructive copies could clobber a live source. Accept only the deterministic word-dependency schedule; otherwise stage in two phases.
  • Performance tuning could bypass provenance. Keep optimization inside the versioned owned encoder and regenerate the complete authority chain.

Next target

Gate B remains open. The next performance target is an interference-safe tail-SCC home-coalescing/superblock policy that attacks the remaining dominant stack-home traffic. Compare materialization and bounds-proof work come after that larger structural bottleneck.

Any change to plan semantics, register authority, reachability rules, or allocation policy requires a new versioned decision and fresh correspondence evidence. Gate B may be reported complete only when ADR-0041 admission reaches <= 2.0x; this ADR makes no such claim.