Skip to content

Conversation

@qedawkins
Copy link
Contributor

@qedawkins qedawkins commented Dec 15, 2025

Adds the LowerStructuralPCFPass which lowers structural PCF operations to SCF:

  • pcf.generic is lowered to scf.execute_region
  • pcf.loop is lowered to scf.forall
  • pcf.branch_cond_return is lowered to cf.cond_br

The pass uses the scope attribute on each operation to determine how to generate worker IDs and counts for the lowered operations. Synchronization barriers are inserted when sync_on_return is set.

Also adds loadStructuralLoweringDependentDialects to PCFConversionDialectInterface, allowing external dialects to register dependent dialects needed during lowering.

Copy link
Collaborator

@MaheshRavishankar MaheshRavishankar left a comment

Choose a reason for hiding this comment

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

Without reviewing this yet. I dont think we should be using scf.execute_region at all. Can you say whats the reason for this?

@qedawkins
Copy link
Contributor Author

Without reviewing this yet. I dont think we should be using scf.execute_region at all. Can you say whats the reason for this?

I am open to alternatives, but that's pretty much the exact op I need here. I have

pcf.generic {
  /* some region to execute */
}

and need to execute its region without breaking up the parent block (because we haven't lowered scf to cf yet). This is kinda exactly what scf.execute_region is for IIUC (inlining function calls is the example given in the op docs) when you aren't able to break up the parent block yet (because the parent requires single block bodies).

@krzysz00
Copy link
Contributor

Wait, doesn't that make execute_region equivalent to just ... inlining the contents of the region? Or am I missing something?

- `pcf.generic` -> `scf.execute_region` with worker IDs from scope
- `pcf.loop` -> serialized `scf.forall` with iteration bounds from count operands
- `pcf.return` -> `scf.yield` (in generic) or `scf.forall.in_parallel` (in loop)
- `pcf.branch_cond_return` -> `cf.cond_br` to a return block
Copy link
Contributor

Choose a reason for hiding this comment

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

... why do we need cf here? Couldn't we have if or switch or such?

Copy link
Contributor

Choose a reason for hiding this comment

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

Ah. That's why.

... Is it just me, or should this conditional branch in PCF be something more like a switch-type op that takes multiple regions to choose between? That means we aren't mixing structured and unstructured control flow

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Regions are limited because either we get no implicit capture within regions at the same scope, or we switch into a finer scope, in which case that's just reinventing one of the already existing switch ops. I'll admit that I haven't landed on a super strong use case for pcf.branch_cond_return yet, but I haven't implemented the use case I had in mind for it yet, so we will see. I am willing to remove it if prompted but in it's current state it does "work" :P.

@qedawkins
Copy link
Contributor Author

Wait, doesn't that make execute_region equivalent to just ... inlining the contents of the region? Or am I missing something?

if you have something like

scf.for {
  scf.execute_region {
    ^bb0: ...
    ^bb1: ...
  }
}

you cannot inline the body of the execute region because scf.for requires a single block body. So the solution is to use the execute_region to hold the region and then lower both at the same time.

Copy link
Member

@kuhar kuhar left a comment

Choose a reason for hiding this comment

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

The logic looks good to me, I'll leave the exact lowering to scf for others to decide

@qedawkins qedawkins force-pushed the users/qedawkins/pcf-transforms-fuse-writes branch from 7c630ab to b061486 Compare January 5, 2026 17:16
Adds the LowerStructuralPCFPass which lowers structural PCF operations
to their SCF equivalents:

- pcf.generic is lowered to scf.execute_region
- pcf.loop is lowered to scf.forall
- pcf.branch_cond_return is lowered to cf.cond_br

The pass uses the scope attribute on each operation to determine how to
generate worker IDs and counts for the lowered operations.
Synchronization barriers are inserted when sync_on_return is set.

Also adds loadStructuralLoweringDependentDialects to
PCFConversionDialectInterface, allowing external dialects to register
dependent dialects needed during lowering.
@qedawkins qedawkins force-pushed the users/qedawkins/pcf-transforms-struct branch from 6a255ec to 867ec68 Compare January 5, 2026 17:22
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.

5 participants