Skip to content

Backend Contracts

This page summarizes backend obligations for current UniversalToolchain/Wist execution paths.

For conceptual background, read Backends and Semantic Parity.

Backend modes

Current Wist-facing modes:

ModeMeaning
interpreterexecute AIR through the interpreter backend
compilercompile through the CIL backend when the selected runtime exposes CIL

Dialect files decide which backend modes are available for a runtime host.

Shared contract

Every backend must preserve:

  • AIR opcode semantics;
  • value stack behavior;
  • label and jump behavior;
  • external binding shape;
  • final result semantics;
  • supported intrinsic behavior;
  • explicit failure for unsupported operations.

Interpreter contract

The interpreter backend:

AreaContract
inputAIR plus execution environment
stateinstruction pointer, value stack, label positions, execution environment
labelsbuilt before execution from Label instructions
executionsequential dispatch over AIR instructions
final resultnull when stack is empty, otherwise top stack value
intrinsicsdelegated to interpreter intrinsic executor

The interpreter is useful as a semantic reference because behavior maps directly to AIR instructions.

CIL contract

The CIL backend:

AreaContract
inputAIR plus declared compilation input
outputDynamicMethod
argumentsIExecutionEnvironment first, then external binding argument types
return typederived by AIR type simulation
labelsconverted to IL labels with simulated stack state
intrinsicscompiled through CIL intrinsic compiler/registry
constantscurrent implementation stores pushed constants in generic static holders

The CIL backend is a compiler, not a second interpreter. Its type simulation and IL emission must still preserve AIR semantics.

Backend availability

Availability is selected by dialect/runtime composition.

A dialect exposing only interpreter should reject compiler mode.

A dialect exposing only CIL/compiler mode should reject interpreter mode.

Do not silently fall back to a different backend when the requested mode is unavailable.

Backend parity

When a dialect exposes both backend modes, they must agree on observable behavior.

Parity should cover:

  • successful values;
  • comparable failures;
  • external bindings;
  • variables;
  • conditions;
  • loops;
  • intrinsic-heavy programs;
  • optimizer-enabled programs.

Intrinsic support

A backend is not required to support every intrinsic.

Backend-specific intrinsic support must be represented through capability sets or supported intrinsic lists. Optimizers and emitters must check those capabilities before producing backend-specific intrinsic forms.

Unsupported operations

Unsupported backend operations should produce explicit failure.

Bad behavior:

text
requested compiler
  -> compiler cannot consume AIR
  -> silently run interpreter

Good behavior:

text
requested compiler
  -> compiler cannot consume AIR
  -> fail with a clear unsupported operation/backend diagnostic

Backend author checklist

A backend implementation should provide or document:

  • supported AIR opcodes;
  • supported intrinsic symbols/type arguments;
  • stack behavior;
  • label/jump behavior;
  • external binding argument handling;
  • final result handling;
  • failure behavior for unsupported instructions;
  • parity tests against existing backends when sharing dialects.

Built for developers who want to use, extend, or understand UniversalToolchain.