Skip to content
Snippets Groups Projects
Commit ef5ac0b5 authored by rarbore2's avatar rarbore2
Browse files

Merge branch 'interpreter' into 'main'

interpreter

See merge request !30
parents bf1b9c90 3471b7f9
No related branches found
No related tags found
1 merge request!30interpreter
Showing
with 2180 additions and 678 deletions
...@@ -7,3 +7,4 @@ ...@@ -7,3 +7,4 @@
*.o *.o
*.hbin *.hbin
.*.swp .*.swp
.vscode
\ No newline at end of file
This diff is collapsed.
...@@ -6,11 +6,14 @@ members = [ ...@@ -6,11 +6,14 @@ members = [
"hercules_rt", "hercules_rt",
"hercules_rt_proc", "hercules_rt_proc",
"hercules_test/hercules_interpreter",
"hercules_test/hercules_tests",
"hercules_tools/hercules_driver", "hercules_tools/hercules_driver",
"hercules_tools/hercules_hbin_dump", "hercules_tools/hercules_hbin_dump",
"juno_frontend", "juno_frontend",
"hercules_samples/matmul", #"hercules_samples/matmul",
"hercules_samples/task_parallel" #"hercules_samples/task_parallel"
] ]
fn myfunc(x: i32) -> i32
y = call(add, x, x)
r = return(start, y)
fn add(x: i32, y: i32) -> i32
w = add(x, y)
r = return(start, w)
\ No newline at end of file
[package]
name = "hercules_interpreter"
version = "0.1.0"
edition = "2021"
[dependencies]
bitvec = "*"
clap = { version = "*", features = ["derive"] }
rand = "*"
hercules_ir = { path = "../../hercules_ir" }
hercules_opt = { path = "../../hercules_opt" }
itertools = "*"
ordered-float = "*"
derive_more = {version = "*", features = ["from"]}
\ No newline at end of file
This diff is collapsed.
pub mod interpreter;
pub mod value;
use std::fs::File;
use hercules_ir::Module;
use hercules_ir::TypeID;
pub use crate::interpreter::*;
pub use crate::value::*;
// Get a vec of
pub fn into_interp_val(module: &Module, wrapper: InterpreterWrapper, target_ty_id: TypeID) -> InterpreterVal
{
match wrapper {
InterpreterWrapper::Boolean(v) => InterpreterVal::Boolean(v),
InterpreterWrapper::Integer8(v) => InterpreterVal::Integer8(v),
InterpreterWrapper::Integer16(v) => InterpreterVal::Integer16(v),
InterpreterWrapper::Integer32(v) => InterpreterVal::Integer32(v),
InterpreterWrapper::Integer64(v) => InterpreterVal::Integer64(v),
InterpreterWrapper::UnsignedInteger8(v) => InterpreterVal::UnsignedInteger8(v),
InterpreterWrapper::UnsignedInteger16(v) => InterpreterVal::UnsignedInteger16(v),
InterpreterWrapper::UnsignedInteger32(v) => InterpreterVal::UnsignedInteger32(v),
InterpreterWrapper::UnsignedInteger64(v) => InterpreterVal::UnsignedInteger64(v),
InterpreterWrapper::Float32(v) => InterpreterVal::Float32(v),
InterpreterWrapper::Float64(v) => InterpreterVal::Float64(v),
InterpreterWrapper::Product(_) => todo!(),
InterpreterWrapper::Summation(_, _) => todo!(),
InterpreterWrapper::Array(array) => {
let ty = &module.types[target_ty_id.idx()];
let ele_type = ty.try_element_type().expect("PANIC: Type ID");
// unwrap -> map to rust type, check
let mut values = vec![];
for i in 0..array.len() {
values.push(into_interp_val(module, array[i].clone(), TypeID::new(0)));
}
InterpreterVal::Array(target_ty_id, values.into_boxed_slice())
}
}
}
pub fn array_from_interp_val<T: Clone>(module: &Module, interp_val: InterpreterVal) -> Vec<T>
where value::InterpreterVal: Into<T>
{
vec![]
}
// Recursively turns rt args into interpreter wrappers.
#[macro_export]
macro_rules! parse_rt_args {
($arg:expr) => {
{
let mut values: Vec<InterpreterWrapper> = vec![];
values.push(($arg).into());
values
}
};
( $arg:expr, $($tail_args:expr), +) => {
{
let mut values: Vec<InterpreterWrapper> = vec![];
values.push($arg.into());
let mut recurse = parse_rt_args!($($tail_args), +); // How do you pass the rest?
values.append(&mut recurse);
values
}
};
}
pub fn parse_file(path: &str) -> Module {
let mut file = File::open(path).expect("PANIC: Unable to open input file.");
let mut contents = String::new();
std::io::Read::read_to_string(&mut file, &mut contents)
.expect("PANIC: Unable to read input file contents.");
let module =
hercules_ir::parse::parse(&contents).expect("PANIC: Failed to parse Hercules IR file.");
module
}
#[macro_export]
macro_rules! interp_module {
($module:ident, $dynamic_constants:expr, $($args:expr), *) => {
{
//let hir_file = String::from($path);
let wrappers = parse_rt_args!( $($args), *);
let dynamic_constants: Vec<usize> = $dynamic_constants.into();
let module = $module.clone(); //parse_file(hir_file);
let mut pm = hercules_opt::pass::PassManager::new(module);
pm.add_pass(hercules_opt::pass::Pass::Verify);
pm.run_passes();
pm.make_reverse_postorders();
pm.make_doms();
pm.make_fork_join_maps();
pm.make_fork_join_nests();
pm.make_control_subgraphs();
pm.make_plans();
let reverse_postorders = pm.reverse_postorders.as_ref().unwrap().clone();
let doms = pm.doms.as_ref().unwrap().clone();
let fork_join_maps = pm.fork_join_maps.as_ref().unwrap().clone();
let fork_join_nests = pm.fork_join_nests.as_ref().unwrap().clone();
let plans = pm.plans.as_ref().unwrap().clone();
let control_subgraphs = pm.control_subgraphs.as_ref().unwrap().clone();
let def_uses = pm.def_uses.as_ref().unwrap().clone();
let module = pm.get_module();
let mut function_contexts = vec![];
for idx in 0..module.functions.len() {
let context = FunctionContext::new(
&control_subgraphs[idx],
&def_uses[idx],
&fork_join_maps[idx],
&fork_join_nests[idx],
);
function_contexts.push(context);
}
let function_number = 0;
let parameter_types = &module.functions[function_number].param_types;
let args = wrappers.into_iter().enumerate().map(|(idx, val)| {into_interp_val(&module, val, parameter_types[idx])}).collect();
let mut state = FunctionExecutionState::new(
args,
&module,
hercules_ir::FunctionID::new(function_number),
&function_contexts,
dynamic_constants,
);
state.run()
}
};
}
#[macro_export]
macro_rules! interp_file_with_passes {
($path:literal, $dynamic_constants:expr, $passes:expr, $($args:expr), *) => {
{
let module = parse_file($path);
let result_before = interp_module!(module, $dynamic_constants, $($args), *);
let mut pm = hercules_opt::pass::PassManager::new(module.clone());
for pass in $passes {
pm.add_pass(pass);
}
pm.run_passes();
let module = pm.get_module();
let result_after = interp_module!(module, $dynamic_constants, $($args), *);
assert_eq!(result_after, result_before);
}
};
}
\ No newline at end of file
extern crate clap;
extern crate hercules_ir;
extern crate hercules_opt;
extern crate rand;
use hercules_interpreter::interpreter::*;
use hercules_interpreter::*;
use hercules_interpreter::value;
use std::fs::File;
use std::io::prelude::*;
use self::hercules_ir::*;
use clap::Parser;
#[derive(Parser, Debug)]
#[command(author, version, about, long_about = None)]
struct Args {
hir_file: String,
#[arg(short, long, default_value_t = String::new())]
output: String,
}
fn main() {
let args = Args::parse();
let module = parse_file(&args.hir_file);
let ret_val = interp_module!(module, [2, 3, 4], 1, 3);
println!("ret val: {:?}", ret_val);
}
This diff is collapsed.
[package]
name = "hercules_tests"
version = "0.1.0"
edition = "2021"
[dependencies]
bitvec = "*"
clap = { version = "*", features = ["derive"] }
rand = "*"
hercules_ir = { path = "../../hercules_ir" }
hercules_opt = { path = "../../hercules_opt" }
hercules_interpreter = { path = "../hercules_interpreter" }
itertools = "*"
ordered-float = "*"
use std::env;
use hercules_interpreter::*;
use hercules_opt::pass::Pass;
extern crate rand;
use rand::Rng;
#[test]
fn matmul_int() {
let module = parse_file("../test_inputs/matmul_int.hir");
let dyn_consts = [2, 2, 2];
let m1 = vec![3, 4, 5, 6];
let m2 = vec![7, 8, 9, 10];
let result_1 = interp_module!(module, dyn_consts, m1.clone(), m2.clone());
let mut pm = hercules_opt::pass::PassManager::new(module.clone());
let passes = vec![
Pass::Verify,
Pass::CCP,
Pass::DCE,
Pass::GVN,
Pass::DCE,
Pass::Forkify,
Pass::DCE,
Pass::Predication,
Pass::DCE,
];
for pass in passes {
pm.add_pass(pass);
}
pm.run_passes();
let module = pm.get_module();
let result_2 = interp_module!(module, dyn_consts, m1, m2);
assert_eq!(result_1, result_2)
}
#[test]
fn ccp_example() {
let module = parse_file("../test_inputs/ccp_example.hir");
let dyn_consts = [];
let x = 34;
let result_1 = interp_module!(module, dyn_consts, x);
let mut pm = hercules_opt::pass::PassManager::new(module.clone());
let passes = vec![
Pass::Verify,
Pass::CCP,
Pass::DCE,
Pass::GVN,
Pass::DCE,
Pass::Forkify,
Pass::DCE,
Pass::Predication,
Pass::DCE,
];
for pass in passes {
pm.add_pass(pass);
}
pm.run_passes();
let module = pm.get_module();
let result_2 = interp_module!(module, dyn_consts, x);
assert_eq!(result_1, result_2)
}
#[test]
fn gvn_example() {
let module = parse_file("../test_inputs/gvn_example.hir");
let dyn_consts = [];
let x: i32 = rand::random();
let x = x / 32;
let y: i32 = rand::random();
let y = y / 32; // prevent overflow,
let result_1 = interp_module!(module, dyn_consts, x, y);
let mut pm = hercules_opt::pass::PassManager::new(module.clone());
let passes = vec![
Pass::Verify,
Pass::CCP,
Pass::DCE,
Pass::GVN,
Pass::DCE,
Pass::Forkify,
Pass::DCE,
Pass::Predication,
Pass::DCE,
];
for pass in passes {
pm.add_pass(pass);
}
pm.run_passes();
let module = pm.get_module();
let result_2 = interp_module!(module, dyn_consts, x, y);
assert_eq!(result_1, result_2)
}
#[test]
fn sum_int() {
let module = parse_file("../test_inputs/sum_int1.hir");
let size = 100;
let dyn_consts = [size];
let mut vec = vec![0; size];
let mut rng = rand::thread_rng();
for x in vec.iter_mut() {
*x = rng.gen::<i32>() / 100;
}
let result_1 = interp_module!(module, dyn_consts, vec.clone());
let mut pm = hercules_opt::pass::PassManager::new(module.clone());
let passes = vec![
Pass::Verify,
Pass::CCP,
Pass::DCE,
Pass::GVN,
Pass::DCE,
Pass::Forkify,
Pass::DCE,
Pass::Predication,
Pass::DCE,
];
for pass in passes {
pm.add_pass(pass);
}
pm.run_passes();
let module = pm.get_module();
let result_2 = interp_module!(module, dyn_consts, vec);
assert_eq!(result_1, result_2)
}
#[test]
fn sum_int2() {
let module = parse_file("../test_inputs/sum_int2.hir");
let size = 100;
let dyn_consts = [size];
let mut vec = vec![0; size];
let mut rng = rand::thread_rng();
for x in vec.iter_mut() {
*x = rng.gen::<i32>() / 100;
}
let result_1 = interp_module!(module, dyn_consts, vec.clone());
let mut pm = hercules_opt::pass::PassManager::new(module.clone());
let passes = vec![
Pass::Verify,
Pass::CCP,
Pass::DCE,
Pass::GVN,
Pass::DCE,
Pass::Forkify,
Pass::DCE,
Pass::Predication,
Pass::DCE,
];
for pass in passes {
pm.add_pass(pass);
}
pm.run_passes();
let module = pm.get_module();
let result_2 = interp_module!(module, dyn_consts, vec);
assert_eq!(result_1, result_2)
}
#[test]
fn sum_int2_smaller() {
interp_file_with_passes!("../test_inputs/sum_int2.hir",
[100],
vec![
Pass::Verify,
Pass::CCP,
Pass::DCE,
Pass::GVN,
Pass::DCE,
Pass::Forkify,
Pass::DCE,
Pass::Predication,
Pass::DCE,
],
vec![1; 100]);
}
\ No newline at end of file
fn myfunc(x: i32) -> i32
y = call(add, x, x)
r = return(start, y)
fn add(x: i32, y: i32) -> i32
w = add(x, y)
r = return(start, w)
\ No newline at end of file
fn myfunc(x: u64) -> u64
y = call<10, 4>(add, x, x)
r = return(start, y)
fn add<2>(x: u64, y: u64) -> u64
b = dynamic_constant(#1)
r = return(start, z)
w = add(x, y)
z = add(b, w)
\ No newline at end of file
fn tricky(x: i32) -> i32
one = constant(i32, 1)
two = constant(i32, 2)
loop = region(start, if2_true)
idx = phi(loop, x, idx_dec)
val = phi(loop, one, later_val)
b = ne(one, val)
if1 = if(loop, b)
if1_false = projection(if1, 0)
if1_true = projection(if1, 1)
middle = region(if1_false, if1_true)
inter_val = sub(two, val)
later_val = phi(middle, inter_val, two)
idx_dec = sub(idx, one)
cond = gte(idx_dec, one)
if2 = if(middle, cond)
if2_false = projection(if2, 0)
if2_true = projection(if2, 1)
r = return(if2_false, later_val)
fn fork_join<1>() -> u64
f_ctrl = fork(start, #0)
j_ctrl = join(f_ctrl)
zero = constant(u64, 0)
x = thread_id(f_ctrl)
data = reduce(j_ctrl, zero, sum)
sum = add(data, x)
r = return(j_ctrl, data)
fn tricky(x: i32, y: i32) -> i32
zero = constant(i32, 0)
xx = add(x, zero)
a = add(xx, y)
b = add(x, y)
bb = add(zero, b)
c = add(a, bb)
r = return(start, c)
fn matmul<3>(a: array(f32, #0, #1), b: array(f32, #1, #2)) -> array(f32, #0, #2)
c = constant(array(f32, #0, #2), zero)
i_ctrl = fork(start, #0)
i_idx = thread_id(i_ctrl)
j_ctrl = fork(i_ctrl, #2)
j_idx = thread_id(j_ctrl)
k_ctrl = fork(j_ctrl, #1)
k_idx = thread_id(k_ctrl)
k_join_ctrl = join(k_ctrl)
j_join_ctrl = join(k_join_ctrl)
i_join_ctrl = join(j_join_ctrl)
r = return(i_join_ctrl, update_i_c)
zero = constant(f32, 0)
a_val = read(a, position(i_idx, k_idx))
b_val = read(b, position(k_idx, j_idx))
mul = mul(a_val, b_val)
add = add(mul, dot)
dot = reduce(k_join_ctrl, zero, add)
updated_c = write(update_j_c, dot, position(i_idx, j_idx))
update_j_c = reduce(j_join_ctrl, update_i_c, updated_c)
update_i_c = reduce(i_join_ctrl, c, update_j_c)
fn matmul<3>(a: array(i32, #0, #1), b: array(i32, #1, #2)) -> array(i32, #0, #2)
c = constant(array(i32, #0, #2), [])
i_ctrl = fork(start, #0)
i_idx = thread_id(i_ctrl)
j_ctrl = fork(i_ctrl, #2)
j_idx = thread_id(j_ctrl)
k_ctrl = fork(j_ctrl, #1)
k_idx = thread_id(k_ctrl)
k_join_ctrl = join(k_ctrl)
j_join_ctrl = join(k_join_ctrl)
i_join_ctrl = join(j_join_ctrl)
r = return(i_join_ctrl, update_i_c)
zero = constant(i32, 0)
a_val = read(a, position(i_idx, k_idx))
b_val = read(b, position(k_idx, j_idx))
mul = mul(a_val, b_val)
add = add(mul, dot)
dot = reduce(k_join_ctrl, zero, add)
updated_c = write(update_j_c, dot, position(i_idx, j_idx))
update_j_c = reduce(j_join_ctrl, update_i_c, updated_c)
update_i_c = reduce(i_join_ctrl, c, update_j_c)
fn simple1(a: i32, b: i32) -> i32
c = add(a, b)
r = return(start, c)
fn simple2(x: i32) -> i32
zero = constant(i32, 0)
one = constant(i32, 1)
loop = region(start, if_true)
idx = phi(loop, zero, idx_inc)
idx_inc = add(idx, one)
fac = phi(loop, one, fac_acc)
fac_acc = mul(fac, idx_inc)
in_bounds = lt(idx_inc, x)
if = if(loop, in_bounds)
if_false = projection(if, 0)
if_true = projection(if, 1)
r = return(if_false, fac_acc)
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment