Skip to content

Conversation

@mse63
Copy link
Contributor

@mse63 mse63 commented May 13, 2025

Closes #513

Copy link
Owner

@sampsyo sampsyo left a comment

Choose a reason for hiding this comment

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

Thanks for the writeup. It sounds like you eventually took my advice from #513 and did not attempt any of the "decompiler" aspects—focusing instead on the straightforward "C backend" aspects. Which makes sense! Even a simple CFG recovery strategy would be complicated to do.

Would you be interested in contributing your bril2c compiler to the Bril monorepo? I can imagine it being useful to other folks down the line!

name = "Mahmoud Elsharawy Sampson"
+++

# Bril2C
Copy link
Owner

Choose a reason for hiding this comment

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

No need to repeat the post title; it's already rendered by default.

+++

# Bril2C
This project is intended to translate code from Bril (Big Red Intermediate Language) to C. Bril is an educational intermediate language used in the CS6120 course at Cornell University. As an intermediate language, it is low-level, which would make it difficult to translate to a high-level language. However, C, with features such as manual memory management and goto statements, makes it a natural choice. In my initial proposal, I thought creating a complete and correct translation from Bril to C would be trivial, but indeed quite a bit of hacking was needed, due to limitations of C not placed on Bril.
Copy link
Owner

Choose a reason for hiding this comment

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

It might be helpful to add a hyperlink when you introduce Bril.

## Implementation
Bril2C is written in Rust, using the "bril-rs" package. Most of the actual translation work happens in a single trait, `Crep`, which contains a single function `crep(self) -> String`. Each piece of Bril implements this function with how it translates itself to C, calling `crep` on smaller pieces, effectively inducting on the structure of the program. For example, `crep` for a program will, along with other things, call `crep` for each function in that program, which will call `crep` for each instruction, which will call `crep` for each operation and variable. In this way, adding additional features of Bril into C becomes as easy as implementing a single function for a specific type.

As it turns out, quite some fiddling is required to get even a majority of Bril code working. Almost all of the benchmarks have `main` function which takes in arguments, something not possible in `C`. We get around this by creating our own `main` function in C, which parses arguments from the command line, and passes them into a copy that's supposed to represent the Bril's main function, called `main_f`. Taking an example, `sum-bits.bril`, with a main function that takes in a single integer argument, this is represented as:
Copy link
Owner

Choose a reason for hiding this comment

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

No need for backticks around C, the name of the programming language.

int64_t: printf("%" PRId64 " ", x),
uint8_t: printf("%s ", (x) ? "true" : "false"),
double: printf("%.17f ", x))
```
Copy link
Owner

Choose a reason for hiding this comment

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

Interesting approach to supporting print! FWIW, for both the issue of main arguments and for print, there is a way that you could consider simplifying code generation by reusing an existing "runtime library" for one of the other Bril-to-native compilers, like this:
https://github.com/sampsyo/bril/blob/main/brilift/rt.c

That's a library of little C functions that do things like parse each command-line argument or print something of a particular type. You can use the Bril type information to select the appropriate _bril_print_* function.

return diff_;
}
```
At this point, you may have noticed the additional characters in each variable name and suffix name. These are inserted to prevent bril registers from being confused with C keywords, which is surprisingly popular in Bril code, especially for words like `if` and `continue`.
Copy link
Owner

Choose a reason for hiding this comment

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

bril -> Bril

uint8_t: printf("%s ", (x) ? "true" : "false"),
double: printf("%.17f ", x))
```
For ease of programming, each function declares all of the variables used in it at the beginning of the function After that, it's a "simple" translation from Bril instructions to C statements. Therefore, the following function in Bril:
Copy link
Owner

Choose a reason for hiding this comment

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

Suggested change
For ease of programming, each function declares all of the variables used in it at the beginning of the function After that, it's a "simple" translation from Bril instructions to C statements. Therefore, the following function in Bril:
For ease of programming, each function declares all of the variables used in it at the beginning of the function. After that, it's a "simple" translation from Bril instructions to C statements. Therefore, the following function in Bril:

```

## Evaluation
Creating a program to translate a single Bril program into C is easy. Creating a program to translate _every_ bril program into C is much more difficult. I tested my code with a simple script, `test.sh` which would run every `.bril` file in `benchmarks`, and compare its output with the translated, compiled, and run code from `Bril2C`. Many times, I thought I had completed my project, only to discover a Bril program that broke my seemingly correct implementation, such as by naming a register the same name as a function, or by using the same register with two different types in two different functions. I did manage to resist the temptation of simply declaring that I would only consider a subset of Bril programs with "nice" formatting, however, and powered on, handling edge case after edge case. After enough bug-fixing, however, I was able to successfully produce a correct program for every single Bril program in the benchmark (as shown in `test_results.txt`).
Copy link
Owner

Choose a reason for hiding this comment

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

Cool! Can you add a link to that results file, test_results.txt?

Mahmoud is an MEng student enrolled in CS6120 as of Spring 2025.
"""
[[extra.authors]]
name = "Mahmoud Elsharawy Sampson"
Copy link
Owner

Choose a reason for hiding this comment

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

Do you have a secret last name?

@mse63
Copy link
Contributor Author

mse63 commented May 15, 2025

I just pushed a new commit to fix the issues.
I can add bril2c to the monorepo, if you think it'll be useful. What directory should I put it under?

@mse63 mse63 requested a review from sampsyo May 15, 2025 18:23
@sampsyo
Copy link
Owner

sampsyo commented May 15, 2025

Looks great; thanks!

Why don't we start with a top-level bril2c directory and see how well that works?

@sampsyo sampsyo merged commit 8d65e52 into sampsyo:2025sp May 15, 2025
2 checks passed
@sampsyo sampsyo added the 2025sp label May 16, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Project Proposal: Bril2C

2 participants