Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rs2bril #227

Merged
merged 4 commits into from
Jul 22, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/rust.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ jobs:
runs-on: ubuntu-latest
strategy:
matrix:
path: ["brilirs/Cargo.toml", "bril-rs/Cargo.toml", "bril-rs/bril2json/Cargo.toml", "bril-rs/brild/Cargo.toml", "brilift/Cargo.toml"]
path: ["brilirs/Cargo.toml", "bril-rs/Cargo.toml", "bril-rs/bril2json/Cargo.toml", "bril-rs/brild/Cargo.toml", "brilift/Cargo.toml", "bril-rs/rs2bril/Cargo.toml"]
steps:
- uses: actions/checkout@v2
- uses: actions-rs/toolchain@v1
Expand Down
4 changes: 2 additions & 2 deletions bril-rs/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,10 +33,10 @@ path = "examples/bril2txt.rs"
# However this currently does not work as expected and is being hashed out in https://github.com/rust-lang/rfcs/pull/3020 and https://github.com/rust-lang/rfcs/pull/2887
# Until a solution is reached, I'm using `required-features` so that these features must be passed by flag. This is less ergonomic at the moment, however the user will get a nicer error that they need a feature flag instead of an Result::unwrap() error.
# Note: See dev-dependencies for a hack to not need the user to pass that feature flag.
required-features = ["memory", "float", "ssa", "speculate", "position"]
required-features = ["memory", "float", "ssa", "speculate", "position", "import"]

[dev-dependencies]
# trick to enable all features in test
# This is actually really hacky because it is used in all tests/examples/benchmarks but since we currently only have one example this works for enabling the following feature flags for our users.
# If the above rfcs every get resolved, then dev-dependencies will no longer be needed.
bril-rs = { path = ".", features = ["memory", "float", "ssa", "speculate", "position"] }
bril-rs = { path = ".", features = ["memory", "float", "ssa", "speculate", "position", "import"] }
4 changes: 3 additions & 1 deletion bril-rs/Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
TESTS := ../test/print/*.json \
../test/parse/*.bril \
../test/linking/*.bril
../test/linking/*.bril \
../test/rs/*.rs

.PHONY: test
test:
Expand All @@ -11,6 +12,7 @@ install:
cargo install --path . --example bril2txt
cargo install --path ./bril2json
cargo install --path ./brild
cargo install --path ./rs2bril

# As more features are added it can be difficult to know if any of them conflict or haven't been appropriately guarded. This command runs cargo check with all possible combinations of feature flags to catch any breakages. Normally you would have to be careful of 2^N explosion but bril-rs builds so fast that this is currently not an issue.
# cargo install cargo-hack
Expand Down
24 changes: 24 additions & 0 deletions bril-rs/rs2bril/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
[package]
name = "rs2bril"
version = "0.1.0"
authors = ["Patrick LaFontaine <[email protected]>"]
edition = "2021"
description = "A compiler for Rust into Bril"
readme = "README.md"
repository = "https://github.com/sampsyo/bril"
# license = "MIT"
license-file = "../../LICENSE"
categories = ["command-line-utilities", "compilers"]
keywords = ["compiler", "bril", "parser", "data-structures", "language"]

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]
syn = {version = "1.0", features = ["full", "extra-traits"]}
proc-macro2 = {version = "1.0", features = ["span-locations"]}
clap = { version = "3.2", features = ["derive"] }

[dependencies.bril-rs]
version = "0.1.0"
path = ".."
features = [ "memory", "float", "position"]
19 changes: 19 additions & 0 deletions bril-rs/rs2bril/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# rs2bril

This project is a Rust version of the `ts2bril` tool. `rs2bril` compiles a subset of Rust to Bril. See the test cases or `example.rs` for the subset of supported syntax. The goal is to support core bril operations like integer arithmetic/comparisons, function calls, control flow like if/while, and printing. It will additionally support floating point operations like those in Bril and memory operations via Rust arrays/slices.

View the interface with `cargo doc --open` or install with `make install` using the Makefile in `bril/bril_rs`. Then use `rs2bril --help` to get the help page for `rs2bril` with all of the supported flags.

## Limitations

- Currently types are not inferred for variable declarations so all let bindings must be explicitly annotated: `let x:i64 = 5;`
- The `println!` macro is special cased to be converted into a `print` call in Bril. It takes a valid `println!` call, ignores the first argument which it assumes to be a format string, and assumes all of the following comma separated arguments are variables: `println!("this is ignored{}", these, must, be, variables);`
- There currently isn't a way to pass arguments to the main function that is also valid Rust. You can either declare arguments in the main function such that it is no longer valid Rust but will generate the correct Bril code, or declared them as const values in the first line and edit the Bril IR later: `fn main(a:i64) {}` or `fn main() {let a:i64 = 0;}`
- Automatic static memory management <https://www.cs.cornell.edu/courses/cs6120/2020fa/blog/asmm/> has not been implemented so arrays must be explicitly dropped where `drop` is specialized to translate to a call to free: `drop([0]);`
- For loops, `continue`, `break`, and ranges have not been implemented(but could be).
- Memory is implemented using Rust arrays. These are statically sized values unlike how calls to Bril `alloc` can be dynamically sized. One solution is to just allocate a large enough array and then treat the dynamic size like the length.(A subset of vectors could also be specialized in the future).
- In normal Rust, `if` can also be used as an expression which evaluates a value to be put in a variable. This is not implemented and it is assumed that there will only be if statements.
- The Bril code that is produces is super inefficient and it is left to other tools to optimize it. Array initialization is unrolled is not an optimal solution.
- `!=` and automatic promotions of integer literals to floats are not implemented.
- to support indexing into arrays, you can cast to usize in the Rust code. This will be ignored when generating Bril. `arr[i as usize];`
- The parts of Rust which make it valid like lifetimes, references, mutability, and function visibility are ignored and compiled away in Bril.
42 changes: 42 additions & 0 deletions bril-rs/rs2bril/example.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
fn test(x: i64, f: f64, b: bool, ptr: [i64; 2], ptr2: &[[i64; 2]]) -> i64 {
let x: i64 = -1;
let y: bool = !(!true);
let z: f64 = -0.0;
z = -1.0;
f = 5.0;
f /= 2.0;
ptr[0] = 1;
ptr[1] = ptr[2 + x];

let foo : i64 = test2(1, 2);
test3();

let test: [i64;2] = [0, 1];
let test2: [[i64; 2]; 1] = [test];
let test3: [f64;10] = [z; 10];

if true {
let cond: i64 = 0;
while cond < 2 {
cond += 1;
}
} else {
if true {
let cond: bool = false;
while cond {}
}
}

println!("{}", x);

return x;
}


fn test2(x:i64, y:i64) -> i64 {
return x;
}

fn test3() {
return;
}
9 changes: 9 additions & 0 deletions bril-rs/rs2bril/src/cli.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
use clap::Parser;

#[derive(Parser)]
#[clap(about, version, author)] // keeps the cli synced with Cargo.toml
pub struct Cli {
/// Flag for whether position information should be included
#[clap(short, action)]
pub position: bool,
}
Loading