Skip to content

Commit

Permalink
Merge pull request #227 from Pat-Lafon/rs2bril
Browse files Browse the repository at this point in the history
Rs2bril
  • Loading branch information
sampsyo authored Jul 22, 2022
2 parents 9e443c2 + 69a8ffa commit 8383f6b
Show file tree
Hide file tree
Showing 31 changed files with 1,474 additions and 4 deletions.
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

0 comments on commit 8383f6b

Please sign in to comment.