advanced27 min studyLesson 530 in Engineering

Differential testing needs a valid reference domain

Compare lowering stages under the same semantics, with explicit floating-point criteria and memory-safety checks.

On this page

What you’ll understand

  • Define valid inputs and a reference contract before differential comparison.
  • Separate value mismatch, permitted numeric difference, and invalid source execution.
  • Use stage localization and boundary-case reduction without treating tests as a full proof.

Differential testing runs related implementations and compares their behavior. It is powerful for compiler lowering only when the reference and candidate share a valid semantic domain. An undefined reference operation or a silently different numeric mode can produce a misleading mismatch. Conversely, a permissive tolerance can hide a real indexing or alias bug. Define what must agree, which differences are allowed, and which input cases the source actually specifies.

The reference must mean the same computation

Record shapes, dtypes, layouts, allowed aliasing, integer overflow rules, floating-point mode, and operation-specific preconditions. Division by zero or out-of-range conversions may be undefined or produce poison under the selected IR contract rather than supply a meaningful reference output. LLVM 20.1.0 documents those distinctions explicitly. Exclude invalid test inputs or test the appropriate defined failure behavior; do not infer a compiler bug merely because two invalid executions happen to disagree.

For strict operations, compare required exact behavior, including signed zero or exceptional values where the contract preserves them. For an approximate or reassociated computation, use a tolerance justified by its actual specification and workload, with NaN and infinity handling defined separately. A model-level quality threshold is not automatically a valid per-operation compiler tolerance. Keep numerical-mode changes visible so a strict baseline is not silently replaced by a more permissive reference just to make tests pass.

∣yi−y^i∣≤εabs+εrel∣yi∣|y_i-\hat y_i|\leq\varepsilon_{\rm abs}+\varepsilon_{\rm rel}|y_i|
This is one explicitly chosen finite-value comparison rule, with absolute tolerance in output units and dimensionless relative tolerance. It is not a universal compiler correctness criterion and needs separate NaN, infinity, signed-zero, and exact-contract handling.↔ Scroll wide equations horizontally.

Test boundaries that transformations actually change

Use zero and small dimensions where valid, values around tile and vector boundaries, non-square shapes, noncontiguous views, nonzero offsets, and permitted overlap. Include cancellation and conversion boundaries for floating-point transformations. A random dense tensor often misses a one-element tail or an old-value consumer. Memory checks and guarded allocations complement value comparisons because an out-of-bounds read can leave outputs apparently correct while violating the execution contract.

Compare intermediate representations or stage outputs when possible: tensor semantics, post-bufferization behavior, scheduled loops, vectorized code, and the final kernel. A failure appearing after one pass narrows the investigation but does not automatically prove that pass is at fault; earlier invalid IR may only become observable later. Preserve verifier diagnostics, compiler revision, flags, target, and a minimized reproducer. Reduction should retain the legality assumptions and numerical mode that made the original case meaningful.

∀x∈D: Obs⁡(P,x)≡CObs⁡(L(P),x)\forall x\in\mathcal D:\ \operatorname{Obs}(P,x)\equiv_{\mathcal C}\operatorname{Obs}(L(P),x)
The intended lowering contract compares observable behavior on valid domain D under specification C. Tests inspect a finite subset and therefore provide evidence rather than proving this universal statement for every program and input.↔ Scroll wide equations horizontally.

Use independent checks and preserve the artifact

A reference that shares the same faulty indexing helper can reproduce the same bug and falsely agree. Use an independently understandable small implementation and manually checked cases alongside randomized testing. For pure independent elementwise operations, a proven permutation relation can provide another check; do not invent algebraic metamorphic rules that fail under floating-point or side effects. Cross-target differences can reveal issues, but compare their supported semantics and allowed precision before declaring one target wrong.

The function lab illustrates a known analytic reference only. Reset and set both coefficient a=1 and position x=1, predict y=1, tangent slope 2, and integral from 0 to 1 equal 1/3, then inspect with Step. It computes y=ax² and associated formulas, not a tensor compiler or test generator. An implementation matching this small family does not validate arbitrary lowering. Use the contrast to explain why a few passing inputs are useful evidence yet cannot establish the universal correctness statement above.

A declared finite-value tolerance

For three finite scalar outputs, reference values are[0,1,10] and absolute candidate errors are[0.0005,0.002,0.03]. Use an explicitly allowed comparison with absolute tolerance 0.001 and relative tolerance 0.002; ignore representation rounding for these displayed decimal calculations.

  1. The permitted bounds are 0.001+0.002×0=0.001,0.001+0.002×1=0.003, and 0.001+0.002×10=0.021.

  2. The first two errors lie inside their bounds. The third error 0.03 exceeds 0.021, so the vector fails this declared comparison even though two positions pass.

  3. This rule would be inappropriate if the operation required exact agreement or if NaN, infinity, or signed-zero distinctions needed separate handling. Diagnose the failed output under the actual contract rather than simply enlarging tolerances until it passes.

The result

A tolerance is a stated acceptance rule with a domain, not a universal excuse for changed computation or an automatically correct reference.

Explore the model

Interactive lab

Interactive lab · function

A small exact family is limited evidence

Reset, set a=1, x=1;predict y=1, slope 2, area 1/3, then Step. This fixed quadratic model is not a tensor compiler, differential-test engine, or proof of arbitrary program correctness.

A small exact family is limited evidenceThis lab uses only y = ax². Playback traces the curve within the fixed integration interval from 0 to x; it does not estimate numerical error or change the chosen point. Current readings: y at chosen x: 0.608; Tangent slope · 2ax: 1.35; Signed area · ax³/3: 0.182. All parameters are adjustable with the labeled controls below.−2.4−1.201.22.4−9−4.504.59xy(x, ax²)
y = ax²TangentSigned integral
y at chosen x
0.608
Tangent slope · 2ax
1.35
Signed area · ax³/3
0.182
t = 0 s

This lab uses only y = ax². Playback traces the curve within the fixed integration interval from 0 to x; it does not estimate numerical error or change the chosen point. Parameter changes pause playback and recompute the model at the current elapsed time. Reset restores both parameters and returns time to zero. Playback starts paused. Adjust either parameter, then choose Play or Step.

Look forKnown analytic cases complement tests, while the claimed verification scope must remain explicit.

Check your understanding

A reference execution contains an operation outside its defined source domain. What should a differential test conclude from a mismatch?

Try it yourself

A test uses relative tolerance 0.01 and absolute tolerance 0.001 for a finite reference value 0.02. Compute the allowed absolute error under the stated rule. Then name a correctness issue that value agreement alone can miss.

Take a moment to make a prediction or work it out on paper. Open a hint when you need one.

Give me a hint

Multiply relative tolerance by the reference magnitude, then add the absolute allowance.

Compare with the solution

The bound is 0.001+0.01×0.02=0.0012 output units. This numerical agreement alone can miss out-of-bounds accesses, premature deallocation, data races, or incorrect effects that happen not to change the sampled output. Use memory/effect checks and stage-aware tests in addition to a tolerance, and apply exact comparison when the actual operation contract requires it.

Take it with you

  • A valid reference domain and shared numeric contract come before comparison.
  • Boundary, alias, lifetime, and effect checks complement output values.
  • Finite tests support evidence; they do not prove universal lowering equivalence.

Read further

Original sources and deeper explanations to follow at your own pace.

Optional progress, saved in this browser when available. Revisit any lesson at any time.

Lesson not marked complete.