Skip to content

Commit

Permalink
Add structural analysis (#59)
Browse files Browse the repository at this point in the history
* upgrade rust toolchain

* structual analysis

* structural analysis
  • Loading branch information
longfangsong authored Jun 27, 2024
1 parent 2337a51 commit efbac01
Show file tree
Hide file tree
Showing 46 changed files with 1,836 additions and 125 deletions.
61 changes: 33 additions & 28 deletions .github/workflows/deploy-doc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ name: Build and Deploy doc

on:
push:
branches: [ main ]
branches: [main]

env:
CARGO_TERM_COLOR: always
Expand All @@ -24,30 +24,35 @@ jobs:
url: ${{ steps.deployment.outputs.page_url }}
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.3
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Build wasm packages
working-directory: ./crates/control-flow-graph-wasm
run: wasm-pack build --target web --release
- name: Move wasm packages
run: mv -f ./crates/control-flow-graph-wasm/pkg/* ./doc/static/tools/graph-editor/
- name: Build site
run: docker run -u "$(id -u):$(id -g)" -v $PWD/doc:/app --workdir /app ghcr.io/getzola/zola:v0.16.0 build
- name: Build crate doc
run: cargo doc --workspace --document-private-items --all-features -r
- name: Move crate doc
run: sudo mv ./target/doc/* ./doc/public/
- name: Setup Pages
uses: actions/configure-pages@v2
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
with:
path: './doc/public'
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
- uses: actions/checkout@v3
with:
submodules: recursive
- name: Run sccache-cache
uses: mozilla-actions/sccache-action@v0.0.3
- name: Install wasm-pack
run: curl https://rustwasm.github.io/wasm-pack/installer/init.sh -sSf | sh
- name: Build wasm packages
working-directory: ./crates/control-flow-graph-wasm
run: wasm-pack build --target web --release
- name: Build wasm packages
working-directory: ./crates/ir-breadboard
run: wasm-pack build --target web --release
- name: Move wasm packages
run: mv -f ./crates/control-flow-graph-wasm/pkg/* ./doc/static/tools/graph-editor/
- name: Move wasm packages
run: mv -f ./crates/ir-breadboard/pkg/* ./doc/static/tools/ir-breadboard/
- name: Build site
run: docker run -u "$(id -u):$(id -g)" -v $PWD/doc:/app --workdir /app ghcr.io/getzola/zola:v0.16.0 build
- name: Build crate doc
run: cargo doc --workspace --document-private-items --all-features -r
- name: Move crate doc
run: sudo mv ./target/doc/* ./doc/public/
- name: Setup Pages
uses: actions/configure-pages@v2
- name: Upload artifact
uses: actions/upload-pages-artifact@v1
with:
path: "./doc/public"
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v1
13 changes: 8 additions & 5 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,23 +11,23 @@ bitvec = { version = "1.0.1", features = ["serde"] }
clap = { version = "4.4.14", features = ["derive"] }
enum_dispatch = "0.3.12"
indexmap = "2.1.0"
itertools = "0.12.0"
itertools = "0.13.0"
nom = "7.1.3"
paste = "1.0.14"
petgraph = "0.6.4"
petgraph = { version = "0.6.4", features = ["serde-1"] }
phf = { version = "0.11.2", features = ["macros"] }
serde = { version = "1.0.195", features = ["derive"] }
toml = "0.8.8"
shadow-rs = { version = "0.26.0", optional = true }
shadow-rs = { version = "0.28.0", optional = true }
ezio = { version = "0.1.2", optional = true }
delegate = "0.12.0"
wasm-encoder = "0.205.0"
wasm-encoder = "0.209.1"

[dev-dependencies]
cov-mark = "1.1.0"

[build-dependencies]
shadow-rs = "0.26.0"
shadow-rs = "0.28.0"

[lib]
crate-type = ["lib"]
Expand All @@ -54,3 +54,6 @@ required-features = ["build-binary"]
[[bin]]
name = "shuasm"
required-features = ["build-binary"]

[workspace]
members = ["crates/control-flow-graph-wasm", "crates/ir-breadboard"]
17 changes: 17 additions & 0 deletions crates/ir-breadboard/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "ir-breadboard"
version = "0.1.0"
edition = "2021"

[dependencies]
serde = { version = "1.0.203", features = ["derive"] }
serde-wasm-bindgen = "0.6.5"
wasm-bindgen = "0.2.92"
come = { path = "../.." }

[lib]
crate-type = ["cdylib", "rlib"]

[profile.release]
opt-level = "z"
lto = true
161 changes: 161 additions & 0 deletions crates/ir-breadboard/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,161 @@
use std::str::FromStr;

use come::ir::{
self,
analyzer::{self, control_flow::structural::FoldedCFG, ControlFlowGraph, IsAnalyzer},
optimize::{optimize as optimize_ir, pass::Pass},
IR,
};
use wasm_bindgen::prelude::*;

#[wasm_bindgen]
pub fn parse(code: &str) -> JsValue {
let (_, parsed_ir) = ir::parse(code).unwrap();
let result = parsed_ir.as_function_definition();
serde_wasm_bindgen::to_value(&result).unwrap()
}

#[wasm_bindgen]
pub fn optimize(code: &str, pass: &str) -> String {
let ir_code = ir::parse(code).unwrap().1;
let pass = Pass::from_str(pass).unwrap();
let result = optimize_ir(vec![ir_code], vec![pass])
.into_iter()
.next()
.unwrap();
format!("{result}")
}

#[wasm_bindgen]
#[derive(Clone, Debug)]
pub struct Edge {
pub from: u32,
pub to: u32,
pub back: bool,
}

#[wasm_bindgen(getter_with_clone)]
#[derive(Default, Debug)]
pub struct CFGraph {
pub nodes: Vec<String>,
pub edges: Vec<Edge>,
}

#[wasm_bindgen]
pub fn dump_control_flow_graph(code: &str) -> CFGraph {
let ir_code = ir::parse(code).unwrap().1;
if let IR::FunctionDefinition(f) = ir_code {
let cfg = analyzer::ControlFlowGraph::new();
let cfg = cfg.bind(&f);
let backedges = cfg.back_edges();
let mut result = CFGraph::default();
let g = cfg.graph();
for n in g.node_indices() {
if n.index() == g.node_count() - 1 {
result.nodes.push("_dummy_end".to_string());
} else {
result
.nodes
.push(cfg.basic_block_name_by_index(n.index()).to_string());
}
}
for e in g.edge_indices() {
let (from, to) = g.edge_endpoints(e).unwrap();
let is_backedge = backedges.contains(&(from.index() as _, to.index() as _));
result.edges.push(Edge {
from: from.index() as _,
to: to.index() as _,
back: is_backedge,
});
}
result
} else {
panic!("faq")
}
}

#[wasm_bindgen]
pub fn structural_analysis(code: &str) -> JsValue {
let ir_code = ir::parse(code).unwrap().1;
let f = ir_code.as_function_definition();
let cfg = ControlFlowGraph::new();
let cfg = cfg.bind(f);
let folded = FoldedCFG::from_control_flow_graph(&cfg);
let result = folded.structural_analysis(&cfg);
serde_wasm_bindgen::to_value(&result).unwrap()
}

#[test]
fn test_optimize() {
dbg!(optimize(
r"fn main() -> () {
%0 = add i32 1, 2
ret
}",
"FixIrreducible"
));
}

#[test]
fn test_dump_cfg() {
dbg!(dump_control_flow_graph(
r"fn test_condition(i32 %a, i32 %b) -> i32 {
test_condition_entry:
%a_0_addr = alloca i32
store i32 %a, address %a_0_addr
%b_0_addr = alloca i32
store i32 %b, address %b_0_addr
%result_0_addr = alloca i32
store i32 0, address %result_0_addr
%i_0_addr = alloca i32
%0 = load i32 %a_0_addr
store i32 %0, address %i_0_addr
j loop_0_condition
loop_0_condition:
%2 = load i32 %i_0_addr
%3 = load i32 %b_0_addr
%1 = slt i32 %2, %3
bne %1, 0, loop_0_success, loop_0_fail
loop_0_success:
%5 = load i32 %result_0_addr
%6 = load i32 %i_0_addr
%4 = add i32 %5, %6
store i32 %4, address %result_0_addr
%8 = load i32 %i_0_addr
%7 = add i32 %8, 1
store i32 %7, address %i_0_addr
j loop_0_condition
loop_0_fail:
%9 = load i32 %result_0_addr
ret %9
}"
));
}

#[test]
fn test_structural_analysis() {
let code = r"fn test_condition(i32 %a, i32 %b) -> i32 {
test_condition_entry:
%a_0_addr = alloca i32
store i32 %a, address %a_0_addr
%b_0_addr = alloca i32
store i32 %b, address %b_0_addr
%1 = load i32 %a_0_addr
%2 = load i32 %b_0_addr
%0 = slt i32 %1, %2
bne %0, 0, if_0_success, if_0_fail
if_0_success:
%3 = load i32 %a_0_addr
ret %3
if_0_fail:
%4 = load i32 %b_0_addr
ret %4
}";
let ir_code = ir::parse(code).unwrap().1;
let f = ir_code.as_function_definition();
let cfg = ControlFlowGraph::new();
let cfg = cfg.bind(f);
let folded = FoldedCFG::from_control_flow_graph(&cfg);
let result = folded.structural_analysis(&cfg);
dbg!(result);
}
Loading

0 comments on commit efbac01

Please sign in to comment.