-
Notifications
You must be signed in to change notification settings - Fork 242
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #104 from Pat-Lafon/brilirs-extensions
Everything but spec and benchmarks
- Loading branch information
Showing
14 changed files
with
643 additions
and
389 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,3 +7,4 @@ yarn.lock | |
.pytest_cache/ | ||
hypothesis_* | ||
__pycache__ | ||
.vscode |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
command = "bril2json < {filename} | cargo run --manifest-path ../../brilirs/Cargo.toml -- -p {args}" | ||
output.out = "-" | ||
output.prof = "2" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
TESTS := ../test/interp/*.bril \ | ||
../test/mem/*.bril \ | ||
../test/fail/*.bril \ | ||
../benchmarks/*.bril | ||
|
||
.PHONY: test | ||
test: | ||
turnt -c turnt_brilirs.toml $(TESTS) | ||
|
||
.PHONY: example | ||
example: | ||
bril2json < ../test/interp/call-with-args.bril | cargo run -- |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,136 +1,141 @@ | ||
use bril_rs::{Function, Program}; | ||
use std::collections::HashMap; | ||
|
||
pub struct Function { | ||
// A program represented as basic blocks. | ||
pub struct BBProgram { | ||
pub func_index: HashMap<String, BBFunction>, | ||
} | ||
|
||
impl BBProgram { | ||
pub fn new(prog: Program) -> BBProgram { | ||
BBProgram { | ||
func_index: prog | ||
.functions | ||
.into_iter() | ||
.map(|func| (func.name.clone(), BBFunction::new(func))) | ||
.collect(), | ||
} | ||
} | ||
|
||
pub fn get(&self, func_name: &str) -> Option<&BBFunction> { | ||
self.func_index.get(func_name) | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct BasicBlock { | ||
pub label: Option<String>, | ||
pub instrs: Vec<bril_rs::Instruction>, | ||
pub exit: Vec<usize>, | ||
} | ||
|
||
impl BasicBlock { | ||
fn new() -> BasicBlock { | ||
BasicBlock { | ||
label: None, | ||
instrs: Vec::new(), | ||
exit: Vec::new(), | ||
} | ||
} | ||
} | ||
|
||
pub struct BBFunction { | ||
pub name: String, | ||
pub args: Vec<bril_rs::Argument>, | ||
pub return_type: Option<bril_rs::Type>, | ||
pub blocks: Vec<BasicBlock>, | ||
|
||
// Map from label to the index of the block that is the target of the label. | ||
pub label_index: HashMap<String, usize>, | ||
pub label_map: HashMap<String, usize>, | ||
} | ||
|
||
impl Function { | ||
pub fn new(f: bril_rs::Function) -> Function { | ||
let mut func = Function { | ||
args: f.args.clone(), | ||
return_type: f.return_type.clone(), | ||
blocks: vec![], | ||
label_index: HashMap::new(), | ||
}; | ||
func.add_blocks(f.instrs); | ||
impl BBFunction { | ||
pub fn new(f: Function) -> BBFunction { | ||
let mut func = BBFunction::find_basic_blocks(f); | ||
func.build_cfg(); | ||
func | ||
} | ||
|
||
fn build_cfg(&mut self) { | ||
let last_idx = self.blocks.len() - 1; | ||
for (i, block) in self.blocks.iter_mut().enumerate() { | ||
// If we're before the last block | ||
if i < last_idx { | ||
// Get the last instruction | ||
let last_instr: &bril_rs::Code = block.instrs.last().unwrap(); | ||
if let bril_rs::Code::Instruction(bril_rs::Instruction::Effect { op, labels, .. }) = | ||
last_instr | ||
{ | ||
if let bril_rs::EffectOps::Jump | bril_rs::EffectOps::Branch = op { | ||
for l in labels { | ||
block.exit.push( | ||
*self | ||
.label_index | ||
.get(l) | ||
.expect(&format!("No label {} found.", &l)), | ||
); | ||
} | ||
} | ||
} else { | ||
block.exit.push(i + 1); | ||
} | ||
} | ||
} | ||
} | ||
fn find_basic_blocks(func: bril_rs::Function) -> BBFunction { | ||
let mut blocks = Vec::new(); | ||
let mut label_map = HashMap::new(); | ||
|
||
fn add_blocks(&mut self, instrs: Vec<bril_rs::Code>) { | ||
let mut curr_block = BasicBlock::new(); | ||
let mut curr_label = None; | ||
for instr in instrs { | ||
for instr in func.instrs.into_iter() { | ||
match instr { | ||
bril_rs::Code::Label { ref label } => { | ||
if !curr_block.instrs.is_empty() { | ||
self.blocks.push(curr_block); | ||
if let Some(old_label) = curr_label { | ||
self.label_index.insert(old_label, self.blocks.len() - 1); | ||
if let Some(old_label) = curr_block.label.as_ref() { | ||
label_map.insert(old_label.to_string(), blocks.len()); | ||
} | ||
blocks.push(curr_block); | ||
curr_block = BasicBlock::new(); | ||
} | ||
curr_label = Some(label.clone()); | ||
curr_block.label = Some(label.clone()); | ||
} | ||
bril_rs::Code::Instruction(bril_rs::Instruction::Effect { op, .. }) | ||
if op == bril_rs::EffectOps::Jump | ||
|| op == bril_rs::EffectOps::Branch | ||
|| op == bril_rs::EffectOps::Return => | ||
bril_rs::Code::Instruction(bril_rs::Instruction::Effect { | ||
op, | ||
args, | ||
funcs, | ||
labels, | ||
}) if op == bril_rs::EffectOps::Jump | ||
|| op == bril_rs::EffectOps::Branch | ||
|| op == bril_rs::EffectOps::Return => | ||
{ | ||
curr_block.instrs.push(instr); | ||
self.blocks.push(curr_block); | ||
if let Some(l) = curr_label { | ||
self.label_index.insert(l, self.blocks.len() - 1); | ||
curr_label = None; | ||
curr_block.instrs.push(bril_rs::Instruction::Effect { | ||
op, | ||
args, | ||
funcs, | ||
labels, | ||
}); | ||
if let Some(l) = curr_block.label.as_ref() { | ||
label_map.insert(l.to_string(), blocks.len()); | ||
} | ||
blocks.push(curr_block); | ||
curr_block = BasicBlock::new(); | ||
} | ||
_ => { | ||
curr_block.instrs.push(instr); | ||
bril_rs::Code::Instruction(code) => { | ||
curr_block.instrs.push(code); | ||
} | ||
} | ||
} | ||
|
||
if !curr_block.instrs.is_empty() { | ||
// If we are here, the function ends without an explicit ret. To make | ||
// processing easier, push a Return op onto the last block. | ||
curr_block.instrs.push(RET.clone()); | ||
self.blocks.push(curr_block); | ||
if let Some(l) = curr_label { | ||
self.label_index.insert(l, self.blocks.len() - 1); | ||
if let Some(l) = curr_block.label.as_ref() { | ||
label_map.insert(l.to_string(), blocks.len()); | ||
} | ||
blocks.push(curr_block); | ||
} | ||
} | ||
} | ||
|
||
// A program represented as basic blocks. | ||
pub struct BBProgram { | ||
pub func_index: HashMap<String, Function>, | ||
} | ||
|
||
impl BBProgram { | ||
pub fn new(prog: bril_rs::Program) -> BBProgram { | ||
let mut bbprog = BBProgram { | ||
func_index: HashMap::new(), | ||
}; | ||
for func in prog.functions { | ||
bbprog | ||
.func_index | ||
.insert(func.name.clone(), Function::new(func)); | ||
BBFunction { | ||
name: func.name, | ||
args: func.args, | ||
return_type: func.return_type, | ||
blocks, | ||
label_map, | ||
} | ||
bbprog | ||
} | ||
} | ||
|
||
#[derive(Debug)] | ||
pub struct BasicBlock { | ||
pub instrs: Vec<bril_rs::Code>, | ||
pub exit: Vec<usize>, | ||
} | ||
|
||
impl BasicBlock { | ||
fn new() -> BasicBlock { | ||
BasicBlock { | ||
instrs: Vec::new(), | ||
exit: Vec::new(), | ||
fn build_cfg(&mut self) { | ||
let last_idx = self.blocks.len() - 1; | ||
for (i, block) in self.blocks.iter_mut().enumerate() { | ||
// If we're before the last block | ||
if i < last_idx { | ||
// Get the last instruction | ||
if let Some(bril_rs::Instruction::Effect { op, labels, .. }) = block.instrs.last().cloned() | ||
{ | ||
if let bril_rs::EffectOps::Jump | bril_rs::EffectOps::Branch = op { | ||
for l in labels { | ||
block.exit.push( | ||
*self | ||
.label_map | ||
.get(&l) | ||
.unwrap_or_else(|| panic!("No label {} found.", &l)), | ||
); | ||
} | ||
} | ||
} else { | ||
block.exit.push(i + 1); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
const RET: bril_rs::Code = bril_rs::Code::Instruction(bril_rs::Instruction::Effect { | ||
op: bril_rs::EffectOps::Return, | ||
args: vec![], | ||
funcs: vec![], | ||
labels: vec![], | ||
}); |
Oops, something went wrong.