Skip to content

Irreducible transform#108

Merged
agle merged 12 commits intomainfrom
irreducible-transform
Apr 1, 2026
Merged

Irreducible transform#108
agle merged 12 commits intomainfrom
irreducible-transform

Conversation

@agle
Copy link
Copy Markdown
Owner

@agle agle commented Mar 30, 2026

Add irreducible loop transform and pull across more tests

@agle
Copy link
Copy Markdown
Owner Author

agle commented Mar 30, 2026

The result for Fig 6.a differs to Basil; we only identify two loops whereas basil identifiers 3 (2 irreducible).

https://github.com/agle/bincaml/actions/runs/23731415109/job/69125853957?pr=108#step:8:28

image

Here we pick just b as the irreducible loop; whereas basil picks h1 and h2. seems suspicious. If I swap the iteration order of successors it picks the same headers as basil (but other things fail because I've hardcoded the header pointers list in a bunch of other tests), @katrinafyi does what its done in the test log look like a valid choice? The test passes otherwise, (all irreducible loops removed and become reducible) I'm just not fully convinced by rotating the loops in my mind that just b -> h3 is a valid loop forest.

@katrinafyi
Copy link
Copy Markdown
Collaborator

this one before transform? I'll have a think

  { block = ("%S", 0); dfs_pos = 1; loop = NonLoop }
  , { block = ("%h3", 1); dfs_pos = 2;
    loop =
    PrimaryHeader {primary_header = None; headers = {("%h3", 1)};
      nodes =
      {("%h3", 1), ("%x", 2), ("%y", 3), ("%b0", 4), ("%h2", 5), ("%h1", 6), ("%b", 7), ("%z", 8), ("%a", 9), ("%back", 10)}}
    }
  , { block = ("%x", 2); dfs_pos = 3;
    loop = LoopParticipant {primary_header = ("%h3", 1)} }
  , { block = ("%y", 3); dfs_pos = 4;
    loop = LoopParticipant {primary_header = ("%h3", 1)} }
  , { block = ("%b0", 4); dfs_pos = 5;
    loop = LoopParticipant {primary_header = ("%h3", 1)} }
  , { block = ("%b", 7); dfs_pos = 6;
    loop =
    PrimaryHeader {primary_header = (Some ("%h3", 1));
      headers = {("%h2", 5), ("%b", 7)};
      nodes = {("%h2", 5), ("%h1", 6), ("%b", 7), ("%z", 8), ("%a", 9)}}
    }
  , { block = ("%z", 8); dfs_pos = 7;
    loop = LoopParticipant {primary_header = ("%b", 7)} }
  , { block = ("%h1", 6); dfs_pos = 8;
    loop = LoopParticipant {primary_header = ("%b", 7)} }
  , { block = ("%a", 9); dfs_pos = 8;
    loop = LoopParticipant {primary_header = ("%b", 7)} }
  , { block = ("%h2", 5); dfs_pos = 9;
    loop = LoopParticipant {primary_header = ("%b", 7)} }
  , { block = ("%back", 10); dfs_pos = 9;
    loop = LoopParticipant {primary_header = ("%h3", 1)} }
  , { block = ("%exit", 11); dfs_pos = 10; loop = NonLoop }
  

@katrinafyi
Copy link
Copy Markdown
Collaborator

katrinafyi commented Mar 30, 2026

do you have the full sbasil loop infos?

@agle
Copy link
Copy Markdown
Owner Author

agle commented Mar 30, 2026

  case class BlockLoopInfo(
    val b: Block,
    val iloop_header: Option[Block],
    val dfsp_pos: Int,
    val headers: Set[Block],
    val nodes: Set[Block]
}
Before transform:

  + BlockLoopInfo(%S,None,1,Set(),Set()) 
  + BlockLoopInfo(%h3,None,2,Set(%h3),HashSet(%back, %h2, %y, %b0, %z, %b, %h1, %x, %h3, %a)) 
  + BlockLoopInfo(%x,Some(%h3),3,Set(),Set()) 
  + BlockLoopInfo(%h2,Some(%h3),4,Set(%h2, %b),HashSet(%h1, %h2, %z, %a, %b)) 
  + BlockLoopInfo(%y,Some(%h3),4,Set(),Set()) 
  + BlockLoopInfo(%h1,Some(%h2),5,Set(%h1, %b),Set(%h1, %z, %b)) 
  + BlockLoopInfo(%b0,Some(%h3),5,Set(),Set()) 
  + BlockLoopInfo(%b,Some(%h1),6,Set(),Set()) 
  + BlockLoopInfo(%z,Some(%h1),7,Set(),Set()) 
  + BlockLoopInfo(%a,Some(%h2),8,Set(),Set()) 
  + BlockLoopInfo(%back,Some(%h3),9,Set(),Set()) 
  + BlockLoopInfo(%exit,None,10,Set(),Set()) 

After transform


  + BlockLoopInfo(%S,None,1,Set(),Set()) 
  + BlockLoopInfo(%h3,None,2,Set(%h3),HashSet(%h1_loop_N, %back, %h2, %y, %h2_loop_N, %b0, %z, %b, %h1, %x, %h3, %a)) 
  + BlockLoopInfo(%x,Some(%h3),3,Set(),Set()) 
  + BlockLoopInfo(%y,Some(%h3),4,Set(),Set()) 
  + BlockLoopInfo(%b0,Some(%h3),5,Set(),Set()) 
  + BlockLoopInfo(%h2_loop_N,Some(%h3),6,Set(%h2_loop_N),HashSet(%h1_loop_N, %h1, %h2, %h2_loop_N, %z, %a, %b)) 
  + BlockLoopInfo(%h2,Some(%h2_loop_N),7,Set(),Set()) 
  + BlockLoopInfo(%h1_loop_N,Some(%h2_loop_N),8,Set(%h1_loop_N),Set(%h1_loop_N, %z, %b, %h1)) 
  + BlockLoopInfo(%h1,Some(%h1_loop_N),9,Set(),Set()) 
  + BlockLoopInfo(%b,Some(%h1_loop_N),10,Set(),Set()) 
  + BlockLoopInfo(%z,Some(%h1_loop_N),11,Set(),Set()) 
  + BlockLoopInfo(%a,Some(%h2_loop_N),12,Set(),Set()) 
  + BlockLoopInfo(%back,Some(%h3),13,Set(),Set()) 
  + BlockLoopInfo(%exit,None,14,Set(),Set()) 

@katrinafyi
Copy link
Copy Markdown
Collaborator

katrinafyi commented Mar 30, 2026

Yeah I'm happy with both the sbasil and bincaml forests. If you visit b first (like bincaml), then there is no sub-loop because all the inner loops go through b. If you visit h2 first, then there's a subloop without h2 via h1.

As long as the transform works, it should be fine.

@agle agle marked this pull request as ready for review April 1, 2026 06:24
@agle agle requested a review from katrinafyi April 1, 2026 06:24
{
name = "irreducible-loops";
apply = Proc Transforms.Irreducible_loop.transform;
doc = "Remove blocks unreachable from entry";
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
doc = "Remove blocks unreachable from entry";
doc = "Transform irreducible loops to reducible ones";

@agle agle enabled auto-merge (squash) April 1, 2026 06:52
@agle agle merged commit db17f1b into main Apr 1, 2026
9 checks passed
@agle agle deleted the irreducible-transform branch April 1, 2026 06:59
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.

2 participants