Skip to content

Add support for unstructured programs#202

Merged
atomb merged 31 commits intomainfrom
add-cfgs
Mar 12, 2026
Merged

Add support for unstructured programs#202
atomb merged 31 commits intomainfrom
add-cfgs

Conversation

@atomb
Copy link
Copy Markdown
Contributor

@atomb atomb commented Nov 13, 2025

Add Control-Flow Graph (CFG) Support to Imperative Dialect

This PR introduces unstructured control-flow graph representation to the
Imperative dialect, enabling transformation from structured statements to
basic blocks with explicit control flow.

Key Changes

New Core Components:

  • BasicBlock.lean - Defines CFG structure with deterministic and non-
    deterministic basic blocks

    • DetTransferCmd - Conditional jumps and finish commands
    • NondetTransferCmd - Non-deterministic goto with multiple targets
    • CFG type - Entry label + labeled blocks
  • CFGSemantics.lean - Small-step operational semantics for CFGs

    • EvalDetBlock / EvalNondetBlock - Block evaluation relations
    • StepCFG / StepCFGStar - Single-step and multi-step execution

Transformation:

  • StructuredToUnstructured.lean - Converts structured statements to CFGs
    • Handles block, ite, loop, and exit constructs
    • Generates labeled basic blocks with explicit control flow
    • Coalesces contiguous blocks during construction

Testing:

  • Extended Exit.lean and Loops.lean tests with CFG generation examples
  • Added #guard_msgs tests verifying CFG structure for various programs

Implementation Details

  • Basic blocks consist of command lists + transfer command
  • Labels are generic (currently String, can be Fin n for total functions)
  • Command accumulation during translation minimizes block count
  • Exit statements properly resolve to labeled block continuations
  • Loop invariants preserved as assertions in loop entry blocks

By submitting this pull request, I confirm that you can use, modify, copy,
and redistribute this contribution, under the terms of your choice.

This introduces a type for control-flow graphs made up of basic blocks
that can include the same sorts of commands that structured statements
do. It includes a translation from structured statements to unstructured
CFGs.
Copy link
Copy Markdown
Contributor

@tautschnig tautschnig left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What will be the semantics of jumping into a block while skipping over a declaration? In C one can do:

goto lab;
int x = 42;
lab: ++x; // x is considered declared, but is uninitialised

I believe programs like the above can now be represented, but we also need to be clear on their semantics.

Comment thread Strata/Languages/Boogie/Examples/Loops.lean Outdated
@atomb
Copy link
Copy Markdown
Contributor Author

atomb commented Feb 16, 2026

What will be the semantics of jumping into a block while skipping over a declaration? In C one can do:

goto lab;
int x = 42;
lab: ++x; // x is considered declared, but is uninitialised

I believe programs like the above can now be represented, but we also need to be clear on their semantics.

You caught one of the key reasons I hadn't moved this from a draft yet! My current plan is to require that declarations be procedure-level when translating to CFG, but I haven't yet decided how best to enforce that. As you've probably noticed, the example you commented on with the errant comma has an init command in a later block.

@atomb
Copy link
Copy Markdown
Contributor Author

atomb commented Mar 3, 2026

What will be the semantics of jumping into a block while skipping over a declaration? In C one can do:

goto lab;
int x = 42;
lab: ++x; // x is considered declared, but is uninitialised

I believe programs like the above can now be represented, but we also need to be clear on their semantics.

On further thought, I'm happy with how the semantics for this work out (as specified in the new CFGSemantics.lean). If you were to do that, evaluation would be stuck, because ++x would be translated into something that would require x to have a value already, and it wouldn't. In a structured program, the type checker won't allow that to happen. If you were to create an unstructured program directly, you could encode the above, and it would have no semantics. We could write a type checker for unstructured programs that would rule out such an issue, too.

@atomb atomb marked this pull request as ready for review March 3, 2026 21:14
@atomb atomb requested a review from a team March 3, 2026 21:14
Copy link
Copy Markdown
Contributor

@MikaelMayer MikaelMayer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few things that could make our life easier down the road. My strong recommendation to have only non deterministic blocks since deterministic blocks are a subset of them.

I love to see that there are semantics as well, haven't checked them though.

Comment thread Strata/DL/Imperative/BasicBlock.lean
Comment thread Strata/DL/Imperative/BasicBlock.lean
Comment thread Strata/DL/Imperative/BasicBlock.lean
Comment thread StrataTest/Languages/Core/Examples/Exit.lean Outdated
Comment thread StrataTest/Languages/Core/Examples/Loops.lean
MikaelMayer
MikaelMayer previously approved these changes Mar 5, 2026
shigoel
shigoel previously approved these changes Mar 10, 2026
@atomb atomb dismissed stale reviews from shigoel and MikaelMayer via 5f46156 March 11, 2026 15:27
@atomb atomb added this pull request to the merge queue Mar 12, 2026
Merged via the queue into main with commit 2288158 Mar 12, 2026
15 checks passed
@atomb atomb deleted the add-cfgs branch March 12, 2026 22:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants