We currently have static op verifiers that check for violated op invariants / assumptions based on static program information.
Op verifiers are unable to detect certain cases where an op may turn out to be invalid at runtime. Such cases are hard to debug because they can crash the program execution at a seemingly unrelated position or (even worse) compute an invalid result without crashing.
Example: memref::ExpandShapeOp
Invalid at compile time: memref.expand_shape %m [[0, 1]] : memref<11xf32> into memref<2x5xf32>
Valid at compile time (because we do not know any better): memref.expand_shape %m [[0, 1]] : memref<?xf32> into memref<?x5xf32>
. This op may or may not be valid at runtime depending on the runtime shape of %m.
Example: memref::CastOp
Invalid at compile time: memref.cast %m : memref<2xf32> into memref<5xf32>
Valid at compile time (because we do not know any better): memref.cast %m : memref<?xf32> into memref<5xf32>
.
Example: memref::CollapseShapeOp
Non-contiguous dimensions cannot be collapsed. This is easy to detect when all dimensions and strides are static, but not can only be detected at runtime in the dynamic case.
Op documentation sometimes contains lingo such as “it acts as an assertion that fails at runtime” (memref.cast
), but in practice such assertions are often not generated.
Proposal: âš™ D138576 [mlir] Add RuntimeVerifiableOpInterface and transform
Add a new op interface RuntimeVerifiableOpInterface
that can be implemented by ops that provide runtime verification. The interface has one method:
/// Generate IR to verify this op at runtime. Abort runtime execution if
/// verification fails. Return `success` if the runtime verification IR was
/// successfully built.
LogicalResult runtimeVerify(OpBuilder &b, Location loc);
A typical implementation of runtimeVerify
may compute some checks and pass the result into cf.assert
.
Runtime verifiers are not expected to verify assumptions that can be verified statically.
Runtime verification can be computationally expensive (e.g., for memref::CollapseShape
), so the IR is only generated on an opt-in basis by running -runtime-op-verify
.
Alternative considered
Generate assertions during the lowering to LLVM. Example for memref::CollapseShapeOp
: âš™ D138444 [mlir][LLVM] Add runtime debug assertions for memref::CollapseShapeOp.
Disadvantages:
- Works only for LLVM backend. (Must be implemented separately for every backend.)
- Tedious to write LLVMIR, esp. when there are loops involved.
- Only works for ops that lower directly to LLVM.
@River707 @mehdi_amini @nicolasvasilache @ftynse @herhut @aartbik @_sean_silva @jpienaar @qcolombet