Repository: sampsyo/cs6120
Pull request #541: Add Brilooped
Author: login: devv64
Labels: name: 2025sp
Created: 2025-05-14T01:28:40Z | Merged: 2025-05-15T02:21:45Z

Closes #504 
@gerardogtn 

Linked issue #504: Project Proposal: Brilooped
**What will you do?**
* The idea is to implement the relooper algorithm to convert bril programs into bril programs with structured control flow. 
* The idea is that we'll be able to write bril programs with two extra constructs: if-then-else and while loops. 
* To generate brilooped programs, you'll be able to write them by hand and compile them to bril. 
* Or you'll be able to generate briloop programs from bril files, a translation implemented using Ramsey's relooper algorithm.
* Another team (Michael, Annabel, and Serena) will work on a project that transforms briloop programs into webassembly. We'll coordinate with them on the file format and our end goal is that we can build a fulll pipeline bril -> briloop -> wasm. 

**How will you do it?**
* To implement the compilation from briloop to bril we'll use a classic compiler pipeline that will translate while and if statements into blocks and jump instructions. The main idea of this phase is to grow comfortable with the grammar for brilooped programs and to enable us to test autogenerated brilooped programs. We hope to spend only a small amount of time in this phase. 
* To implement compilation from bril to briloop we'll use the relooper algorithm from Ramsey. We hope to spend a majority of time of the project in this stage. 

**How will you empirically measure success?**
* By implementing a full translation loop! bril -> briloop -> bril and test the output back on bril benchmarks. 
* Our goal is for the implementation to be correct (i.e. the output of each program is equivalent), we can also establish a metric of efficiency in terms of how many dynamic instructions are executed for the original bril vs the translated bril program. 
* As a stretch goal, it would be fun to compare how different some programs look if we write briloop by hand vs by compiling bril to brilooper! Would any optimizations over a bril program lead to significant different briloop program?


**Team members:**
@devv64 
@gerardogtn 

Linked issue comments: user: login: sampsyo
created_at: 2025-04-07T19:10:53Z
body: Sounds good overall! See also #503 for the WebAssembly backend project that will consume this representation. Please head on over to https://github.com/sampsyo/cs6120/issues/503#issuecomment-2784294696 to consider my request for a near-term checkpoint where we, together, review the design for the JSON syntax for structured control flow.

It is great that you can use a Bril->Brilooped->Bril "round trip" as a convenient testing oracle!

Here's one thing to consider: will you extend the reference interpreter (or any interpreter) to execute these Brilooped programs directly? It could also be useful as a debugging aid, so you can use differential testing on the Bril->Brilooped and Brilooped->Bril passes independently. It also probably would not be very hard. But it's not strictly necessary by any means, especially if you just feel allergic to TypeScript.
author_association: OWNER

Diff:
diff --git a/content/blog/2025-05-13-brilooped/index.md b/content/blog/2025-05-13-brilooped/index.md
new file mode 100644
index 000000000..e75f72a49
--- /dev/null
+++ b/content/blog/2025-05-13-brilooped/index.md
@@ -0,0 +1,438 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows Bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate Bril programs into Briloop automatically, having a an average performance penalty of 9% when using the core Bril benchmarks. Brilooped not only enables programmers to write Bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: `while`, `block`, `if`, `break`, and `continue`.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### From lists to trees
+
+Briloop follows Bril's design philosophy and represent a program as a JSON Object with single key `functions` that maps to a list of BriloopFunction.
+```
+// BriloopProgram
+{ "functions": [<BriloopFunction>] }
+```
+
+A Briloop function contains a name, an optional array of function arguments, an optional return type, and a list of instructions. There are no labels in Briloop. 
+```
+// BriloopFunction
+{
+    "name": "<string>",
+    "args": [{"name": "<string>, "type":<Type>}, ...]?,
+    "type": <Type>?,
+    "instrs": [<BriloopInstruction>, ...],
+}
+```
+
+In Bril, the instructions array is a flat list of instructions, but in Briloop structured control flow statements may reference other Briloop instructions. So control flow statements in briloop may contain a `children` field a list of list of Briloop instructions. Since BriloopInstructions may contain other BriloopInstructions, they give the appearance of being nested:
+```
+// BriloopInstruction
+{
+    "op": "<string>",
+    "dest": "<string>"?,
+    "type": "<Type>"?,
+    "args": ["<string>", ...]?,
+    "funcs": ["<string>", ...]?,
+    "value": <Value>?,
+    "children": [[ <BriloopInstruction>, ...], ...]?,
+}
+```
+
+Let's see some of the control flow statements to see how they use the children field
+
+#### `while`
+
+The `while` operation starts a loop that is executed until its argument evaluates to false, or execution is interrupted by a break or continue statement: 
+
+```json
+{
+  "op": "while",
+  "args": ["cond"],
+  "children": [
+    [
+      { "op": "print", "args": ["b"], },
+      { "op": "add", "args": ["a","b"], "dest": "b", "type": "int" },
+      { "op": "le", "args": ["b", "ten"], "dest": "cond", "type": "bool" }
+    ]
+  ],
+}
+```
+
+- `op`: must be "while"
+- `args`: a list with exactly one element, the name of a boolean variable that serves as the loop condition. It is evaluated before each execution of the loop.
+- `children`: a list with exactly one element, the list of instructions (body) to execute in each iteration of the loop. A while statement will iterate indefinitely until the variable name evaluates to false or a `break`/`ret` instruction is executed in the body.  
+- may also be represented in text form:
+
+```
+# will print 0, 1, ..., 9
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    print b;
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+#### `block`
+The `block` operation starts a block statement that executes the instructions in its body exactly one time, unless interrupted by a `block`, `continue`, or `ret` instruction. 
+
+```json
+{
+  "op": "block",
+  "children": [
+    [
+      { "op": "print", "args": ["a"] } 
+      { "op": "print", "args": ["b"] } 
+    ]
+  ],
+}
+```
+
+- `op`: must be "block"
+- `children`: a list with exactly one element, the list of instructions (body). 
+- may also be represented in text form:
+
+```
+# will print 1, 0
+a: int = const 1;
+b: int = const 0;
+block {
+    print a;
+    print b;
+}
+```
+
+### `if`
+
+The `if` operation represents a conditional execution of at least one, but possibly two branches:
+
+```json
+{
+  "op": "if",
+  "args": ["cond"],
+  "children": [
+    [{ "args": ["a", "b"], "dest": "temp", "op": "add", "type": "int" }],
+    [{ "args": ["a", "b"], "dest": "temp", "op": "sub", "type": "int" }]
+  ],
+}
+```
+- `op`: must be "if"
+- `args`: a list with exactly one element, the name of a boolean variable that serves as the if condition.
+- `children`: a list with at least one element and maximum two elements. The first element represents the true branch and the second (if any) the false branch.
+- may also be represented in text form: 
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### Transferring control: break and continue
+#### `break`
+The `break n` operation terminates execution the current control flow statement and exits `n` additional enclosing control flow statements, transferring control to the instruction immediately after the n-th control flow statement. 
+
+```json
+{ "op": "break", "value": 0 }
+```
+- `op`: must be "break"
+- `value`: an integer literal representing how many levels of control flow to break out of. Zero-indexed. 
+
+Let's consider a few break examples to see how it behaves in action. In this first example break makes the block statement exit early and execution moves to the first instruction after its closing curly brace:
+
+```
+# will print 1, 3.
+block {
+    print one;
+    break 0;
+    print two;
+}
+print three;
+```
+
+More deeply nested blocks, will require different levels to break out of: 
+```
+# will print 1, 2, 3, 6, 7
+block {
+    print one;
+    block {
+        print two;
+        block {
+            print three;
+            break 1;
+            print four;
+        }
+        print five;
+    }
+    print six;
+}
+print seven;
+```
+
+Only block and while statements count for the number of levels to break out of: 
+
+```
+# will print 1, 2, 3, 7
+while cond {
+    print one;
+    block {
+        print two;
+        while cond {
+            print three;
+            break 2;
+            print four;
+        }
+        print five;
+    }
+    print six;
+}
+print seven;
+```
+
+#### `continue`
+The `continue n` operation skips the remaining code in the current control flow instruction and transfers execution to the n-th control flow instruction. If the n-th control flow operation is a while loop, the next iteration of the loop starts, if it is a block statement it exits the block entirely.
+
+```json
+{ "op": "continue", "value": 0 }
+```
+- `op`: must be "continue"
+- `value`: an integer literal representing how many levels of control flow to continue out of. Zero-indexed. 
+
+Let's consider a few break examples to see how it behaves in action. Inside of a block, continue works just like break.
+
+```
+# will print 1, 3.
+block {
+    print one;
+    continue 0;
+    print two;
+}
+print three;
+```
+
+In while statements, continue transfers control to the start of the loop
+```
+# will print 0, 1, ..., 9
+cond: bool = const true;
+a: int = const 0;
+one: int = const 1;
+ten: int = const 10;
+while cond {
+    print a; 
+    a: int = add a one;
+    keep_going: bool = le a ten;
+    if keep_going
+    then {
+        continue 0;
+    }
+    else {
+        break 0;
+    }
+}
+```
+
+In nested while loops, continue may transfer control to outer loops: 
+```
+# will print 1, 2, 1, 2, ...
+cond: bool = const true;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+## Interpreter Changes
+
+We expanded Bril's interpreter to handle the five new op codes described above, its implementation was relatively straightforward for break and continue statements and [more invovled for the rest of the operations](https://github.com/gerardogtn/bril/blob/f2f795c4a313596510772a9c24d4697ccf9904c9/brili.ts#L878). In particular, correctly implementing multi-level `break`s and `continue`s required careful tracking of a `level` counter to track how many loop boundaries a statement needs to cross.
+During development improper handling of multi-level breaks and exits caused programs to become trapped in infinite loops and were tricky to debug - we ultimately resorted to execution profiling to trace the interpreter's control flow and identify where it was getting stuck. The resulting implementation not only handles complex control flow patterns correctly but does so with minimal additional overhead on the interpreter.
+
+## Beyond Relooper
+
+The Beyond Relooper algorithm was described by Ramsey as a way to translate [Cmm sources](https://gitlab.haskell.org/ghc/ghc/-/wikis/commentary/rts/cmm) into [WebAssembly](https://developer.mozilla.org/en-US/docs/WebAssembly); for this project we adapted the algorithm to translate Bril into Briloop. We'll start by providing a high level overview of the algorithm and some of the adaptations we did, as the source and target languages are different from what are presented in Ramsey's paper.
+
+The Beyond Relooper algorithm takes as input the Dominator Tree of a Control Flow Graph, with the important characteristic that the children in the tree are sorted in descending reverse post order, and produces the Briloop Program as an output. It is implemented as a recursive function over the structure of the dominator tree, where the current node is translated into either a while statement, a list of Briloop instructions, or a block statement:
+
+- A basic block is translated into a while statement if it is a loop header. We use Ramsey's definition of a block header being a loop header if it has a predecessor with a larger reverse post order than itself rather than the more standard definition of a loop header being a node that has a predecessor that it dominates.
+- If a basic block is a merge node it is translated into a Briloop block statement, to support breaking.
+- Otherwise, the basic block is translated into a flat list of Briloop instructions.
+
+Detecting the different kinds of translations allows us to only introduce the minimal number of blocks needed for the translation.
+
+### Merge nodes
+
+Identifying merge nodes is a key part of the Briloop algorithm. They are defined as nodes that have at least 2 in edges from nodes with a smaller reverse post order. This means that in the original control flow, there are two basic blocks that jump into it and that thse nodes do not form a loop. Detecting them is important since we need to rely on block statements and break instructions in order to reach them ([see Theorem three in Peterson, Kasami, and Tokura](https://dl.acm.org/doi/10.1145/355609.362337)).
+
+To see why this is needed, consider the following example (based on Ramsey):
+![Merge Nodes](merge-nodes.png)
+
+This translation proves difficult to translate without block and break statements as two basic blocks navigate to the same basic block, in this example both B and C are connected to E. If this were expressed in a language with no go to statements, programmers might rely on duplicating the E block in both branches:
+
+```Java
+// Block A
+public void foo(boolean l, boolean r) {
+    System.out.println("Block A");
+    if (l) {
+        if (r) {
+            System.out.println("Block B");
+        } else {
+            System.out.println("Block E");
+        }
+    } else {
+        if (r) {
+            System.out.println("Block E");
+        } else {
+            System.out.println("Block F");
+        }
+    }
+    System.out.println("Block G");
+```
+
+But we want our translation to be minimal, and not rely on duplicate blocks. The beyond relooper algorithm allows this to happen by using `break n;` statements ([Peterson et. al](https://dl.acm.org/doi/10.1145/355609.362337) refer to them as multi-level exit instructions):
+
+```code
+@foo(l: bool, r: bool) {
+    print a;
+    block {
+        block {
+            if (l)
+            then {
+                if (r)
+                then {
+                    print b;
+                    break 1;
+                } else {
+                    break 0;
+                }
+            }
+            else {
+                if (r)
+                then {
+                    break 0;
+                }
+                else {
+                    print f;
+                    break 1;
+                }
+            }
+        }
+        print e;
+        break 0;
+    }
+    print g;
+    ret;
+}
+````
+
+This translation may not be what programmers in languages like Java may write, but since the source contains an arbitrary control flow graph and those allow these kind of statements, we need a correct way to translate them.
+
+### Loop Nodes
+
+Loop nodes are easier to translate, and only two conditions need to be met:
+
+- Loop headers must be translated into while statements.
+- When jumping to a loop header we use a `continue n;` instruction, where n is how many control flow statements we need to skip.
+
+The use of while loops introduces a couple of quirks, one to the language and one to the translation from Bril to Briloop programs. The language quirk is that not only are you able to execute continue inside of block statements (in which case it behaves just like a break), but you the level passed to the continue statement must take into account block statements. In the following example we can see the behavior at play, foo will print a, b, c repeatedly whereas bar will print a, b
+repeatedly.
+
+```
+@foo(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 0;
+        }
+        print c;
+    }
+}
+
+@bar(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 1;
+        }
+        print c;
+    }
+}
+```
+
+The quirk from the translation to Bril to Briloop is that we rely on all while loops to execute forever and rely on break statements to terminate the loop execution. This has the unfortunate consequence of worsening performance for loops (especially nested ones) as we introduce a true variable before every while translation.
+
+## Results
+
+### Impact of Brilooped Transformation on Dynamic Instruction Count
+
+Our analysis of the Bril to Brilooped transformation using the relooper algorithm shows significant variations in dynamic instruction count across different benchmarks. As shown in Figure 1, the majority of benchmarks (37 out of 38) experienced an increase in dynamic instruction count after transformation, with only the `collatz` benchmark showing a reduction (-6.51%) due to `br` and `jmp` instructions making up a majority of the functionality. The changes in dynamic instruction count ranged from minimal increases (below 1%) for benchmarks like `sum-check` and `lcm` to substantial increases exceeding 30% for benchmarks such as `binary-fmt` (28.00%), `hanoi` (31.31%), and `pythagorean_triple` (37.60%).
+
+![Figure 1: Relative Change in Dynamic Instructions After Brilooped Transformation](relative_change.png)
+
+The blue dashed line in Figure 1 is the average (9.06%) change in dynamic instructions after the transformation. 11 of the benchmarks were significantly above (>15%) this average while 9 were significantly below (<1%), leading to a large standard deviation (9.75%).
+
+### Execution Time Analysis Across Benchmarks
+
+Figure 2 presents the speedup ratios (Before/After) across all benchmarks. The majority of speedup ratios fall below 1.0 (collatz is the only outlier), indicating an increase in execution time after transformation to Brilooped. The average performance across all benchmarks shows:
+
+- Arithmetic Mean: 0.9235 (7.65% slowdown)
+- Geometric Mean: 0.9203 (7.97% slowdown)
+- Harmonic Mean: 0.9169 (8.31% slowdown)
+
+![Figure 2: Speedup Ratios Across Benchmarks with Different Mean Calculations](speedup_comparison.png)
+
+The speedup ratios vary considerably across benchmarks, with `pythagorean_triple` showing the most significant slowdown (speedup ratio of approximately 0.73 or 27% slowdown), while benchmarks like `collatz` exhibited speedup ratios near or slightly above 1.0, indicating slight improvement to performance. Benchmarks like `pythagorean_triple` struggle in this category due to nested loops.
+
+### Relationship Between Benchmark Size and Transformation Impact
+
+Figure 3 illustrates the relationship between benchmark size (measured in dynamic instructions before the transformation) and the percentage change in dynamic instructions. This shows some interesting patterns:
+
+![Figure 3: Impact of Brilooped Transformation vs Benchmark Size](size_vs_change.png)
+
+1. The most substantial percentage increases occurred in benchmarks of varying sizes, with `pythagorean_triple` (largest at ~10,000 instructions) showing a ~37% increase, `hanoi` (~100 instructions) showing a ~31% increase, and `binary-fmt` (~100 instructions) showing a ~28% increase.
+
+   - Briloop syntax seems to be causing lots of overhead in the smaller examples
+   - Nested loops are very expensive
+   - Recursion can be very expensive
+
+2. There doesn't seem to be any strong correlation between benchmark size and the magnitude of impact from the Brilooped transformation. Both small and large benchmarks showed varying degrees of change. Benchmarks clustered around the 10^2 instruction count range had the greatest variance, ranging from approximately -6% to +31%.
+
+### Before vs. After Comparison with Percentage Changes
+
+Figure 4 provides a comparison of the total dynamic instructions before and after the Brilooped transformation on a logarithmic scale, along with the percentage changes for each benchmark. The top graph demonstrates that while the absolute instruction count increases for almost all benchmarks, the relative differences vary significantly.
+
+![Figure 4: Before vs After Comparison (Log Scale) with Percentage Changes](log_scale_comparison.png)
+
+### Summary of Findings
+
+1. The Brilooped transformation using the relooper algorithm resulted in increased dynamic instruction counts for 37 out of 38 benchmarks, with increases ranging from negligible to substantial (up to 37.60%).
+
+2. The overall performance impact was a modest slowdown, with average execution time increases between 7.65% and 8.31% depending on the mean calculation method.
+
+3. The benchmarks most affected by the transformation were `pythagorean_triple`, `hanoi`, and `binary-fmt`, while `collatz` was the only benchmark that saw reduced instruction count after transformation.
+
+4. **Most importantly, all benchmarks in the test suite produced correct results after transformation to Brilooped**, confirming the semantic correctness of our implementation of the relooper algorithm.
+
+These results suggest that while transforming Bril code to Brilooped using the relooper algorithm introduces some overhead in most cases, the structured control flow benefits of Brilooped come with a reasonable performance cost. The high variance in impact across different benchmarks indicates that the transformation's efficiency depends significantly on the specific control flow patterns in the original code. This tradeoff seems acceptable, especially considering that all benchmarks maintained their functional correctness.
+
diff --git a/content/blog/2025-05-13-brilooped/log_scale_comparison.png b/content/blog/2025-05-13-brilooped/log_scale_comparison.png
new file mode 100644
index 000000000..2e1d90420
Binary files /dev/null and b/content/blog/2025-05-13-brilooped/log_scale_comparison.png differ
diff --git a/content/blog/2025-05-13-brilooped/merge-nodes.png b/content/blog/2025-05-13-brilooped/merge-nodes.png
new file mode 100644
index 000000000..2800de10c
Binary files /dev/null and b/content/blog/2025-05-13-brilooped/merge-nodes.png differ
diff --git a/content/blog/2025-05-13-brilooped/relative_change.png b/content/blog/2025-05-13-brilooped/relative_change.png
new file mode 100644
index 000000000..ac3b3ff35
Binary files /dev/null and b/content/blog/2025-05-13-brilooped/relative_change.png differ
diff --git a/content/blog/2025-05-13-brilooped/size_vs_change.png b/content/blog/2025-05-13-brilooped/size_vs_change.png
new file mode 100644
index 000000000..f2dcbf148
Binary files /dev/null and b/content/blog/2025-05-13-brilooped/size_vs_change.png differ
diff --git a/content/blog/2025-05-13-brilooped/speedup_comparison.png b/content/blog/2025-05-13-brilooped/speedup_comparison.png
new file mode 100644
index 000000000..949726610
Binary files /dev/null and b/content/blog/2025-05-13-brilooped/speedup_comparison.png differ
diff --git a/content/blog/2025-05-13-brilooped/top_improvements.png b/content/blog/2025-05-13-brilooped/top_improvements.png
new file mode 100644
index 000000000..c9eb2afd6
Binary files /dev/null and b/content/blog/2025-05-13-brilooped/top_improvements.png differ
diff --git a/content/blog/2025-05-13-brilooped/top_regressions.png b/content/blog/2025-05-13-brilooped/top_regressions.png
new file mode 100644
index 000000000..b23687720
Binary files /dev/null and b/content/blog/2025-05-13-brilooped/top_regressions.png differ


Reviews:
user: login: sampsyo
body: Very very cool; nice work here! This is a substantial chunk of implementation work, and you've done a great job of explaining what you've done. And the empirical evaluation is great as well!!

I would love to merge two things into the main Bril monorepo:

* The specification of the Briloop language extension.
* The "Beyond Relooper" implementation that does the transformation.

Could I have your help opening some PRs for those into the Bril repo so we can get those merged? 😇 
state: CHANGES_REQUESTED
author_association: OWNER
submitted_at: 2025-05-14T19:51:51Z
user: login: gerardogtn
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T02:00:32Z
user: login: gerardogtn
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T02:02:56Z
user: login: gerardogtn
state: COMMENTED
author_association: CONTRIBUTOR
submitted_at: 2025-05-15T02:04:14Z
user: login: sampsyo
state: COMMENTED
author_association: OWNER
submitted_at: 2025-05-15T02:18:26Z
user: login: sampsyo
state: COMMENTED
author_association: OWNER
submitted_at: 2025-05-15T02:19:48Z

Review comments:
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: Let's try to keep capitalization consistent throughout the post: bril -> Bril and briloop -> Briloop.
created_at: 2025-05-14T19:29:21Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: Seems like a good idea to mark these opcode names with Markdown code backticks: `while`, `block`, `if`, etc.
created_at: 2025-05-14T19:30:07Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: …and presumably `block` as well?

Maybe it would be a good idea to, before getting into the individual opcodes, introduce this new `children` field _in general_ and say that it will be used in several operations. It's interesting to highlight this up front because it means that Brilloop programs, unlike classic Bril programs, look "nested."
created_at: 2025-05-14T19:31:50Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: Consider putting `op` first in the dictionary, for legibility.
created_at: 2025-05-14T19:32:59Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: JSON listings might be a little easier to read if you "wrap" some lines manually. For example, it can be nice to put entire instructions on one line, like this:

```json
{ "args": ["b", "ten"], "dest": "cond", "op": "le", "type": "bool" }
```

Same with, like, `"args": ["cond"]`. It requires a little manual reformatting vs. what you get out of a raw `json.dump`, but it makes a big difference for the reader.
created_at: 2025-05-14T19:33:22Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: (if any)
created_at: 2025-05-14T19:34:30Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: It's maybe worth adding one more sentence to explain what the integer argument means (the "number of loops" to traverse). It goes by somewhat quickly here, and it would be nice to highlight this somewhat non-obvious language choice.
created_at: 2025-05-14T19:35:37Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
+
+For example the following program will print 1 and 2 forever:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+Whereas this program will print 1 followed by infinite twos:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 0;
+    }
+}
+```
+
+## Interpreter Changes
+
+### New Language Constructs
+
+We expanded Bril's control flow capabilities by introducing five new constructs to the interpreter type system:
+
+- `while` - For creating loops
+- `block` - For grouping instructions
+- `if` - For conditional execution
+- `break` - For exiting loops
+- `continue` - For skipping to the next loop iteration
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: I think you've already covered this above? As in, you've already explained the set of new operations you've added and what they mean, so you don't need this section here. You can just say, in one sentence, that you implemented each of the new constructs in the reference interpreter.
created_at: 2025-05-14T19:36:41Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
+
+For example the following program will print 1 and 2 forever:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+Whereas this program will print 1 followed by infinite twos:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 0;
+    }
+}
+```
+
+## Interpreter Changes
+
+### New Language Constructs
+
+We expanded Bril's control flow capabilities by introducing five new constructs to the interpreter type system:
+
+- `while` - For creating loops
+- `block` - For grouping instructions
+- `if` - For conditional execution
+- `break` - For exiting loops
+- `continue` - For skipping to the next loop iteration
+
+### Implementation Challenges
+
+The implementation complexity varied across these new constructs. The `break` and `continue` instructions were relatively straightforward as they act as terminals in the evaluation pipeline - they simply return an action to be handled by their parent control structure.
+
+However, the other three constructs (`while`, `block`, and `if`) demanded more sophisticated handling:
+
+```typescript
+case "if": {
+    if (cond) {
+        return evalBlock(children[0], state);
+    }
+    else {
+        return evalBlock(children[1], state);
+    }
+}
+
+case "block": {
+    const result = evalBlock(children[0], state);
+    if (result.action == "break") {
+        if result.level > 0 {
+            return { action: "break", level: result.level - 1 };
+        }
+        else {
+            return NEXT;
+        }
+    } else if (result.action === "continue") {
+        if (result.level > 0) {
+            return { action: "continue", level: result.level - 1 };
+        } else {
+            return NEXT;
+        }
+    } else {
+        return result;
+    }
+}
+
+case "while": {
+    while true {
+        if (!cond) {
+            return NEXT:
+        }
+        const result = evalBlock(children[0], state);
+        if (result.action == "break") {
+            if (result.level > 0) {
+                return { action: "break", level: result.level - 1 };
+            } else {
+                return NEXT;
+            }
+        } else if result.action == "continue" {
+            if (result.level > 0) {
+                return { action: "continue", level: result.level - 1 };
+            } else {
+                continue;
+            }
+        } else if (
+            result.action === "end" ||
+            result.action === "speculate" ||
+            result.action === "commit" ||
+            result.action === "abort"
+        ) {
+            return result;
+        }
+    }
+}
+
+```
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: Can I encourage you to avoid the temptation to include big blocks of the implementation code here in the blog post? You can always include a link to the GitHub blob page for people who are really interested! But from the reader's perspective, just one or two sentences that briefly captures the _idea_ of the code can be way more valuable than the full code itself.
created_at: 2025-05-14T19:37:59Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
+
+For example the following program will print 1 and 2 forever:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+Whereas this program will print 1 followed by infinite twos:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 0;
+    }
+}
+```
+
+## Interpreter Changes
+
+### New Language Constructs
+
+We expanded Bril's control flow capabilities by introducing five new constructs to the interpreter type system:
+
+- `while` - For creating loops
+- `block` - For grouping instructions
+- `if` - For conditional execution
+- `break` - For exiting loops
+- `continue` - For skipping to the next loop iteration
+
+### Implementation Challenges
+
+The implementation complexity varied across these new constructs. The `break` and `continue` instructions were relatively straightforward as they act as terminals in the evaluation pipeline - they simply return an action to be handled by their parent control structure.
+
+However, the other three constructs (`while`, `block`, and `if`) demanded more sophisticated handling:
+
+```typescript
+case "if": {
+    if (cond) {
+        return evalBlock(children[0], state);
+    }
+    else {
+        return evalBlock(children[1], state);
+    }
+}
+
+case "block": {
+    const result = evalBlock(children[0], state);
+    if (result.action == "break") {
+        if result.level > 0 {
+            return { action: "break", level: result.level - 1 };
+        }
+        else {
+            return NEXT;
+        }
+    } else if (result.action === "continue") {
+        if (result.level > 0) {
+            return { action: "continue", level: result.level - 1 };
+        } else {
+            return NEXT;
+        }
+    } else {
+        return result;
+    }
+}
+
+case "while": {
+    while true {
+        if (!cond) {
+            return NEXT:
+        }
+        const result = evalBlock(children[0], state);
+        if (result.action == "break") {
+            if (result.level > 0) {
+                return { action: "break", level: result.level - 1 };
+            } else {
+                return NEXT;
+            }
+        } else if result.action == "continue" {
+            if (result.level > 0) {
+                return { action: "continue", level: result.level - 1 };
+            } else {
+                continue;
+            }
+        } else if (
+            result.action === "end" ||
+            result.action === "speculate" ||
+            result.action === "commit" ||
+            result.action === "abort"
+        ) {
+            return result;
+        }
+    }
+}
+
+```
+
+This evalBlock function was an additional evaluation helper function that was used to evaluate a block of instructions and return the resulting action. It was used to handle blocks of instructions in the children arrays:
+
+```typescript
+function evalBlock(instrs: bril.Instruction[], state: State): Action {
+  for (let i = 0; i < instrs.length; ++i) {
+    const instr = instrs[i];
+    if ("op" in instr) {
+      const action = evalInstr(instr, state);
+
+      switch (action.action) {
+        case "next":
+          break;
+        case "break":
+        case "continue":
+        case "end":
+        case "speculate":
+        case "commit":
+        case "abort":
+          return action;
+        default:
+          unreachable(action);
+          throw error(`unhandled action ${action.action}`);
+      }
+    }
+  }
+  return NEXT;
+}
+```
+
+The multi-level breaks and continues proved particularly challenging to implement, especially ensuring the correct bubble-up mechanism through nested control structures. Our solution hinged on the `level` counter, which elegantly tracks how many loop boundaries a `break` or `continue` statement needs to cross. During development, we encountered several cases where improper handling of the recursive evaluation caused programs to become trapped in infinite loops. These issues were difficult to debug — we ultimately resorted to execution profiling to trace the interpreter's control flow and identify where it was getting stuck. The resulting implementation not only handles complex control flow patterns correctly but does so with minimal additional overhead on the interpreter.
+
+## Beyond Relooper
+
+The Beyond Relooper algorithm was described by Ramsey as a way to translate Cmm sources into WebAssembly, for this project we adapted the algorith to translate Bril into Briloop. We'll start by providing a high level overview of the algorithm and some of the adaptations we did as the source and target languages are different from what are presented in Ramsey's paper.
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: It might be nice to include a hyperlink or something to explain what Cmm is (I think it's an IR used in GHC?).
created_at: 2025-05-14T19:40:00Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: > … that supports structured control flow, this allows bril programs …

This is a comma splice. Please replace the `,` with a `;` or a `.` (and a new sentence).
created_at: 2025-05-14T19:41:10Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
+
+For example the following program will print 1 and 2 forever:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+Whereas this program will print 1 followed by infinite twos:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 0;
+    }
+}
+```
+
+## Interpreter Changes
+
+### New Language Constructs
+
+We expanded Bril's control flow capabilities by introducing five new constructs to the interpreter type system:
+
+- `while` - For creating loops
+- `block` - For grouping instructions
+- `if` - For conditional execution
+- `break` - For exiting loops
+- `continue` - For skipping to the next loop iteration
+
+### Implementation Challenges
+
+The implementation complexity varied across these new constructs. The `break` and `continue` instructions were relatively straightforward as they act as terminals in the evaluation pipeline - they simply return an action to be handled by their parent control structure.
+
+However, the other three constructs (`while`, `block`, and `if`) demanded more sophisticated handling:
+
+```typescript
+case "if": {
+    if (cond) {
+        return evalBlock(children[0], state);
+    }
+    else {
+        return evalBlock(children[1], state);
+    }
+}
+
+case "block": {
+    const result = evalBlock(children[0], state);
+    if (result.action == "break") {
+        if result.level > 0 {
+            return { action: "break", level: result.level - 1 };
+        }
+        else {
+            return NEXT;
+        }
+    } else if (result.action === "continue") {
+        if (result.level > 0) {
+            return { action: "continue", level: result.level - 1 };
+        } else {
+            return NEXT;
+        }
+    } else {
+        return result;
+    }
+}
+
+case "while": {
+    while true {
+        if (!cond) {
+            return NEXT:
+        }
+        const result = evalBlock(children[0], state);
+        if (result.action == "break") {
+            if (result.level > 0) {
+                return { action: "break", level: result.level - 1 };
+            } else {
+                return NEXT;
+            }
+        } else if result.action == "continue" {
+            if (result.level > 0) {
+                return { action: "continue", level: result.level - 1 };
+            } else {
+                continue;
+            }
+        } else if (
+            result.action === "end" ||
+            result.action === "speculate" ||
+            result.action === "commit" ||
+            result.action === "abort"
+        ) {
+            return result;
+        }
+    }
+}
+
+```
+
+This evalBlock function was an additional evaluation helper function that was used to evaluate a block of instructions and return the resulting action. It was used to handle blocks of instructions in the children arrays:
+
+```typescript
+function evalBlock(instrs: bril.Instruction[], state: State): Action {
+  for (let i = 0; i < instrs.length; ++i) {
+    const instr = instrs[i];
+    if ("op" in instr) {
+      const action = evalInstr(instr, state);
+
+      switch (action.action) {
+        case "next":
+          break;
+        case "break":
+        case "continue":
+        case "end":
+        case "speculate":
+        case "commit":
+        case "abort":
+          return action;
+        default:
+          unreachable(action);
+          throw error(`unhandled action ${action.action}`);
+      }
+    }
+  }
+  return NEXT;
+}
+```
+
+The multi-level breaks and continues proved particularly challenging to implement, especially ensuring the correct bubble-up mechanism through nested control structures. Our solution hinged on the `level` counter, which elegantly tracks how many loop boundaries a `break` or `continue` statement needs to cross. During development, we encountered several cases where improper handling of the recursive evaluation caused programs to become trapped in infinite loops. These issues were difficult to debug — we ultimately resorted to execution profiling to trace the interpreter's control flow and identify where it was getting stuck. The resulting implementation not only handles complex control flow patterns correctly but does so with minimal additional overhead on the interpreter.
+
+## Beyond Relooper
+
+The Beyond Relooper algorithm was described by Ramsey as a way to translate Cmm sources into WebAssembly, for this project we adapted the algorith to translate Bril into Briloop. We'll start by providing a high level overview of the algorithm and some of the adaptations we did as the source and target languages are different from what are presented in Ramsey's paper.
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: "algorith"
created_at: 2025-05-14T19:41:36Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
+
+For example the following program will print 1 and 2 forever:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+Whereas this program will print 1 followed by infinite twos:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 0;
+    }
+}
+```
+
+## Interpreter Changes
+
+### New Language Constructs
+
+We expanded Bril's control flow capabilities by introducing five new constructs to the interpreter type system:
+
+- `while` - For creating loops
+- `block` - For grouping instructions
+- `if` - For conditional execution
+- `break` - For exiting loops
+- `continue` - For skipping to the next loop iteration
+
+### Implementation Challenges
+
+The implementation complexity varied across these new constructs. The `break` and `continue` instructions were relatively straightforward as they act as terminals in the evaluation pipeline - they simply return an action to be handled by their parent control structure.
+
+However, the other three constructs (`while`, `block`, and `if`) demanded more sophisticated handling:
+
+```typescript
+case "if": {
+    if (cond) {
+        return evalBlock(children[0], state);
+    }
+    else {
+        return evalBlock(children[1], state);
+    }
+}
+
+case "block": {
+    const result = evalBlock(children[0], state);
+    if (result.action == "break") {
+        if result.level > 0 {
+            return { action: "break", level: result.level - 1 };
+        }
+        else {
+            return NEXT;
+        }
+    } else if (result.action === "continue") {
+        if (result.level > 0) {
+            return { action: "continue", level: result.level - 1 };
+        } else {
+            return NEXT;
+        }
+    } else {
+        return result;
+    }
+}
+
+case "while": {
+    while true {
+        if (!cond) {
+            return NEXT:
+        }
+        const result = evalBlock(children[0], state);
+        if (result.action == "break") {
+            if (result.level > 0) {
+                return { action: "break", level: result.level - 1 };
+            } else {
+                return NEXT;
+            }
+        } else if result.action == "continue" {
+            if (result.level > 0) {
+                return { action: "continue", level: result.level - 1 };
+            } else {
+                continue;
+            }
+        } else if (
+            result.action === "end" ||
+            result.action === "speculate" ||
+            result.action === "commit" ||
+            result.action === "abort"
+        ) {
+            return result;
+        }
+    }
+}
+
+```
+
+This evalBlock function was an additional evaluation helper function that was used to evaluate a block of instructions and return the resulting action. It was used to handle blocks of instructions in the children arrays:
+
+```typescript
+function evalBlock(instrs: bril.Instruction[], state: State): Action {
+  for (let i = 0; i < instrs.length; ++i) {
+    const instr = instrs[i];
+    if ("op" in instr) {
+      const action = evalInstr(instr, state);
+
+      switch (action.action) {
+        case "next":
+          break;
+        case "break":
+        case "continue":
+        case "end":
+        case "speculate":
+        case "commit":
+        case "abort":
+          return action;
+        default:
+          unreachable(action);
+          throw error(`unhandled action ${action.action}`);
+      }
+    }
+  }
+  return NEXT;
+}
+```
+
+The multi-level breaks and continues proved particularly challenging to implement, especially ensuring the correct bubble-up mechanism through nested control structures. Our solution hinged on the `level` counter, which elegantly tracks how many loop boundaries a `break` or `continue` statement needs to cross. During development, we encountered several cases where improper handling of the recursive evaluation caused programs to become trapped in infinite loops. These issues were difficult to debug — we ultimately resorted to execution profiling to trace the interpreter's control flow and identify where it was getting stuck. The resulting implementation not only handles complex control flow patterns correctly but does so with minimal additional overhead on the interpreter.
+
+## Beyond Relooper
+
+The Beyond Relooper algorithm was described by Ramsey as a way to translate Cmm sources into WebAssembly, for this project we adapted the algorith to translate Bril into Briloop. We'll start by providing a high level overview of the algorithm and some of the adaptations we did as the source and target languages are different from what are presented in Ramsey's paper.
+
+The Beyond Relooper algorithm takes as input the Dominator Tree of a Control Flow Graph, with the important characteristic that the children in the tree are sorted in descending reverse post order, and produces the Briloop Program as an output. It is implemented as a recursive function over the structure of the dominator tree, where the current node is translated into either a while statement, a list of briloop instructions, or a block statement:
+
+- A basic block is translated into a while statement if it is a loop header, we use Ramsey's definition of a block header being a loop header if it has a predecessor with a larger reverse post order than itself rather than the more standard definition of a loop header being a node that has a predecessor that it dominates.
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: > … if it is a loop header, we use Ramsey's definition …

This is a comma splice; please start a new sentence here.
created_at: 2025-05-14T19:42:03Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
+
+For example the following program will print 1 and 2 forever:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+Whereas this program will print 1 followed by infinite twos:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 0;
+    }
+}
+```
+
+## Interpreter Changes
+
+### New Language Constructs
+
+We expanded Bril's control flow capabilities by introducing five new constructs to the interpreter type system:
+
+- `while` - For creating loops
+- `block` - For grouping instructions
+- `if` - For conditional execution
+- `break` - For exiting loops
+- `continue` - For skipping to the next loop iteration
+
+### Implementation Challenges
+
+The implementation complexity varied across these new constructs. The `break` and `continue` instructions were relatively straightforward as they act as terminals in the evaluation pipeline - they simply return an action to be handled by their parent control structure.
+
+However, the other three constructs (`while`, `block`, and `if`) demanded more sophisticated handling:
+
+```typescript
+case "if": {
+    if (cond) {
+        return evalBlock(children[0], state);
+    }
+    else {
+        return evalBlock(children[1], state);
+    }
+}
+
+case "block": {
+    const result = evalBlock(children[0], state);
+    if (result.action == "break") {
+        if result.level > 0 {
+            return { action: "break", level: result.level - 1 };
+        }
+        else {
+            return NEXT;
+        }
+    } else if (result.action === "continue") {
+        if (result.level > 0) {
+            return { action: "continue", level: result.level - 1 };
+        } else {
+            return NEXT;
+        }
+    } else {
+        return result;
+    }
+}
+
+case "while": {
+    while true {
+        if (!cond) {
+            return NEXT:
+        }
+        const result = evalBlock(children[0], state);
+        if (result.action == "break") {
+            if (result.level > 0) {
+                return { action: "break", level: result.level - 1 };
+            } else {
+                return NEXT;
+            }
+        } else if result.action == "continue" {
+            if (result.level > 0) {
+                return { action: "continue", level: result.level - 1 };
+            } else {
+                continue;
+            }
+        } else if (
+            result.action === "end" ||
+            result.action === "speculate" ||
+            result.action === "commit" ||
+            result.action === "abort"
+        ) {
+            return result;
+        }
+    }
+}
+
+```
+
+This evalBlock function was an additional evaluation helper function that was used to evaluate a block of instructions and return the resulting action. It was used to handle blocks of instructions in the children arrays:
+
+```typescript
+function evalBlock(instrs: bril.Instruction[], state: State): Action {
+  for (let i = 0; i < instrs.length; ++i) {
+    const instr = instrs[i];
+    if ("op" in instr) {
+      const action = evalInstr(instr, state);
+
+      switch (action.action) {
+        case "next":
+          break;
+        case "break":
+        case "continue":
+        case "end":
+        case "speculate":
+        case "commit":
+        case "abort":
+          return action;
+        default:
+          unreachable(action);
+          throw error(`unhandled action ${action.action}`);
+      }
+    }
+  }
+  return NEXT;
+}
+```
+
+The multi-level breaks and continues proved particularly challenging to implement, especially ensuring the correct bubble-up mechanism through nested control structures. Our solution hinged on the `level` counter, which elegantly tracks how many loop boundaries a `break` or `continue` statement needs to cross. During development, we encountered several cases where improper handling of the recursive evaluation caused programs to become trapped in infinite loops. These issues were difficult to debug — we ultimately resorted to execution profiling to trace the interpreter's control flow and identify where it was getting stuck. The resulting implementation not only handles complex control flow patterns correctly but does so with minimal additional overhead on the interpreter.
+
+## Beyond Relooper
+
+The Beyond Relooper algorithm was described by Ramsey as a way to translate Cmm sources into WebAssembly, for this project we adapted the algorith to translate Bril into Briloop. We'll start by providing a high level overview of the algorithm and some of the adaptations we did as the source and target languages are different from what are presented in Ramsey's paper.
+
+The Beyond Relooper algorithm takes as input the Dominator Tree of a Control Flow Graph, with the important characteristic that the children in the tree are sorted in descending reverse post order, and produces the Briloop Program as an output. It is implemented as a recursive function over the structure of the dominator tree, where the current node is translated into either a while statement, a list of briloop instructions, or a block statement:
+
+- A basic block is translated into a while statement if it is a loop header, we use Ramsey's definition of a block header being a loop header if it has a predecessor with a larger reverse post order than itself rather than the more standard definition of a loop header being a node that has a predecessor that it dominates.
+- If a basic block is a merge node it is translated into a briloop block statement, to support breaking.
+- Otherwise, the basic block is translated into a flat list of briloop instructions.
+
+Detecting the different kinds of translations allows us to only introduce the minimal number of blocks needed for the translation.
+
+### Merge nodes
+
+Identifying merge nodes is a key part of the briloop algorithm, they are defined as nodes that have at least 2 in edges from nodes with a smaller reverse post order. This means that in the original control flow, there are two basic blocks that jump into it and that thse nodes do not form a loop. Detecting them is important since we need to rely on block statements and break instructions in order to reach them (see Theorem three in Peterson, Kasami, and Tokura for more info).
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: > … a key part of the briloop algorithm, they are defined …

Another comma splice.
created_at: 2025-05-14T19:42:58Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
+
+For example the following program will print 1 and 2 forever:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+Whereas this program will print 1 followed by infinite twos:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 0;
+    }
+}
+```
+
+## Interpreter Changes
+
+### New Language Constructs
+
+We expanded Bril's control flow capabilities by introducing five new constructs to the interpreter type system:
+
+- `while` - For creating loops
+- `block` - For grouping instructions
+- `if` - For conditional execution
+- `break` - For exiting loops
+- `continue` - For skipping to the next loop iteration
+
+### Implementation Challenges
+
+The implementation complexity varied across these new constructs. The `break` and `continue` instructions were relatively straightforward as they act as terminals in the evaluation pipeline - they simply return an action to be handled by their parent control structure.
+
+However, the other three constructs (`while`, `block`, and `if`) demanded more sophisticated handling:
+
+```typescript
+case "if": {
+    if (cond) {
+        return evalBlock(children[0], state);
+    }
+    else {
+        return evalBlock(children[1], state);
+    }
+}
+
+case "block": {
+    const result = evalBlock(children[0], state);
+    if (result.action == "break") {
+        if result.level > 0 {
+            return { action: "break", level: result.level - 1 };
+        }
+        else {
+            return NEXT;
+        }
+    } else if (result.action === "continue") {
+        if (result.level > 0) {
+            return { action: "continue", level: result.level - 1 };
+        } else {
+            return NEXT;
+        }
+    } else {
+        return result;
+    }
+}
+
+case "while": {
+    while true {
+        if (!cond) {
+            return NEXT:
+        }
+        const result = evalBlock(children[0], state);
+        if (result.action == "break") {
+            if (result.level > 0) {
+                return { action: "break", level: result.level - 1 };
+            } else {
+                return NEXT;
+            }
+        } else if result.action == "continue" {
+            if (result.level > 0) {
+                return { action: "continue", level: result.level - 1 };
+            } else {
+                continue;
+            }
+        } else if (
+            result.action === "end" ||
+            result.action === "speculate" ||
+            result.action === "commit" ||
+            result.action === "abort"
+        ) {
+            return result;
+        }
+    }
+}
+
+```
+
+This evalBlock function was an additional evaluation helper function that was used to evaluate a block of instructions and return the resulting action. It was used to handle blocks of instructions in the children arrays:
+
+```typescript
+function evalBlock(instrs: bril.Instruction[], state: State): Action {
+  for (let i = 0; i < instrs.length; ++i) {
+    const instr = instrs[i];
+    if ("op" in instr) {
+      const action = evalInstr(instr, state);
+
+      switch (action.action) {
+        case "next":
+          break;
+        case "break":
+        case "continue":
+        case "end":
+        case "speculate":
+        case "commit":
+        case "abort":
+          return action;
+        default:
+          unreachable(action);
+          throw error(`unhandled action ${action.action}`);
+      }
+    }
+  }
+  return NEXT;
+}
+```
+
+The multi-level breaks and continues proved particularly challenging to implement, especially ensuring the correct bubble-up mechanism through nested control structures. Our solution hinged on the `level` counter, which elegantly tracks how many loop boundaries a `break` or `continue` statement needs to cross. During development, we encountered several cases where improper handling of the recursive evaluation caused programs to become trapped in infinite loops. These issues were difficult to debug — we ultimately resorted to execution profiling to trace the interpreter's control flow and identify where it was getting stuck. The resulting implementation not only handles complex control flow patterns correctly but does so with minimal additional overhead on the interpreter.
+
+## Beyond Relooper
+
+The Beyond Relooper algorithm was described by Ramsey as a way to translate Cmm sources into WebAssembly, for this project we adapted the algorith to translate Bril into Briloop. We'll start by providing a high level overview of the algorithm and some of the adaptations we did as the source and target languages are different from what are presented in Ramsey's paper.
+
+The Beyond Relooper algorithm takes as input the Dominator Tree of a Control Flow Graph, with the important characteristic that the children in the tree are sorted in descending reverse post order, and produces the Briloop Program as an output. It is implemented as a recursive function over the structure of the dominator tree, where the current node is translated into either a while statement, a list of briloop instructions, or a block statement:
+
+- A basic block is translated into a while statement if it is a loop header, we use Ramsey's definition of a block header being a loop header if it has a predecessor with a larger reverse post order than itself rather than the more standard definition of a loop header being a node that has a predecessor that it dominates.
+- If a basic block is a merge node it is translated into a briloop block statement, to support breaking.
+- Otherwise, the basic block is translated into a flat list of briloop instructions.
+
+Detecting the different kinds of translations allows us to only introduce the minimal number of blocks needed for the translation.
+
+### Merge nodes
+
+Identifying merge nodes is a key part of the briloop algorithm, they are defined as nodes that have at least 2 in edges from nodes with a smaller reverse post order. This means that in the original control flow, there are two basic blocks that jump into it and that thse nodes do not form a loop. Detecting them is important since we need to rely on block statements and break instructions in order to reach them (see Theorem three in Peterson, Kasami, and Tokura for more info).
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: It might be nice to hyperlink from those author names to the paper you're referring to.
created_at: 2025-05-14T19:43:34Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
+
+For example the following program will print 1 and 2 forever:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+Whereas this program will print 1 followed by infinite twos:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 0;
+    }
+}
+```
+
+## Interpreter Changes
+
+### New Language Constructs
+
+We expanded Bril's control flow capabilities by introducing five new constructs to the interpreter type system:
+
+- `while` - For creating loops
+- `block` - For grouping instructions
+- `if` - For conditional execution
+- `break` - For exiting loops
+- `continue` - For skipping to the next loop iteration
+
+### Implementation Challenges
+
+The implementation complexity varied across these new constructs. The `break` and `continue` instructions were relatively straightforward as they act as terminals in the evaluation pipeline - they simply return an action to be handled by their parent control structure.
+
+However, the other three constructs (`while`, `block`, and `if`) demanded more sophisticated handling:
+
+```typescript
+case "if": {
+    if (cond) {
+        return evalBlock(children[0], state);
+    }
+    else {
+        return evalBlock(children[1], state);
+    }
+}
+
+case "block": {
+    const result = evalBlock(children[0], state);
+    if (result.action == "break") {
+        if result.level > 0 {
+            return { action: "break", level: result.level - 1 };
+        }
+        else {
+            return NEXT;
+        }
+    } else if (result.action === "continue") {
+        if (result.level > 0) {
+            return { action: "continue", level: result.level - 1 };
+        } else {
+            return NEXT;
+        }
+    } else {
+        return result;
+    }
+}
+
+case "while": {
+    while true {
+        if (!cond) {
+            return NEXT:
+        }
+        const result = evalBlock(children[0], state);
+        if (result.action == "break") {
+            if (result.level > 0) {
+                return { action: "break", level: result.level - 1 };
+            } else {
+                return NEXT;
+            }
+        } else if result.action == "continue" {
+            if (result.level > 0) {
+                return { action: "continue", level: result.level - 1 };
+            } else {
+                continue;
+            }
+        } else if (
+            result.action === "end" ||
+            result.action === "speculate" ||
+            result.action === "commit" ||
+            result.action === "abort"
+        ) {
+            return result;
+        }
+    }
+}
+
+```
+
+This evalBlock function was an additional evaluation helper function that was used to evaluate a block of instructions and return the resulting action. It was used to handle blocks of instructions in the children arrays:
+
+```typescript
+function evalBlock(instrs: bril.Instruction[], state: State): Action {
+  for (let i = 0; i < instrs.length; ++i) {
+    const instr = instrs[i];
+    if ("op" in instr) {
+      const action = evalInstr(instr, state);
+
+      switch (action.action) {
+        case "next":
+          break;
+        case "break":
+        case "continue":
+        case "end":
+        case "speculate":
+        case "commit":
+        case "abort":
+          return action;
+        default:
+          unreachable(action);
+          throw error(`unhandled action ${action.action}`);
+      }
+    }
+  }
+  return NEXT;
+}
+```
+
+The multi-level breaks and continues proved particularly challenging to implement, especially ensuring the correct bubble-up mechanism through nested control structures. Our solution hinged on the `level` counter, which elegantly tracks how many loop boundaries a `break` or `continue` statement needs to cross. During development, we encountered several cases where improper handling of the recursive evaluation caused programs to become trapped in infinite loops. These issues were difficult to debug — we ultimately resorted to execution profiling to trace the interpreter's control flow and identify where it was getting stuck. The resulting implementation not only handles complex control flow patterns correctly but does so with minimal additional overhead on the interpreter.
+
+## Beyond Relooper
+
+The Beyond Relooper algorithm was described by Ramsey as a way to translate Cmm sources into WebAssembly, for this project we adapted the algorith to translate Bril into Briloop. We'll start by providing a high level overview of the algorithm and some of the adaptations we did as the source and target languages are different from what are presented in Ramsey's paper.
+
+The Beyond Relooper algorithm takes as input the Dominator Tree of a Control Flow Graph, with the important characteristic that the children in the tree are sorted in descending reverse post order, and produces the Briloop Program as an output. It is implemented as a recursive function over the structure of the dominator tree, where the current node is translated into either a while statement, a list of briloop instructions, or a block statement:
+
+- A basic block is translated into a while statement if it is a loop header, we use Ramsey's definition of a block header being a loop header if it has a predecessor with a larger reverse post order than itself rather than the more standard definition of a loop header being a node that has a predecessor that it dominates.
+- If a basic block is a merge node it is translated into a briloop block statement, to support breaking.
+- Otherwise, the basic block is translated into a flat list of briloop instructions.
+
+Detecting the different kinds of translations allows us to only introduce the minimal number of blocks needed for the translation.
+
+### Merge nodes
+
+Identifying merge nodes is a key part of the briloop algorithm, they are defined as nodes that have at least 2 in edges from nodes with a smaller reverse post order. This means that in the original control flow, there are two basic blocks that jump into it and that thse nodes do not form a loop. Detecting them is important since we need to rely on block statements and break instructions in order to reach them (see Theorem three in Peterson, Kasami, and Tokura for more info).
+
+To see why this is needed, consider the following example (based on Ramsey):
+![Merge Nodes](merge-nodes.png)
+
+This translation proves difficult to translate without block and break statements as two basic blocks navigate to the same basic block, in this example both B and C are connected to E. If this were expressed in a language with no go to statements, programmers might rely on duplicating the E block in both branches:
+
+```Java
+// Block A
+public void foo(boolean l, boolean r) {
+    System.out.println("Block A");
+    if (l) {
+        if (r) {
+            System.out.println("Block B");
+        } else {
+            System.out.println("Block E");
+        }
+    } else {
+        if (r) {
+            System.out.println("Block E");
+        } else {
+            System.out.println("Block F");
+        }
+    }
+    System.out.println("Block G");
+```
+
+But we want our translation to be minimal, and not rely on duplicate blocks. The beyond relooper algorithm allows this to happen by using `break n;` statements (Peterson et. al.) refer to them as multi-level exit instructions:
+
+```code
+@foo(l: bool, r: bool) {
+    print a;
+    block {
+        block {
+            if (l)
+            then {
+                if (r)
+                then {
+                    print b;
+                    break 1;
+                } else {
+                    break 0;
+                }
+            }
+            else {
+                if (r)
+                then {
+                    break 0;
+                }
+                else {
+                    print f;
+                    break 1;
+                }
+            }
+        }
+        print e;
+        break 0;
+    }
+    print g;
+    ret;
+}
+````
+
+This translation may not be what programmers in languages like Java may write, but since the source contains an arbitrary control flow graph and those allow these kind of statements, we need a correct way to translate them.
+
+### Loop Nodes
+
+Loop nodes are easier to translate, and only two conditions need to be met:
+
+- Loop headers must be translated into while statements.
+- When jumping to a loop header we use a `continue n;` instruction, where n is how many control flow statements we need to skip.
+
+The use of while loops introduces a couple of quirks, one to the language and one to the translation from bril to briloop programs. The language quirk is that not only are you able to execute continue inside of block statements (in which case it behaves just like a break), but you the level passed to the continue statement must take into account block statements. In the following example we can see the behavior at play, foo will print a, b, c repeatedly whereas bar will print a, b
+repeatedly.
+
+```
+@foo(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 0;
+        }
+        print c;
+    }
+}
+
+@bar(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 1;
+        }
+        print c;
+    }
+}
+```
+
+The quirk from the translation to bril to briloop is that we rely on all while loops to execute forever and rely on break statements to terminate the loop execution. This has the unfortunate consequence of worsening performance for loops (especially nested ones) as we introduce a true variable before every while translation.
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: [non-actionable comment; nothing to change here] As we discussed briefly today, I think it would make sense to (in a version 1.1 of this extension) replace `while` with `loop` for this reason! It keeps the language a little simpler, and it seems unlikely to make the downstream WebAssembly backend any more complicated.
created_at: 2025-05-14T19:46:44Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
+
+For example the following program will print 1 and 2 forever:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+Whereas this program will print 1 followed by infinite twos:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 0;
+    }
+}
+```
+
+## Interpreter Changes
+
+### New Language Constructs
+
+We expanded Bril's control flow capabilities by introducing five new constructs to the interpreter type system:
+
+- `while` - For creating loops
+- `block` - For grouping instructions
+- `if` - For conditional execution
+- `break` - For exiting loops
+- `continue` - For skipping to the next loop iteration
+
+### Implementation Challenges
+
+The implementation complexity varied across these new constructs. The `break` and `continue` instructions were relatively straightforward as they act as terminals in the evaluation pipeline - they simply return an action to be handled by their parent control structure.
+
+However, the other three constructs (`while`, `block`, and `if`) demanded more sophisticated handling:
+
+```typescript
+case "if": {
+    if (cond) {
+        return evalBlock(children[0], state);
+    }
+    else {
+        return evalBlock(children[1], state);
+    }
+}
+
+case "block": {
+    const result = evalBlock(children[0], state);
+    if (result.action == "break") {
+        if result.level > 0 {
+            return { action: "break", level: result.level - 1 };
+        }
+        else {
+            return NEXT;
+        }
+    } else if (result.action === "continue") {
+        if (result.level > 0) {
+            return { action: "continue", level: result.level - 1 };
+        } else {
+            return NEXT;
+        }
+    } else {
+        return result;
+    }
+}
+
+case "while": {
+    while true {
+        if (!cond) {
+            return NEXT:
+        }
+        const result = evalBlock(children[0], state);
+        if (result.action == "break") {
+            if (result.level > 0) {
+                return { action: "break", level: result.level - 1 };
+            } else {
+                return NEXT;
+            }
+        } else if result.action == "continue" {
+            if (result.level > 0) {
+                return { action: "continue", level: result.level - 1 };
+            } else {
+                continue;
+            }
+        } else if (
+            result.action === "end" ||
+            result.action === "speculate" ||
+            result.action === "commit" ||
+            result.action === "abort"
+        ) {
+            return result;
+        }
+    }
+}
+
+```
+
+This evalBlock function was an additional evaluation helper function that was used to evaluate a block of instructions and return the resulting action. It was used to handle blocks of instructions in the children arrays:
+
+```typescript
+function evalBlock(instrs: bril.Instruction[], state: State): Action {
+  for (let i = 0; i < instrs.length; ++i) {
+    const instr = instrs[i];
+    if ("op" in instr) {
+      const action = evalInstr(instr, state);
+
+      switch (action.action) {
+        case "next":
+          break;
+        case "break":
+        case "continue":
+        case "end":
+        case "speculate":
+        case "commit":
+        case "abort":
+          return action;
+        default:
+          unreachable(action);
+          throw error(`unhandled action ${action.action}`);
+      }
+    }
+  }
+  return NEXT;
+}
+```
+
+The multi-level breaks and continues proved particularly challenging to implement, especially ensuring the correct bubble-up mechanism through nested control structures. Our solution hinged on the `level` counter, which elegantly tracks how many loop boundaries a `break` or `continue` statement needs to cross. During development, we encountered several cases where improper handling of the recursive evaluation caused programs to become trapped in infinite loops. These issues were difficult to debug — we ultimately resorted to execution profiling to trace the interpreter's control flow and identify where it was getting stuck. The resulting implementation not only handles complex control flow patterns correctly but does so with minimal additional overhead on the interpreter.
+
+## Beyond Relooper
+
+The Beyond Relooper algorithm was described by Ramsey as a way to translate Cmm sources into WebAssembly, for this project we adapted the algorith to translate Bril into Briloop. We'll start by providing a high level overview of the algorithm and some of the adaptations we did as the source and target languages are different from what are presented in Ramsey's paper.
+
+The Beyond Relooper algorithm takes as input the Dominator Tree of a Control Flow Graph, with the important characteristic that the children in the tree are sorted in descending reverse post order, and produces the Briloop Program as an output. It is implemented as a recursive function over the structure of the dominator tree, where the current node is translated into either a while statement, a list of briloop instructions, or a block statement:
+
+- A basic block is translated into a while statement if it is a loop header, we use Ramsey's definition of a block header being a loop header if it has a predecessor with a larger reverse post order than itself rather than the more standard definition of a loop header being a node that has a predecessor that it dominates.
+- If a basic block is a merge node it is translated into a briloop block statement, to support breaking.
+- Otherwise, the basic block is translated into a flat list of briloop instructions.
+
+Detecting the different kinds of translations allows us to only introduce the minimal number of blocks needed for the translation.
+
+### Merge nodes
+
+Identifying merge nodes is a key part of the briloop algorithm, they are defined as nodes that have at least 2 in edges from nodes with a smaller reverse post order. This means that in the original control flow, there are two basic blocks that jump into it and that thse nodes do not form a loop. Detecting them is important since we need to rely on block statements and break instructions in order to reach them (see Theorem three in Peterson, Kasami, and Tokura for more info).
+
+To see why this is needed, consider the following example (based on Ramsey):
+![Merge Nodes](merge-nodes.png)
+
+This translation proves difficult to translate without block and break statements as two basic blocks navigate to the same basic block, in this example both B and C are connected to E. If this were expressed in a language with no go to statements, programmers might rely on duplicating the E block in both branches:
+
+```Java
+// Block A
+public void foo(boolean l, boolean r) {
+    System.out.println("Block A");
+    if (l) {
+        if (r) {
+            System.out.println("Block B");
+        } else {
+            System.out.println("Block E");
+        }
+    } else {
+        if (r) {
+            System.out.println("Block E");
+        } else {
+            System.out.println("Block F");
+        }
+    }
+    System.out.println("Block G");
+```
+
+But we want our translation to be minimal, and not rely on duplicate blocks. The beyond relooper algorithm allows this to happen by using `break n;` statements (Peterson et. al.) refer to them as multi-level exit instructions:
+
+```code
+@foo(l: bool, r: bool) {
+    print a;
+    block {
+        block {
+            if (l)
+            then {
+                if (r)
+                then {
+                    print b;
+                    break 1;
+                } else {
+                    break 0;
+                }
+            }
+            else {
+                if (r)
+                then {
+                    break 0;
+                }
+                else {
+                    print f;
+                    break 1;
+                }
+            }
+        }
+        print e;
+        break 0;
+    }
+    print g;
+    ret;
+}
+````
+
+This translation may not be what programmers in languages like Java may write, but since the source contains an arbitrary control flow graph and those allow these kind of statements, we need a correct way to translate them.
+
+### Loop Nodes
+
+Loop nodes are easier to translate, and only two conditions need to be met:
+
+- Loop headers must be translated into while statements.
+- When jumping to a loop header we use a `continue n;` instruction, where n is how many control flow statements we need to skip.
+
+The use of while loops introduces a couple of quirks, one to the language and one to the translation from bril to briloop programs. The language quirk is that not only are you able to execute continue inside of block statements (in which case it behaves just like a break), but you the level passed to the continue statement must take into account block statements. In the following example we can see the behavior at play, foo will print a, b, c repeatedly whereas bar will print a, b
+repeatedly.
+
+```
+@foo(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 0;
+        }
+        print c;
+    }
+}
+
+@bar(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 1;
+        }
+        print c;
+    }
+}
+```
+
+The quirk from the translation to bril to briloop is that we rely on all while loops to execute forever and rely on break statements to terminate the loop execution. This has the unfortunate consequence of worsening performance for loops (especially nested ones) as we introduce a true variable before every while translation.
+
+## Results
+
+### Impact of Brilooped Transformation on Dynamic Instruction Count
+
+Our analysis of the Bril to Brilooped transformation using the relooper algorithm shows significant variations in dynamic instruction count across different benchmarks. As shown in Figure 1, the majority of benchmarks (37 out of 38) experienced an increase in dynamic instruction count after transformation, with only the `collatz` benchmark showing a reduction (-6.51%) due to `br` and `jmp` instructions making up a majority of the functionality. The changes in dynamic instruction count ranged from minimal increases (below 1%) for benchmarks like `sum-check` and `lcm` to substantial increases exceeding 30% for benchmarks such as `binary-fmt` (28.00%), `hanoi` (31.31%), and `pythagorean_triple` (37.60%).
+
+![Figure 1: Relative Change in Dynamic Instructions After Brilooped Transformation](relative_change.png)
+
+The blue dashed line in Figure 1 is the average (9.06%) change in dynamic instructions after the transformation. 11 of the benchmarks were significantly above (>15%) this average while 9 were significantly below (<1%), leading to a large standard deviation (9.75%)
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: ```suggestion
The blue dashed line in Figure 1 is the average (9.06%) change in dynamic instructions after the transformation. 11 of the benchmarks were significantly above (>15%) this average while 9 were significantly below (<1%), leading to a large standard deviation (9.75%).
```
created_at: 2025-05-14T19:47:45Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
+
+For example the following program will print 1 and 2 forever:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+Whereas this program will print 1 followed by infinite twos:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 0;
+    }
+}
+```
+
+## Interpreter Changes
+
+### New Language Constructs
+
+We expanded Bril's control flow capabilities by introducing five new constructs to the interpreter type system:
+
+- `while` - For creating loops
+- `block` - For grouping instructions
+- `if` - For conditional execution
+- `break` - For exiting loops
+- `continue` - For skipping to the next loop iteration
+
+### Implementation Challenges
+
+The implementation complexity varied across these new constructs. The `break` and `continue` instructions were relatively straightforward as they act as terminals in the evaluation pipeline - they simply return an action to be handled by their parent control structure.
+
+However, the other three constructs (`while`, `block`, and `if`) demanded more sophisticated handling:
+
+```typescript
+case "if": {
+    if (cond) {
+        return evalBlock(children[0], state);
+    }
+    else {
+        return evalBlock(children[1], state);
+    }
+}
+
+case "block": {
+    const result = evalBlock(children[0], state);
+    if (result.action == "break") {
+        if result.level > 0 {
+            return { action: "break", level: result.level - 1 };
+        }
+        else {
+            return NEXT;
+        }
+    } else if (result.action === "continue") {
+        if (result.level > 0) {
+            return { action: "continue", level: result.level - 1 };
+        } else {
+            return NEXT;
+        }
+    } else {
+        return result;
+    }
+}
+
+case "while": {
+    while true {
+        if (!cond) {
+            return NEXT:
+        }
+        const result = evalBlock(children[0], state);
+        if (result.action == "break") {
+            if (result.level > 0) {
+                return { action: "break", level: result.level - 1 };
+            } else {
+                return NEXT;
+            }
+        } else if result.action == "continue" {
+            if (result.level > 0) {
+                return { action: "continue", level: result.level - 1 };
+            } else {
+                continue;
+            }
+        } else if (
+            result.action === "end" ||
+            result.action === "speculate" ||
+            result.action === "commit" ||
+            result.action === "abort"
+        ) {
+            return result;
+        }
+    }
+}
+
+```
+
+This evalBlock function was an additional evaluation helper function that was used to evaluate a block of instructions and return the resulting action. It was used to handle blocks of instructions in the children arrays:
+
+```typescript
+function evalBlock(instrs: bril.Instruction[], state: State): Action {
+  for (let i = 0; i < instrs.length; ++i) {
+    const instr = instrs[i];
+    if ("op" in instr) {
+      const action = evalInstr(instr, state);
+
+      switch (action.action) {
+        case "next":
+          break;
+        case "break":
+        case "continue":
+        case "end":
+        case "speculate":
+        case "commit":
+        case "abort":
+          return action;
+        default:
+          unreachable(action);
+          throw error(`unhandled action ${action.action}`);
+      }
+    }
+  }
+  return NEXT;
+}
+```
+
+The multi-level breaks and continues proved particularly challenging to implement, especially ensuring the correct bubble-up mechanism through nested control structures. Our solution hinged on the `level` counter, which elegantly tracks how many loop boundaries a `break` or `continue` statement needs to cross. During development, we encountered several cases where improper handling of the recursive evaluation caused programs to become trapped in infinite loops. These issues were difficult to debug — we ultimately resorted to execution profiling to trace the interpreter's control flow and identify where it was getting stuck. The resulting implementation not only handles complex control flow patterns correctly but does so with minimal additional overhead on the interpreter.
+
+## Beyond Relooper
+
+The Beyond Relooper algorithm was described by Ramsey as a way to translate Cmm sources into WebAssembly, for this project we adapted the algorith to translate Bril into Briloop. We'll start by providing a high level overview of the algorithm and some of the adaptations we did as the source and target languages are different from what are presented in Ramsey's paper.
+
+The Beyond Relooper algorithm takes as input the Dominator Tree of a Control Flow Graph, with the important characteristic that the children in the tree are sorted in descending reverse post order, and produces the Briloop Program as an output. It is implemented as a recursive function over the structure of the dominator tree, where the current node is translated into either a while statement, a list of briloop instructions, or a block statement:
+
+- A basic block is translated into a while statement if it is a loop header, we use Ramsey's definition of a block header being a loop header if it has a predecessor with a larger reverse post order than itself rather than the more standard definition of a loop header being a node that has a predecessor that it dominates.
+- If a basic block is a merge node it is translated into a briloop block statement, to support breaking.
+- Otherwise, the basic block is translated into a flat list of briloop instructions.
+
+Detecting the different kinds of translations allows us to only introduce the minimal number of blocks needed for the translation.
+
+### Merge nodes
+
+Identifying merge nodes is a key part of the briloop algorithm, they are defined as nodes that have at least 2 in edges from nodes with a smaller reverse post order. This means that in the original control flow, there are two basic blocks that jump into it and that thse nodes do not form a loop. Detecting them is important since we need to rely on block statements and break instructions in order to reach them (see Theorem three in Peterson, Kasami, and Tokura for more info).
+
+To see why this is needed, consider the following example (based on Ramsey):
+![Merge Nodes](merge-nodes.png)
+
+This translation proves difficult to translate without block and break statements as two basic blocks navigate to the same basic block, in this example both B and C are connected to E. If this were expressed in a language with no go to statements, programmers might rely on duplicating the E block in both branches:
+
+```Java
+// Block A
+public void foo(boolean l, boolean r) {
+    System.out.println("Block A");
+    if (l) {
+        if (r) {
+            System.out.println("Block B");
+        } else {
+            System.out.println("Block E");
+        }
+    } else {
+        if (r) {
+            System.out.println("Block E");
+        } else {
+            System.out.println("Block F");
+        }
+    }
+    System.out.println("Block G");
+```
+
+But we want our translation to be minimal, and not rely on duplicate blocks. The beyond relooper algorithm allows this to happen by using `break n;` statements (Peterson et. al.) refer to them as multi-level exit instructions:
+
+```code
+@foo(l: bool, r: bool) {
+    print a;
+    block {
+        block {
+            if (l)
+            then {
+                if (r)
+                then {
+                    print b;
+                    break 1;
+                } else {
+                    break 0;
+                }
+            }
+            else {
+                if (r)
+                then {
+                    break 0;
+                }
+                else {
+                    print f;
+                    break 1;
+                }
+            }
+        }
+        print e;
+        break 0;
+    }
+    print g;
+    ret;
+}
+````
+
+This translation may not be what programmers in languages like Java may write, but since the source contains an arbitrary control flow graph and those allow these kind of statements, we need a correct way to translate them.
+
+### Loop Nodes
+
+Loop nodes are easier to translate, and only two conditions need to be met:
+
+- Loop headers must be translated into while statements.
+- When jumping to a loop header we use a `continue n;` instruction, where n is how many control flow statements we need to skip.
+
+The use of while loops introduces a couple of quirks, one to the language and one to the translation from bril to briloop programs. The language quirk is that not only are you able to execute continue inside of block statements (in which case it behaves just like a break), but you the level passed to the continue statement must take into account block statements. In the following example we can see the behavior at play, foo will print a, b, c repeatedly whereas bar will print a, b
+repeatedly.
+
+```
+@foo(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 0;
+        }
+        print c;
+    }
+}
+
+@bar(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 1;
+        }
+        print c;
+    }
+}
+```
+
+The quirk from the translation to bril to briloop is that we rely on all while loops to execute forever and rely on break statements to terminate the loop execution. This has the unfortunate consequence of worsening performance for loops (especially nested ones) as we introduce a true variable before every while translation.
+
+## Results
+
+### Impact of Brilooped Transformation on Dynamic Instruction Count
+
+Our analysis of the Bril to Brilooped transformation using the relooper algorithm shows significant variations in dynamic instruction count across different benchmarks. As shown in Figure 1, the majority of benchmarks (37 out of 38) experienced an increase in dynamic instruction count after transformation, with only the `collatz` benchmark showing a reduction (-6.51%) due to `br` and `jmp` instructions making up a majority of the functionality. The changes in dynamic instruction count ranged from minimal increases (below 1%) for benchmarks like `sum-check` and `lcm` to substantial increases exceeding 30% for benchmarks such as `binary-fmt` (28.00%), `hanoi` (31.31%), and `pythagorean_triple` (37.60%).
+
+![Figure 1: Relative Change in Dynamic Instructions After Brilooped Transformation](relative_change.png)
+
+The blue dashed line in Figure 1 is the average (9.06%) change in dynamic instructions after the transformation. 11 of the benchmarks were significantly above (>15%) this average while 9 were significantly below (<1%), leading to a large standard deviation (9.75%)
+
+### Execution Time Analysis Across Benchmarks
+
+Figure 2 presents the speedup ratios (Before/After) across all benchmarks. The majority of speedup ratios fall below 1.0 (collatz is the only outlier), indicating an increase in execution time after transformation to Brilooped. The average performance across all benchmarks shows:
+
+- Arithmetic Mean: 0.9235 (7.65% slowdown)
+- Geometric Mean: 0.9203 (7.97% slowdown)
+- Harmonic Mean: 0.9169 (8.31% slowdown)
+
+![Figure 2: Speedup Ratios Across Benchmarks with Different Mean Calculations](speedup_comparison.png)
+
+The speedup ratios vary considerably across benchmarks, with `pythagorean_triple` showing the most significant slowdown (speedup ratio of approximately 0.73 or 27% slowdown), while benchmarks like `collatz` exhibited speedup ratios near or slightly above 1.0, indicating slight improvement to performance. Benchmarks like `pythagorean_triple` struggle in this category due to nested loops.
+
+### Relationship Between Benchmark Size and Transformation Impact
+
+Figure 3 illustrates the relationship between benchmark size (measured in dynamic instructions before the transformation) and the percentage change in dynamic instructions. This shows some interesting patterns:
+
+![Figure 3: Impact of Brilooped Transformation vs Benchmark Size](size_vs_change.png)
+
+1. The most substantial percentage increases occurred in benchmarks of varying sizes, with `pythagorean_triple` (largest at ~10,000 instructions) showing a ~37% increase, `hanoi` (~100 instructions) showing a ~31% increase, and `binary-fmt` (~100 instructions) showing a ~28% increase.
+
+   - Briloop syntax seems to be causing lots of overhead in the smaller examples
+   - Nested loops are very expensive
+   - Recursion can be very expensive
+
+2. There doesn't seem to be any strong correlation between benchmark size and the magnitude of impact from the Brilooped transformation. Both small and large benchmarks showed varying degrees of change. Benchmarks clustered around the 10^2 instruction count range had the greatest variance, ranging from approximately -6% to +31%.
+   - Note: this could be a product of the benchmark suite.
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: I think you can leave this note off—it's true of basically everything all the time. :)
created_at: 2025-05-14T19:48:57Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
+
+For example the following program will print 1 and 2 forever:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+Whereas this program will print 1 followed by infinite twos:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 0;
+    }
+}
+```
+
+## Interpreter Changes
+
+### New Language Constructs
+
+We expanded Bril's control flow capabilities by introducing five new constructs to the interpreter type system:
+
+- `while` - For creating loops
+- `block` - For grouping instructions
+- `if` - For conditional execution
+- `break` - For exiting loops
+- `continue` - For skipping to the next loop iteration
+
+### Implementation Challenges
+
+The implementation complexity varied across these new constructs. The `break` and `continue` instructions were relatively straightforward as they act as terminals in the evaluation pipeline - they simply return an action to be handled by their parent control structure.
+
+However, the other three constructs (`while`, `block`, and `if`) demanded more sophisticated handling:
+
+```typescript
+case "if": {
+    if (cond) {
+        return evalBlock(children[0], state);
+    }
+    else {
+        return evalBlock(children[1], state);
+    }
+}
+
+case "block": {
+    const result = evalBlock(children[0], state);
+    if (result.action == "break") {
+        if result.level > 0 {
+            return { action: "break", level: result.level - 1 };
+        }
+        else {
+            return NEXT;
+        }
+    } else if (result.action === "continue") {
+        if (result.level > 0) {
+            return { action: "continue", level: result.level - 1 };
+        } else {
+            return NEXT;
+        }
+    } else {
+        return result;
+    }
+}
+
+case "while": {
+    while true {
+        if (!cond) {
+            return NEXT:
+        }
+        const result = evalBlock(children[0], state);
+        if (result.action == "break") {
+            if (result.level > 0) {
+                return { action: "break", level: result.level - 1 };
+            } else {
+                return NEXT;
+            }
+        } else if result.action == "continue" {
+            if (result.level > 0) {
+                return { action: "continue", level: result.level - 1 };
+            } else {
+                continue;
+            }
+        } else if (
+            result.action === "end" ||
+            result.action === "speculate" ||
+            result.action === "commit" ||
+            result.action === "abort"
+        ) {
+            return result;
+        }
+    }
+}
+
+```
+
+This evalBlock function was an additional evaluation helper function that was used to evaluate a block of instructions and return the resulting action. It was used to handle blocks of instructions in the children arrays:
+
+```typescript
+function evalBlock(instrs: bril.Instruction[], state: State): Action {
+  for (let i = 0; i < instrs.length; ++i) {
+    const instr = instrs[i];
+    if ("op" in instr) {
+      const action = evalInstr(instr, state);
+
+      switch (action.action) {
+        case "next":
+          break;
+        case "break":
+        case "continue":
+        case "end":
+        case "speculate":
+        case "commit":
+        case "abort":
+          return action;
+        default:
+          unreachable(action);
+          throw error(`unhandled action ${action.action}`);
+      }
+    }
+  }
+  return NEXT;
+}
+```
+
+The multi-level breaks and continues proved particularly challenging to implement, especially ensuring the correct bubble-up mechanism through nested control structures. Our solution hinged on the `level` counter, which elegantly tracks how many loop boundaries a `break` or `continue` statement needs to cross. During development, we encountered several cases where improper handling of the recursive evaluation caused programs to become trapped in infinite loops. These issues were difficult to debug — we ultimately resorted to execution profiling to trace the interpreter's control flow and identify where it was getting stuck. The resulting implementation not only handles complex control flow patterns correctly but does so with minimal additional overhead on the interpreter.
+
+## Beyond Relooper
+
+The Beyond Relooper algorithm was described by Ramsey as a way to translate Cmm sources into WebAssembly, for this project we adapted the algorith to translate Bril into Briloop. We'll start by providing a high level overview of the algorithm and some of the adaptations we did as the source and target languages are different from what are presented in Ramsey's paper.
+
+The Beyond Relooper algorithm takes as input the Dominator Tree of a Control Flow Graph, with the important characteristic that the children in the tree are sorted in descending reverse post order, and produces the Briloop Program as an output. It is implemented as a recursive function over the structure of the dominator tree, where the current node is translated into either a while statement, a list of briloop instructions, or a block statement:
+
+- A basic block is translated into a while statement if it is a loop header, we use Ramsey's definition of a block header being a loop header if it has a predecessor with a larger reverse post order than itself rather than the more standard definition of a loop header being a node that has a predecessor that it dominates.
+- If a basic block is a merge node it is translated into a briloop block statement, to support breaking.
+- Otherwise, the basic block is translated into a flat list of briloop instructions.
+
+Detecting the different kinds of translations allows us to only introduce the minimal number of blocks needed for the translation.
+
+### Merge nodes
+
+Identifying merge nodes is a key part of the briloop algorithm, they are defined as nodes that have at least 2 in edges from nodes with a smaller reverse post order. This means that in the original control flow, there are two basic blocks that jump into it and that thse nodes do not form a loop. Detecting them is important since we need to rely on block statements and break instructions in order to reach them (see Theorem three in Peterson, Kasami, and Tokura for more info).
+
+To see why this is needed, consider the following example (based on Ramsey):
+![Merge Nodes](merge-nodes.png)
+
+This translation proves difficult to translate without block and break statements as two basic blocks navigate to the same basic block, in this example both B and C are connected to E. If this were expressed in a language with no go to statements, programmers might rely on duplicating the E block in both branches:
+
+```Java
+// Block A
+public void foo(boolean l, boolean r) {
+    System.out.println("Block A");
+    if (l) {
+        if (r) {
+            System.out.println("Block B");
+        } else {
+            System.out.println("Block E");
+        }
+    } else {
+        if (r) {
+            System.out.println("Block E");
+        } else {
+            System.out.println("Block F");
+        }
+    }
+    System.out.println("Block G");
+```
+
+But we want our translation to be minimal, and not rely on duplicate blocks. The beyond relooper algorithm allows this to happen by using `break n;` statements (Peterson et. al.) refer to them as multi-level exit instructions:
+
+```code
+@foo(l: bool, r: bool) {
+    print a;
+    block {
+        block {
+            if (l)
+            then {
+                if (r)
+                then {
+                    print b;
+                    break 1;
+                } else {
+                    break 0;
+                }
+            }
+            else {
+                if (r)
+                then {
+                    break 0;
+                }
+                else {
+                    print f;
+                    break 1;
+                }
+            }
+        }
+        print e;
+        break 0;
+    }
+    print g;
+    ret;
+}
+````
+
+This translation may not be what programmers in languages like Java may write, but since the source contains an arbitrary control flow graph and those allow these kind of statements, we need a correct way to translate them.
+
+### Loop Nodes
+
+Loop nodes are easier to translate, and only two conditions need to be met:
+
+- Loop headers must be translated into while statements.
+- When jumping to a loop header we use a `continue n;` instruction, where n is how many control flow statements we need to skip.
+
+The use of while loops introduces a couple of quirks, one to the language and one to the translation from bril to briloop programs. The language quirk is that not only are you able to execute continue inside of block statements (in which case it behaves just like a break), but you the level passed to the continue statement must take into account block statements. In the following example we can see the behavior at play, foo will print a, b, c repeatedly whereas bar will print a, b
+repeatedly.
+
+```
+@foo(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 0;
+        }
+        print c;
+    }
+}
+
+@bar(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 1;
+        }
+        print c;
+    }
+}
+```
+
+The quirk from the translation to bril to briloop is that we rely on all while loops to execute forever and rely on break statements to terminate the loop execution. This has the unfortunate consequence of worsening performance for loops (especially nested ones) as we introduce a true variable before every while translation.
+
+## Results
+
+### Impact of Brilooped Transformation on Dynamic Instruction Count
+
+Our analysis of the Bril to Brilooped transformation using the relooper algorithm shows significant variations in dynamic instruction count across different benchmarks. As shown in Figure 1, the majority of benchmarks (37 out of 38) experienced an increase in dynamic instruction count after transformation, with only the `collatz` benchmark showing a reduction (-6.51%) due to `br` and `jmp` instructions making up a majority of the functionality. The changes in dynamic instruction count ranged from minimal increases (below 1%) for benchmarks like `sum-check` and `lcm` to substantial increases exceeding 30% for benchmarks such as `binary-fmt` (28.00%), `hanoi` (31.31%), and `pythagorean_triple` (37.60%).
+
+![Figure 1: Relative Change in Dynamic Instructions After Brilooped Transformation](relative_change.png)
+
+The blue dashed line in Figure 1 is the average (9.06%) change in dynamic instructions after the transformation. 11 of the benchmarks were significantly above (>15%) this average while 9 were significantly below (<1%), leading to a large standard deviation (9.75%)
+
+### Execution Time Analysis Across Benchmarks
+
+Figure 2 presents the speedup ratios (Before/After) across all benchmarks. The majority of speedup ratios fall below 1.0 (collatz is the only outlier), indicating an increase in execution time after transformation to Brilooped. The average performance across all benchmarks shows:
+
+- Arithmetic Mean: 0.9235 (7.65% slowdown)
+- Geometric Mean: 0.9203 (7.97% slowdown)
+- Harmonic Mean: 0.9169 (8.31% slowdown)
+
+![Figure 2: Speedup Ratios Across Benchmarks with Different Mean Calculations](speedup_comparison.png)
+
+The speedup ratios vary considerably across benchmarks, with `pythagorean_triple` showing the most significant slowdown (speedup ratio of approximately 0.73 or 27% slowdown), while benchmarks like `collatz` exhibited speedup ratios near or slightly above 1.0, indicating slight improvement to performance. Benchmarks like `pythagorean_triple` struggle in this category due to nested loops.
+
+### Relationship Between Benchmark Size and Transformation Impact
+
+Figure 3 illustrates the relationship between benchmark size (measured in dynamic instructions before the transformation) and the percentage change in dynamic instructions. This shows some interesting patterns:
+
+![Figure 3: Impact of Brilooped Transformation vs Benchmark Size](size_vs_change.png)
+
+1. The most substantial percentage increases occurred in benchmarks of varying sizes, with `pythagorean_triple` (largest at ~10,000 instructions) showing a ~37% increase, `hanoi` (~100 instructions) showing a ~31% increase, and `binary-fmt` (~100 instructions) showing a ~28% increase.
+
+   - Briloop syntax seems to be causing lots of overhead in the smaller examples
+   - Nested loops are very expensive
+   - Recursion can be very expensive
+
+2. There doesn't seem to be any strong correlation between benchmark size and the magnitude of impact from the Brilooped transformation. Both small and large benchmarks showed varying degrees of change. Benchmarks clustered around the 10^2 instruction count range had the greatest variance, ranging from approximately -6% to +31%.
+   - Note: this could be a product of the benchmark suite.
+
+### Before vs. After Comparison with Percentage Changes
+
+Figure 4 provides a comparison of the total dynamic instructions before and after the Brilooped transformation on a logarithmic scale, along with the percentage changes for each benchmark. The top graph demonstrates that while the absolute instruction count increases for almost all benchmarks, the relative differences vary significantly.
+
+![Figure 4: Before vs After Comparison (Log Scale) with Percentage Changes](log_scale_comparison.png)
+
+### Summary of Findings
+
+1. The Brilooped transformation using the relooper algorithm resulted in increased dynamic instruction counts for 37 out of 38 benchmarks, with increases ranging from negligible to substantial (up to 37.60%).
+
+2. The overall performance impact was a modest slowdown, with average execution time increases between 7.65% and 8.31% depending on the mean calculation method.
+
+3. The benchmarks most affected by the transformation were `pythagorean_triple`, `hanoi`, and `binary-fmt`, while `collatz` was the only benchmark that saw reduced instruction count after transformation.
+
+4. **Most importantly, all benchmarks in the test suite produced correct results after transformation to Brilooped**, confirming the semantic correctness of our implementation of the relooper algorithm.
+
+These results suggest that while transforming Bril code to Brilooped using the relooper algorithm introduces some overhead in most cases, the structured control flow benefits of Brilooped come with a reasonable performance cost. The high variance in impact across different benchmarks indicates that the transformation's efficiency depends significantly on the specific control flow patterns in the original code. This tradeoff seems acceptable, especially considering that all benchmarks maintained their functional correctness.
+
+### References
+
+Peterson, Kasami, Tokura. "On the capabilities of while, repeat, and exit statements". https://dl.acm.org/doi/10.1145/355609.362337
+
+Ramsey, Norman. "Beyond Relooper: recursive translation of unstructured control flow to structured control flow (functional perl)". https://dl.acm.org/doi/10.1145/3547621
+
+Leroy, Xavier. "The birth of control structures: from 'goto' to structured programming". https://xavierleroy.org/CdF/2023-2024/1.pdf
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: Because this is a webpage and not a PDF, I recommend just linking to these papers from the text instead of having a separate "references" section at the end!
created_at: 2025-05-14T19:50:11Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
path: content/blog/2025-05-13-brilooped/index.md
user: login: gerardogtn
body: great catch! expanded this section quite a bit and added some examples for break and continue. I agree that it's non-obvious and i tried to include the examples that i used when talking to the wasm team to clarify its behaviour, open to more changes if we can still improve this section
created_at: 2025-05-15T02:00:32Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
path: content/blog/2025-05-13-brilooped/index.md
user: login: gerardogtn
body: great catch! guilty as charged of overusing comma splices. All three of them should be fixed now
created_at: 2025-05-15T02:02:56Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
+
+For example the following program will print 1 and 2 forever:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+Whereas this program will print 1 followed by infinite twos:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 0;
+    }
+}
+```
+
+## Interpreter Changes
+
+### New Language Constructs
+
+We expanded Bril's control flow capabilities by introducing five new constructs to the interpreter type system:
+
+- `while` - For creating loops
+- `block` - For grouping instructions
+- `if` - For conditional execution
+- `break` - For exiting loops
+- `continue` - For skipping to the next loop iteration
+
+### Implementation Challenges
+
+The implementation complexity varied across these new constructs. The `break` and `continue` instructions were relatively straightforward as they act as terminals in the evaluation pipeline - they simply return an action to be handled by their parent control structure.
+
+However, the other three constructs (`while`, `block`, and `if`) demanded more sophisticated handling:
+
+```typescript
+case "if": {
+    if (cond) {
+        return evalBlock(children[0], state);
+    }
+    else {
+        return evalBlock(children[1], state);
+    }
+}
+
+case "block": {
+    const result = evalBlock(children[0], state);
+    if (result.action == "break") {
+        if result.level > 0 {
+            return { action: "break", level: result.level - 1 };
+        }
+        else {
+            return NEXT;
+        }
+    } else if (result.action === "continue") {
+        if (result.level > 0) {
+            return { action: "continue", level: result.level - 1 };
+        } else {
+            return NEXT;
+        }
+    } else {
+        return result;
+    }
+}
+
+case "while": {
+    while true {
+        if (!cond) {
+            return NEXT:
+        }
+        const result = evalBlock(children[0], state);
+        if (result.action == "break") {
+            if (result.level > 0) {
+                return { action: "break", level: result.level - 1 };
+            } else {
+                return NEXT;
+            }
+        } else if result.action == "continue" {
+            if (result.level > 0) {
+                return { action: "continue", level: result.level - 1 };
+            } else {
+                continue;
+            }
+        } else if (
+            result.action === "end" ||
+            result.action === "speculate" ||
+            result.action === "commit" ||
+            result.action === "abort"
+        ) {
+            return result;
+        }
+    }
+}
+
+```
+
+This evalBlock function was an additional evaluation helper function that was used to evaluate a block of instructions and return the resulting action. It was used to handle blocks of instructions in the children arrays:
+
+```typescript
+function evalBlock(instrs: bril.Instruction[], state: State): Action {
+  for (let i = 0; i < instrs.length; ++i) {
+    const instr = instrs[i];
+    if ("op" in instr) {
+      const action = evalInstr(instr, state);
+
+      switch (action.action) {
+        case "next":
+          break;
+        case "break":
+        case "continue":
+        case "end":
+        case "speculate":
+        case "commit":
+        case "abort":
+          return action;
+        default:
+          unreachable(action);
+          throw error(`unhandled action ${action.action}`);
+      }
+    }
+  }
+  return NEXT;
+}
+```
+
+The multi-level breaks and continues proved particularly challenging to implement, especially ensuring the correct bubble-up mechanism through nested control structures. Our solution hinged on the `level` counter, which elegantly tracks how many loop boundaries a `break` or `continue` statement needs to cross. During development, we encountered several cases where improper handling of the recursive evaluation caused programs to become trapped in infinite loops. These issues were difficult to debug — we ultimately resorted to execution profiling to trace the interpreter's control flow and identify where it was getting stuck. The resulting implementation not only handles complex control flow patterns correctly but does so with minimal additional overhead on the interpreter.
+
+## Beyond Relooper
+
+The Beyond Relooper algorithm was described by Ramsey as a way to translate Cmm sources into WebAssembly, for this project we adapted the algorith to translate Bril into Briloop. We'll start by providing a high level overview of the algorithm and some of the adaptations we did as the source and target languages are different from what are presented in Ramsey's paper.
+
+The Beyond Relooper algorithm takes as input the Dominator Tree of a Control Flow Graph, with the important characteristic that the children in the tree are sorted in descending reverse post order, and produces the Briloop Program as an output. It is implemented as a recursive function over the structure of the dominator tree, where the current node is translated into either a while statement, a list of briloop instructions, or a block statement:
+
+- A basic block is translated into a while statement if it is a loop header, we use Ramsey's definition of a block header being a loop header if it has a predecessor with a larger reverse post order than itself rather than the more standard definition of a loop header being a node that has a predecessor that it dominates.
+- If a basic block is a merge node it is translated into a briloop block statement, to support breaking.
+- Otherwise, the basic block is translated into a flat list of briloop instructions.
+
+Detecting the different kinds of translations allows us to only introduce the minimal number of blocks needed for the translation.
+
+### Merge nodes
+
+Identifying merge nodes is a key part of the briloop algorithm, they are defined as nodes that have at least 2 in edges from nodes with a smaller reverse post order. This means that in the original control flow, there are two basic blocks that jump into it and that thse nodes do not form a loop. Detecting them is important since we need to rely on block statements and break instructions in order to reach them (see Theorem three in Peterson, Kasami, and Tokura for more info).
+
+To see why this is needed, consider the following example (based on Ramsey):
+![Merge Nodes](merge-nodes.png)
+
+This translation proves difficult to translate without block and break statements as two basic blocks navigate to the same basic block, in this example both B and C are connected to E. If this were expressed in a language with no go to statements, programmers might rely on duplicating the E block in both branches:
+
+```Java
+// Block A
+public void foo(boolean l, boolean r) {
+    System.out.println("Block A");
+    if (l) {
+        if (r) {
+            System.out.println("Block B");
+        } else {
+            System.out.println("Block E");
+        }
+    } else {
+        if (r) {
+            System.out.println("Block E");
+        } else {
+            System.out.println("Block F");
+        }
+    }
+    System.out.println("Block G");
+```
+
+But we want our translation to be minimal, and not rely on duplicate blocks. The beyond relooper algorithm allows this to happen by using `break n;` statements (Peterson et. al.) refer to them as multi-level exit instructions:
+
+```code
+@foo(l: bool, r: bool) {
+    print a;
+    block {
+        block {
+            if (l)
+            then {
+                if (r)
+                then {
+                    print b;
+                    break 1;
+                } else {
+                    break 0;
+                }
+            }
+            else {
+                if (r)
+                then {
+                    break 0;
+                }
+                else {
+                    print f;
+                    break 1;
+                }
+            }
+        }
+        print e;
+        break 0;
+    }
+    print g;
+    ret;
+}
+````
+
+This translation may not be what programmers in languages like Java may write, but since the source contains an arbitrary control flow graph and those allow these kind of statements, we need a correct way to translate them.
+
+### Loop Nodes
+
+Loop nodes are easier to translate, and only two conditions need to be met:
+
+- Loop headers must be translated into while statements.
+- When jumping to a loop header we use a `continue n;` instruction, where n is how many control flow statements we need to skip.
+
+The use of while loops introduces a couple of quirks, one to the language and one to the translation from bril to briloop programs. The language quirk is that not only are you able to execute continue inside of block statements (in which case it behaves just like a break), but you the level passed to the continue statement must take into account block statements. In the following example we can see the behavior at play, foo will print a, b, c repeatedly whereas bar will print a, b
+repeatedly.
+
+```
+@foo(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 0;
+        }
+        print c;
+    }
+}
+
+@bar(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 1;
+        }
+        print c;
+    }
+}
+```
+
+The quirk from the translation to bril to briloop is that we rely on all while loops to execute forever and rely on break statements to terminate the loop execution. This has the unfortunate consequence of worsening performance for loops (especially nested ones) as we introduce a true variable before every while translation.
path: content/blog/2025-05-13-brilooped/index.md
user: login: gerardogtn
body: I can change whiles to loop operations for the merge into the bril repo. It would definitely make things nicer and it's one of the few things that i wished we had used since the beginning instead of a while loop
created_at: 2025-05-15T02:04:14Z
author_association: CONTRIBUTOR
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: Looks great!
created_at: 2025-05-15T02:18:26Z
author_association: OWNER
diff_hunk: @@ -0,0 +1,443 @@
++++
+title = "Brilooped"
+[[extra.authors]]
+name = "Gerardo Garcia Teruel Noriega"
+[[extra.authors]]
+name = "Dev Patel"
++++
+
+# Brilooped
+
+## Abstract
+
+In this project we introduce Briloop, an extension into the [Bril programming language](https://capra.cs.cornell.edu/bril/) that supports structured control flow, this allows bril programs to use if-then-else, while, and block statements instead of relying on jumps and branches. We also implemented Ramsey's [Beyond Relooper](https://dl.acm.org/doi/10.1145/3547621) to translate bril programs into briloop automatically, having a an average performance penalty of 9% when using the core bril benchmarks. Brilooped not only enables programmers to write bril programs with structured control flow, but also enables a translation from Bril into WebAssembly.
+
+## Representing Briloop Programs
+
+Brilooped programs extends the Bril instruction set with the following op codes: while, block, if, break, and continue.
+Brilooped extends the Bril instruction set with new control flow operations that provide structured alternatives to jumps and labels. These new op codes allow programmers to write more readable and maintainable code with familiar control flow constructs like loops and conditionals. This structured control flow can also be useful for specific applications such as WASM.
+
+### `while`
+
+The `while` operation introduces a structured loop into Bril programs:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the loop condition.
+- It includes an additional `children` field that contains an array of arrays of `Instr` objects representing the loop body.
+  - Note: this is an array of arrays to make the language a little more uniform (children field is used in both while loops and if-then-else statements)
+- The condition is evaluated before each iteration. If true, the body executes; if false, the loop terminates.
+- The instructions within the loop body are responsible for potentially updating the condition variable.
+
+Example usage:
+
+```json
+{
+  "args": [
+    "cond"
+  ],
+  "children": [
+    [
+      {
+        "args": [
+          "a",
+          "b"
+        ],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      },
+      {
+        "args": ["b", "ten"],
+        "dest": "cond",
+        "op": "le",
+        "type": "bool"
+      }
+    ]
+  ],
+  "op": "while"
+},
+```
+
+```
+ten: int = const 10;
+a: int = const 1;
+b: int = const 0;
+cond: bool = id true;
+while cond {
+    b: int = add a b;
+    cond: bool = le b ten;
+}
+```
+
+### `if`
+
+The `if` operation implements conditional execution:
+
+- It takes exactly one argument: a string containing the name of a boolean variable that serves as the condition.
+- It includes a `children` field with an array of arrays of `Instr` objects.
+  - This will contain 1 or 2 arrays, belonging to the True and False blocks respectively.
+  - When the condition is true, the first array of `Instrs` objects in the `children` is executed.
+  - When it is false, the second array is executed.
+
+Example usage:
+
+```json
+{
+  "args": ["cond"],
+  "children": [
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "add",
+        "type": "int"
+      }
+    ],
+    [
+      {
+        "args": ["a", "b"],
+        "dest": "temp",
+        "op": "sub",
+        "type": "int"
+      }
+    ]
+  ],
+  "op": "if"
+}
+```
+
+```
+cond: bool = id true;
+if cond
+then {
+    temp: int = add a b;
+}
+else {
+    temp: int = sub a b;
+}
+
+```
+
+### The `break` and `continue` Operations
+
+Two additional operations provide finer control within loops:
+
+- `break`: Takes one constant argument and exits `value` loops. This brings execution to the top of this loop.
+- `continue`: Takes one constant argument and exits `value` loops. This continues execution at the following instruction.
+
+For example the following program will print 1 and 2 forever:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 1;
+    }
+}
+```
+
+Whereas this program will print 1 followed by infinite twos:
+
+```
+cond: bool = const true;
+one: int = const 1;
+two: int = const 2;
+while cond {
+    print one;
+    while cond {
+        print two;
+        continue 0;
+    }
+}
+```
+
+## Interpreter Changes
+
+### New Language Constructs
+
+We expanded Bril's control flow capabilities by introducing five new constructs to the interpreter type system:
+
+- `while` - For creating loops
+- `block` - For grouping instructions
+- `if` - For conditional execution
+- `break` - For exiting loops
+- `continue` - For skipping to the next loop iteration
+
+### Implementation Challenges
+
+The implementation complexity varied across these new constructs. The `break` and `continue` instructions were relatively straightforward as they act as terminals in the evaluation pipeline - they simply return an action to be handled by their parent control structure.
+
+However, the other three constructs (`while`, `block`, and `if`) demanded more sophisticated handling:
+
+```typescript
+case "if": {
+    if (cond) {
+        return evalBlock(children[0], state);
+    }
+    else {
+        return evalBlock(children[1], state);
+    }
+}
+
+case "block": {
+    const result = evalBlock(children[0], state);
+    if (result.action == "break") {
+        if result.level > 0 {
+            return { action: "break", level: result.level - 1 };
+        }
+        else {
+            return NEXT;
+        }
+    } else if (result.action === "continue") {
+        if (result.level > 0) {
+            return { action: "continue", level: result.level - 1 };
+        } else {
+            return NEXT;
+        }
+    } else {
+        return result;
+    }
+}
+
+case "while": {
+    while true {
+        if (!cond) {
+            return NEXT:
+        }
+        const result = evalBlock(children[0], state);
+        if (result.action == "break") {
+            if (result.level > 0) {
+                return { action: "break", level: result.level - 1 };
+            } else {
+                return NEXT;
+            }
+        } else if result.action == "continue" {
+            if (result.level > 0) {
+                return { action: "continue", level: result.level - 1 };
+            } else {
+                continue;
+            }
+        } else if (
+            result.action === "end" ||
+            result.action === "speculate" ||
+            result.action === "commit" ||
+            result.action === "abort"
+        ) {
+            return result;
+        }
+    }
+}
+
+```
+
+This evalBlock function was an additional evaluation helper function that was used to evaluate a block of instructions and return the resulting action. It was used to handle blocks of instructions in the children arrays:
+
+```typescript
+function evalBlock(instrs: bril.Instruction[], state: State): Action {
+  for (let i = 0; i < instrs.length; ++i) {
+    const instr = instrs[i];
+    if ("op" in instr) {
+      const action = evalInstr(instr, state);
+
+      switch (action.action) {
+        case "next":
+          break;
+        case "break":
+        case "continue":
+        case "end":
+        case "speculate":
+        case "commit":
+        case "abort":
+          return action;
+        default:
+          unreachable(action);
+          throw error(`unhandled action ${action.action}`);
+      }
+    }
+  }
+  return NEXT;
+}
+```
+
+The multi-level breaks and continues proved particularly challenging to implement, especially ensuring the correct bubble-up mechanism through nested control structures. Our solution hinged on the `level` counter, which elegantly tracks how many loop boundaries a `break` or `continue` statement needs to cross. During development, we encountered several cases where improper handling of the recursive evaluation caused programs to become trapped in infinite loops. These issues were difficult to debug — we ultimately resorted to execution profiling to trace the interpreter's control flow and identify where it was getting stuck. The resulting implementation not only handles complex control flow patterns correctly but does so with minimal additional overhead on the interpreter.
+
+## Beyond Relooper
+
+The Beyond Relooper algorithm was described by Ramsey as a way to translate Cmm sources into WebAssembly, for this project we adapted the algorith to translate Bril into Briloop. We'll start by providing a high level overview of the algorithm and some of the adaptations we did as the source and target languages are different from what are presented in Ramsey's paper.
+
+The Beyond Relooper algorithm takes as input the Dominator Tree of a Control Flow Graph, with the important characteristic that the children in the tree are sorted in descending reverse post order, and produces the Briloop Program as an output. It is implemented as a recursive function over the structure of the dominator tree, where the current node is translated into either a while statement, a list of briloop instructions, or a block statement:
+
+- A basic block is translated into a while statement if it is a loop header, we use Ramsey's definition of a block header being a loop header if it has a predecessor with a larger reverse post order than itself rather than the more standard definition of a loop header being a node that has a predecessor that it dominates.
+- If a basic block is a merge node it is translated into a briloop block statement, to support breaking.
+- Otherwise, the basic block is translated into a flat list of briloop instructions.
+
+Detecting the different kinds of translations allows us to only introduce the minimal number of blocks needed for the translation.
+
+### Merge nodes
+
+Identifying merge nodes is a key part of the briloop algorithm, they are defined as nodes that have at least 2 in edges from nodes with a smaller reverse post order. This means that in the original control flow, there are two basic blocks that jump into it and that thse nodes do not form a loop. Detecting them is important since we need to rely on block statements and break instructions in order to reach them (see Theorem three in Peterson, Kasami, and Tokura for more info).
+
+To see why this is needed, consider the following example (based on Ramsey):
+![Merge Nodes](merge-nodes.png)
+
+This translation proves difficult to translate without block and break statements as two basic blocks navigate to the same basic block, in this example both B and C are connected to E. If this were expressed in a language with no go to statements, programmers might rely on duplicating the E block in both branches:
+
+```Java
+// Block A
+public void foo(boolean l, boolean r) {
+    System.out.println("Block A");
+    if (l) {
+        if (r) {
+            System.out.println("Block B");
+        } else {
+            System.out.println("Block E");
+        }
+    } else {
+        if (r) {
+            System.out.println("Block E");
+        } else {
+            System.out.println("Block F");
+        }
+    }
+    System.out.println("Block G");
+```
+
+But we want our translation to be minimal, and not rely on duplicate blocks. The beyond relooper algorithm allows this to happen by using `break n;` statements (Peterson et. al.) refer to them as multi-level exit instructions:
+
+```code
+@foo(l: bool, r: bool) {
+    print a;
+    block {
+        block {
+            if (l)
+            then {
+                if (r)
+                then {
+                    print b;
+                    break 1;
+                } else {
+                    break 0;
+                }
+            }
+            else {
+                if (r)
+                then {
+                    break 0;
+                }
+                else {
+                    print f;
+                    break 1;
+                }
+            }
+        }
+        print e;
+        break 0;
+    }
+    print g;
+    ret;
+}
+````
+
+This translation may not be what programmers in languages like Java may write, but since the source contains an arbitrary control flow graph and those allow these kind of statements, we need a correct way to translate them.
+
+### Loop Nodes
+
+Loop nodes are easier to translate, and only two conditions need to be met:
+
+- Loop headers must be translated into while statements.
+- When jumping to a loop header we use a `continue n;` instruction, where n is how many control flow statements we need to skip.
+
+The use of while loops introduces a couple of quirks, one to the language and one to the translation from bril to briloop programs. The language quirk is that not only are you able to execute continue inside of block statements (in which case it behaves just like a break), but you the level passed to the continue statement must take into account block statements. In the following example we can see the behavior at play, foo will print a, b, c repeatedly whereas bar will print a, b
+repeatedly.
+
+```
+@foo(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 0;
+        }
+        print c;
+    }
+}
+
+@bar(cond: bool) {
+    while cond {
+        print a;
+        block {
+            print b;
+            continue 1;
+        }
+        print c;
+    }
+}
+```
+
+The quirk from the translation to bril to briloop is that we rely on all while loops to execute forever and rely on break statements to terminate the loop execution. This has the unfortunate consequence of worsening performance for loops (especially nested ones) as we introduce a true variable before every while translation.
path: content/blog/2025-05-13-brilooped/index.md
user: login: sampsyo
body: FWIW, I think it would be just fine to merge stuff you already have, and we can try to address the `while` -> `loop` simplification in a future PR! Whatever strategy makes sense to you.
created_at: 2025-05-15T02:19:48Z
author_association: OWNER

PR comments:
user: login: gerardogtn
created_at: 2025-05-15T02:09:26Z
body: > Very very cool; nice work here! This is a substantial chunk of implementation work, and you've done a great job of explaining what you've done. And the empirical evaluation is great as well!!
> 
> I would love to merge two things into the main Bril monorepo:
> 
>     * The specification of the Briloop language extension.
> 
>     * The "Beyond Relooper" implementation that does the transformation.
> 
> 
> Could I have your help opening some PRs for those into the Bril repo so we can get those merged? 😇

For the briloop language extension, we tried to keep things separate in the development repo by making a copy of `briltxt.py` and naming it `brilooptxt.py` for example. Would you prefer we merge this into the briltxt.py and keep it as the default behaviour of `bril2json`/`bril2txt`, or would you prefer to keep them as separate commands?

I'll work on sending a PR with the beyond relooper algorithm!
author_association: CONTRIBUTOR
user: login: sampsyo
created_at: 2025-05-15T02:21:28Z
body: > For the briloop language extension, we tried to keep things separate in the development repo by making a copy of `briltxt.py` and naming it `brilooptxt.py` for example. Would you prefer we merge this into the briltxt.py and keep it as the default behaviour of `bril2json`/`bril2txt`, or would you prefer to keep them as separate commands?

I think it makes sense to just have one such command! That's the basic idea with all the Bril language extensions: the support exists in such common Bril tools as the parser and printer, but you don't have to use them. In other words, their presence in the parser/printer doesn't interfere with code that doesn't use the constructs.
author_association: OWNER
user: login: sampsyo
created_at: 2025-05-15T02:21:40Z
body: Anyway, this all looks great! I'll publish this post now.
author_association: OWNER