Skip to content
Snippets Groups Projects
Commit e6c38c2e authored by Xavier Routh's avatar Xavier Routh
Browse files

restructure directories, more functionality

parent 627a99d7
No related branches found
No related tags found
1 merge request!28Draft: Interpreter, Tests, Debug Info, Misc.
......@@ -367,6 +367,8 @@ dependencies = [
"clap",
"hercules_ir",
"hercules_opt",
"itertools",
"ordered-float",
"rand",
]
......@@ -375,7 +377,6 @@ name = "hercules_ir"
version = "0.1.0"
dependencies = [
"bitvec",
"itertools",
"nom",
"ordered-float",
"rand",
......
......@@ -8,5 +8,4 @@ rand = "*"
nom = "*"
ordered-float = "*"
bitvec = "*"
itertools = "*"
serde = { version = "*", features = ["derive"] }
\ No newline at end of file
......@@ -416,6 +416,7 @@ impl<'a> Builder<'a> {
return_type,
nodes: vec![Node::Start],
num_dynamic_constants,
debug_info: None,
});
Ok((id, NodeID::new(0)))
}
......
extern crate itertools;
use std::convert::TryInto;
use self::itertools::Itertools;
use crate::*;
/* High level design details / discussion for this:
*
* This module includes tools for itnerepreteing. Execution model / flow is based on
* "A Simple Graph-Based Intermediate Representation" Section 3 by Cliff Click.
*
* Eventually we would an *interactive* interpreter. I.e to be able to step forward and backwards
* throughout the IR (idealy visually) and analyze results at certain steps in the computation.
* We can do this w/ a custom implementation of data structure (differential?) or w/ mutating closures.
*
*
*/
/* Hold state for interpreter blah blah */
pub struct IRInterpreter<'a> {
constants: &'a Vec<Constant>,
types: &'a Vec<Type>,
/* For a single function: */
// reverse_postorder: &'a Vec<NodeID>,
}
pub struct FunctionExecutionState<'a> {
control_subgraph: &'a Subgraph,
constants: &'a Vec<Constant>,
types: &'a Vec<Type>,
args: Vec<usize>, // parameters
function: &'a Function,
phi_values: Vec<usize>, // Map phis -> values
def_use: &'a ImmutableDefUseMap,
}
/*
pub struct FunctionResult {
} */
/*
pub struct FunctionContext {
pub(crate) function: &'a Function,
pub(crate) types: &'a Vec<Type>,
pub(crate) constants: &'a Vec<Constant>,
pub(crate) dynamic_constants: &'a Vec<DynamicConstant>,
pub(crate) def_use: &'a ImmutableDefUseMap,
pub(crate) reverse_postorder: &'a Vec<NodeID>,
pub(crate) typing: &'a Vec<TypeID>,
pub(crate) control_subgraph: &'a Subgraph,
pub(crate) fork_join_map: &'a HashMap<NodeID, NodeID>,
pub(crate) fork_join_nest: &'a HashMap<NodeID, Vec<NodeID>>,
pub(crate) antideps: &'a Vec<(NodeID, NodeID)>,
pub(crate) bbs: &'a Vec<NodeID>,
} */
impl<'a> FunctionExecutionState<'a> {
pub fn new(args: Vec<usize>, control_subgraph: &'a Subgraph, module: &'a Module, def_use: &'a ImmutableDefUseMap, function: &'a Function) -> Self {
debug_assert_eq!(args.len(), function.param_types.len());
FunctionExecutionState {
control_subgraph,
constants: &module.constants,
types: &module.types,
function,
phi_values: vec![0; function.nodes.len()], // Sprase slotmap
args,
def_use,
}
}
pub fn handle_region(&mut self, prev: NodeID, node: NodeID, preds: &Box<[NodeID]>) -> NodeID {
// Gather PHI nodes for this region node.
let phis: Vec<NodeID> = self.def_use.get_users(node).into_iter().filter_map(
|n| {
if self.function.nodes[n.idx()].is_phi() {
Some(*n)
}
else {
None
}
}).collect();
// Latch their values at this point.
for phi in phis {
self.phi_values[phi.idx()] = self.handle_data(phi);
}
// Return the (single) control successor of the region node
self.control_subgraph.succs(node).next().unwrap()
}
// FIXME: Need to return data of the correct type?
pub fn handle_data(&self, node: NodeID) -> usize {
match &self.function.nodes[node.idx()] {
Node::Phi { control, data } => todo!(),
Node::ThreadID { control } => todo!(),
Node::Reduce { control, init, reduct } => todo!(),
Node::Parameter { index } => {
self.args[*index]
}
Node::Constant { id } => {
match self.constants[id.idx()] {
Constant::Boolean(v) => v.try_into().unwrap(),
Constant::Integer8(v) => v.try_into().unwrap(),
Constant::Integer16(v) => v.try_into().unwrap(),
Constant::Integer32(v) => v.try_into().unwrap(),
Constant::Integer64(v) => v.try_into().unwrap(),
Constant::UnsignedInteger8(v) => v.try_into().unwrap(),
Constant::UnsignedInteger16(v) => v.try_into().unwrap(),
Constant::UnsignedInteger32(v) => v.try_into().unwrap(),
Constant::UnsignedInteger64(v) => v.try_into().unwrap(),
// What in the world do we do here: (do we have to cast)
Constant::Zero(_) => 0,
Constant::Float32(_) => todo!(),
Constant::Float64(_) => todo!(),
Constant::Product(_, _) => todo!(),
Constant::Summation(_, _, _) => todo!(),
Constant::Array(_, _) => todo!(),
}
}
Node::DynamicConstant { id } => todo!(),
Node::Unary { input, op } => todo!(),
Node::Binary { left, right, op } => {
let left = self.handle_data(*left);
let right = self.handle_data(*right);
match op {
BinaryOperator::Add => left + right,
BinaryOperator::Sub => todo!(),
BinaryOperator::Mul => todo!(),
BinaryOperator::Div => todo!(),
BinaryOperator::Rem => todo!(),
BinaryOperator::LT => todo!(),
BinaryOperator::LTE => todo!(),
BinaryOperator::GT => todo!(),
BinaryOperator::GTE => todo!(),
BinaryOperator::EQ => todo!(),
BinaryOperator::NE => todo!(),
BinaryOperator::Or => todo!(),
BinaryOperator::And => todo!(),
BinaryOperator::Xor => todo!(),
BinaryOperator::LSh => todo!(),
BinaryOperator::RSh => todo!(),
}
}
Node::Ternary { first, second, third, op } => todo!(),
Node::Call { function, dynamic_constants, args } => todo!(),
Node::Read { collect, indices } => todo!(),
Node::Write { collect, data, indices } => todo!(),
_ => todo!()
}
}
pub fn run(&mut self) -> () {
let mut ctrl_token: NodeID = NodeID::new(
self.function
.nodes
.iter()
.find_position(|node| node.is_start())
.expect("PANIC: no start node")
.0,
);
let prev = ctrl_token;
loop {
ctrl_token = match &self.function.nodes[ctrl_token.idx()] {
Node::Start => {
println!("{:?}", ctrl_token);
let next: NodeID = self.control_subgraph.succs(ctrl_token).next().unwrap();
println!("{:?}", next);
next
}
Node::Region { preds } => {
self.handle_region(prev, ctrl_token, preds)
}
Node::If { control, cond } => todo!(),
Node::Match { control, sum } => todo!(),
Node::Fork { control, factor } => todo!(),
Node::Join { control } => todo!(),
Node::Phi { control, data } => todo!(),
Node::ThreadID { control } => todo!(),
Node::Reduce { control, init, reduct } => todo!(),
Node::Return { control, data } => {
let result = self.handle_data(*data);
println!("result = {result}");
break;
}
Node::Parameter { index } => todo!(),
Node::Constant { id } => todo!(),
Node::DynamicConstant { id } => todo!(),
Node::Unary { input, op } => todo!(),
Node::Binary { left, right, op } => todo!(),
Node::Ternary { first, second, third, op } => todo!(),
Node::Call { function, dynamic_constants, args } => todo!(),
Node::Read { collect, indices } => todo!(),
Node::Write { collect, data, indices } => todo!(),
};
let prev = ctrl_token;
}
}
}
impl<'a> IRInterpreter<'a> {
/*
pub fn resolve_data_subgraph(&self, data_subgraph: &'a Subgraph) -> u32 {
}
*/
/* TODO: only update nodes that need to be updated (i.e their inputs did not change) \
* To eventually support this, instead of recursing backwards, move forward in reverse postorder?
* (data sections alone aren't cyclic?)
*/
}
......@@ -761,6 +761,13 @@ impl DynamicConstant {
false
}
}
pub fn value(&self) -> usize {
match self {
DynamicConstant::Constant(v) => *v,
DynamicConstant::Parameter(v) => *v,
}
}
}
/*
......@@ -900,6 +907,14 @@ impl Node {
}
}
pub fn try_reduce(&self) -> Option<(NodeID, NodeID, NodeID)> {
if let Node::Reduce { control, init, reduct } = self {
Some((*control, *init, *reduct))
} else {
None
}
}
pub fn try_constant(&self) -> Option<ConstantID> {
if let Node::Constant { id } = self {
Some(*id)
......
......@@ -8,7 +8,6 @@ pub mod def_use;
pub mod dom;
pub mod dot;
pub mod gcm;
pub mod interpreter;
pub mod ir;
pub mod loops;
pub mod parse;
......@@ -25,7 +24,6 @@ pub use crate::def_use::*;
pub use crate::dom::*;
pub use crate::dot::*;
pub use crate::gcm::*;
pub use crate::interpreter::*;
pub use crate::ir::*;
pub use crate::loops::*;
pub use crate::parse::*;
......
......@@ -8,3 +8,5 @@ clap = { version = "*", features = ["derive"] }
rand = "*"
hercules_ir = { path = "../../hercules_ir" }
hercules_opt = { path = "../../hercules_opt" }
itertools = "*"
ordered-float = "*"
\ No newline at end of file
This diff is collapsed.
extern crate clap;
extern crate rand;
extern crate hercules_opt;
extern crate hercules_ir;
pub mod interpreter;
pub mod value;
use interpreter::*;
use value::*;
use std::fs::File;
use std::io::prelude::*;
use self::hercules_ir::*;
use self::hercules_opt::*;
use clap::Parser;
#[derive(Parser, Debug)]
......@@ -30,29 +40,66 @@ fn main() {
let mut pm = hercules_opt::pass::PassManager::new(module);
pm.add_pass(hercules_opt::pass::Pass::Verify);
pm.add_pass(hercules_opt::pass::Pass::Xdot(true));
pm.add_pass(hercules_opt::pass::Pass::CCP);
pm.add_pass(hercules_opt::pass::Pass::DCE);
pm.add_pass(hercules_opt::pass::Pass::GVN);
pm.add_pass(hercules_opt::pass::Pass::DCE);
pm.add_pass(hercules_opt::pass::Pass::Forkify);
pm.add_pass(hercules_opt::pass::Pass::DCE);
pm.add_pass(hercules_opt::pass::Pass::Predication);
pm.add_pass(hercules_opt::pass::Pass::DCE);
pm.add_pass(hercules_opt::pass::Pass::Xdot(true));
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 state = hercules_ir::interpreter::FunctionExecutionState::new(
vec![2, 0],
control_subgraphs.first().unwrap(),
let dynamic_constants = vec![DynamicConstant::Constant(2); 3];
//let vec = vec![InterpreterVal::Integer32(15); 12];
let matrix1 = vec![InterpreterVal::Integer32(2), InterpreterVal::Integer32(3),
InterpreterVal::Integer32(4), InterpreterVal::Integer32(1)];
let matrix2 = vec![InterpreterVal::Integer32(2), InterpreterVal::Integer32(3),
InterpreterVal::Integer32(4), InterpreterVal::Integer32(1)];
//let array = InterpreterVal::Array(TypeID::new(0), bingle.into_boxed_slice());
//let args = vec![];
let function_number = 0;
let parameter_types = &module.functions[function_number].param_types;
println!("parameter_types: {:?}", parameter_types);
let array_type = parameter_types[0];
println!("type: {:?}", array_type);
let args = vec![InterpreterVal::Array(parameter_types[0], matrix1.into_boxed_slice()), InterpreterVal::Array(parameter_types[1], matrix2.into_boxed_slice())];
let mut state = interpreter::FunctionExecutionState::new(
args,
&control_subgraphs[function_number],
&module,
def_uses.first().unwrap(),
module.functions.first().unwrap(),
&def_uses[function_number],
&dynamic_constants,
&fork_join_maps[function_number],
&fork_join_nests[function_number],
&module.functions[function_number]
);
state.run();
......
This diff is collapsed.
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