Utility Passes¶
Normalization and cleanup passes for IR structure.
Overview¶
These utility passes handle IR normalization and cleanup tasks:
- NormalizeStmtStructure: Ensures consistent statement structure
- VerifyNoNestedCall: Verification pass for three-address code form
These are typically used internally by other passes or for specific normalization needs.
SeqStmts::Flatten¶
Static helper method for creating well-formed SeqStmts nodes. Code that constructs SeqStmts should prefer Flatten() to satisfy the NoRedundantBlocks structural property.
SeqStmts::Flatten¶
// Signature (include/pypto/ir/stmt.h)
static StmtPtr SeqStmts::Flatten(std::vector<StmtPtr> stmts, Span span);
| Input | Output |
|---|---|
Flatten({a, SeqStmts({b, c}), d}, span) |
SeqStmts({a, b, c, d}) |
Flatten({a}, span) |
a (unwrapped) |
Flatten({}, span) |
SeqStmts({}) |
Nested SeqStmts children are absorbed (flattened). Single-child results are unwrapped.
Usage in IRMutator¶
The base IRMutator::VisitStmt_(SeqStmtsPtr) calls SeqStmts::Flatten() automatically. All passes inheriting from IRMutator produce well-formed IR without extra effort.
Usage in Passes¶
Passes that construct SeqStmts directly (not via the mutator) should use Flatten():
// ✅ Good — always well-formed
return SeqStmts::Flatten(std::move(new_stmts), op->span_);
// ❌ Bad — may produce single-child or nested SeqStmts
return std::make_shared<SeqStmts>(new_stmts, op->span_);
NoRedundantBlocks (Structural Property)¶
NoRedundantBlocks is a structural property — verified at pipeline start and expected to hold at all times. It checks:
| Check | SeqStmts |
|---|---|
| Single-child (should unwrap) | yes |
| Nested (should flatten) | yes |
NormalizeStmtStructure¶
Ensures IR is in a normalized form with consistent structure.
Requires: TypeChecked property.
Purpose¶
Normalizes statement structure by:
- Flattening nested
SeqStmts - Unwrapping single-child
SeqStmts - Leaving
AssignStmt/EvalStmtas direct children ofSeqStmts
API¶
| C++ | Python |
|---|---|
pass::NormalizeStmtStructure() |
passes.normalize_stmt_structure() |
Algorithm¶
- Flatten Nesting: Absorb nested
SeqStmtsinto the parent - Unwrap Single-child: Return single child directly (no redundant
SeqStmtswrapper) - Preserve Control Flow: Keep
IfStmt/ForStmt/WhileStmtbodies otherwise unchanged
Example¶
Before:
After:
Before:
After:
Implementation¶
Factory: pass::NormalizeStmtStructure()
File: src/ir/transforms/utils/normalize_stmt_structure.cpp
Tests: tests/ut/ir/transforms/test_normalize_stmt_structure_pass.py
Verify NoNestedCall (Part of IRVerifier)¶
Verifies that IR is in three-address code form (no nested calls).
Purpose¶
This verification rule (part of IRVerifier) checks that FlattenCallExpr pass has been run successfully. It detects:
CALL_IN_CALL_ARGS: Call in call argumentsCALL_IN_IF_CONDITION: Call in if conditionCALL_IN_FOR_RANGE: Call in for rangeCALL_IN_BINARY_EXPR: Call in binary expressionCALL_IN_UNARY_EXPR: Call in unary expression
API¶
Verified via PropertyVerifierRegistry (not a standalone pass):
# Verify with default properties (includes NoNestedCalls)
verify_pass = passes.run_verifier()
# Or exclude NoNestedCalls from verification
props = passes.get_default_verify_properties()
props.remove(passes.IRProperty.NoNestedCalls)
verify_pass = passes.run_verifier(properties=props)
Implementation¶
File: src/ir/verifier/verify_no_nested_call_pass.cpp
Rule name: "NoNestedCall"
Tests: tests/ut/ir/transforms/test_verifier.py
Usage Patterns¶
Normalization Pipeline¶
Verification¶
# Verify three-address code form
verifier = passes.run_verifier() # Includes NoNestedCall by default
verified_program = verifier(program) # Throws if nested calls found
When to Use¶
| Pass | When to Use |
|---|---|
| NormalizeStmtStructure | Before passes that expect flat SeqStmts structure |
| VerifyNoNestedCall | After FlattenCallExpr to ensure correctness |
Implementation Files¶
| Pass | Header | Implementation | Tests |
|---|---|---|---|
| NormalizeStmtStructure | passes.h |
normalize_stmt_structure.cpp |
test_normalize_stmt_structure_pass.py |
| VerifyNoNestedCall | passes.h |
verify_no_nested_call_pass.cpp |
test_verifier.py |