Skip to content

[FR] Verifier Pass #30

Description

@hsqStephenZhang

Motivation

In the current implementation of Koopa IR, it is relatively easy to inadvertently violate IR invariants, leading to "broken" IR states that are difficult to diagnose. Common scenarios include:

  1. Inconsistent Use-Def Chains: Modifying instructions via kind_mut() without manually synchronizing the corresponding used_by information.
  2. Structural Desynchronization: Instructions existing in the Layout (execution order) but missing from the DataFlowGraph (data storage), or vice-versa.
  3. SSA Violations: Moving instructions such that a value is used before its definition point (dominance violation).

Currently, these issues are often handled silently or trigger obscure panics deep within the codegen or later optimization passes. This makes debugging significantly harder, as the root cause (the pass that broke the IR) is disconnected from the symptoms. As an educational framework, Koopa should empower users to identify exactly when and where their IR became invalid.

Proposal

We propose introducing a Verifier abstraction and a VerifierManager to ensure IR integrity throughout the compilation pipeline.

1. The Verifier Trait

A core trait that allows for both global (Program) and local (Function) level checks. To provide high-quality error messages, Verifiers will be granted access to certain internal fields (via pub(crate) visibility or extension traits).

pub trait Verifier {
  /// Returns the human-readable name of the verifier for error reporting.
  fn name(&self) -> &str;

  /// Performs integrity checks on the entire IR program.
  fn verify_program(&self, _program: &Program) {}

  /// Performs integrity checks on a specific function.
  fn verify_function(&self, _func: Function, _data: &FunctionData) {}
}

2. Built-in Verifiers

Koopa will ship with a set of standard verifiers:

  • UseDefVerifier: Ensures every Value in the DFG has a perfectly synchronized used_by set.
  • CfgVerifier: Validates basic block termination and layout-DFG consistency.
  • DominanceVerifier: (Planned) Validates SSA dominance properties.

3. Verification Management & Pass Integration

To provide maximum flexibility, we propose two ways to run verifiers:

  • Explicit Pass Wrapping: Provide VerifierModulePass<V> and VerifierFunctionPass<V> so verifiers can be treated as standard passes and manually registered at specific points in the PassManager.
  • Automatic Verification (The VerifierManager): A dedicated manager that can be configured to run a suite of verifiers automatically after each optimization pass.

Why a dedicated Manager?
While manual registration works, it is redundant and error-prone for users to re-add a "VerifyPass" after every single optimization. A VerifierManager integrated into the PassManager execution loop allows for a "Verify-Each" mode (similar to LLVM's -verify-each), ensuring that the IR is validated at every step of the transformation.

Benefits

  1. Fail-Fast Debugging: Catch IR corruption immediately after the problematic pass, rather than during codegen.
  2. Educational Clarity: Detailed error messages help students understand the subtle invariants of SSA and IR structures.
  3. Extensibility: Users can easily define and register custom verifiers for their own specific optimization constraints.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions