Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • llvm/hercules
1 result
Show changes
Commits on Source (2)
Showing
with 2113 additions and 87 deletions
......@@ -5,5 +5,5 @@
*.ll
*.c
*.o
*.hbin
.*.swp
......@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "aho-corasick"
version = "1.1.2"
version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0"
checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [
"memchr",
]
......@@ -61,15 +61,30 @@ dependencies = [
[[package]]
name = "anyhow"
version = "1.0.80"
version = "1.0.81"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247"
[[package]]
name = "atomic-polyfill"
version = "1.0.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ad32ce52e4161730f7098c077cd2ed6229b5804ccf99e5366be1ab72a98b4e1"
checksum = "8cf2bce30dfe09ef0bfaef228b9d414faaf7e563035494d7fe092dba54b300f4"
dependencies = [
"critical-section",
]
[[package]]
name = "autocfg"
version = "1.1.0"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa"
checksum = "f1fdabc7756949593fe60f30ec81974b613357de856987752631dea1e3394c80"
[[package]]
name = "base64"
version = "0.21.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9d297deb1925b89f2ccc13d7635fa0714f12c87adce1c75356b39ca9b7178567"
[[package]]
name = "bincode"
......@@ -86,6 +101,15 @@ version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "bitflags"
version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cf4b9d6a944f767f8e5e0db018570623c85f3d925ac718db4e06d0187adb21c1"
dependencies = [
"serde",
]
[[package]]
name = "bitvec"
version = "1.0.1"
......@@ -98,6 +122,12 @@ dependencies = [
"wyz",
]
[[package]]
name = "byteorder"
version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b"
[[package]]
name = "cactus"
version = "1.0.7"
......@@ -126,9 +156,9 @@ dependencies = [
[[package]]
name = "clap"
version = "4.5.2"
version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b230ab84b0ffdf890d5a10abdbc8b83ae1c4918275daea1ab8801f71536b2651"
checksum = "90bc066a67923782aa8515dbaea16946c5bcc5addbd668bb80af688e53e548a0"
dependencies = [
"clap_builder",
"clap_derive",
......@@ -148,9 +178,9 @@ dependencies = [
[[package]]
name = "clap_derive"
version = "4.5.0"
version = "4.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "307bc0538d5f0f83b8248db3087aa92fe504e4691294d0c96c0eabc33f47ba47"
checksum = "528131438037fd55894f62d6e9f068b8f45ac57ffa77517819645d10aed04f64"
dependencies = [
"heck",
"proc-macro2",
......@@ -164,12 +194,24 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "98cc8fbded0c607b7ba9dd60cd98df59af97e84d24e49c8557331cfc26d301ce"
[[package]]
name = "cobs"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "67ba02a97a2bd10f4b59b25c7973101c79642302776489e030cd13cdab09ed15"
[[package]]
name = "colorchoice"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
[[package]]
name = "critical-section"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7059fff8937831a9ae6f0fe4d658ffabf58f2ca96aa9dec1c889f936f705f216"
[[package]]
name = "deranged"
version = "0.3.11"
......@@ -180,13 +222,10 @@ dependencies = [
]
[[package]]
name = "ena"
version = "0.14.2"
name = "embedded-io"
version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c533630cf40e9caa44bd91aadc88a75d75a4c3a12b4cfde353cbed41daa1e1f1"
dependencies = [
"log",
]
checksum = "ef1a6892d9eef45c8fa6b9e0086428a2cca8491aca8f787c534a3d6d0bcb3ced"
[[package]]
name = "equivalent"
......@@ -238,29 +277,52 @@ dependencies = [
"wasi",
]
[[package]]
name = "hash32"
version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0c35f58762feb77d74ebe43bdbc3210f09be9fe6742234d573bacc26ed92b67"
dependencies = [
"byteorder",
]
[[package]]
name = "hashbrown"
version = "0.14.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "290f1a1d9242c78d09ce40a5e87e7554ee637af1351968159f4952f028f75604"
[[package]]
name = "heapless"
version = "0.7.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "cdc6457c0eb62c71aac4bc17216026d8410337c4126773b9c5daba343f17964f"
dependencies = [
"atomic-polyfill",
"hash32",
"rustc_version",
"serde",
"spin",
"stable_deref_trait",
]
[[package]]
name = "heck"
version = "0.4.1"
version = "0.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "95505c38b4572b2d910cecb0281560f54b440a19336cbbcb27bf6ce6adc6f5a8"
checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea"
[[package]]
name = "hercules_cg"
version = "0.1.0"
dependencies = [
"bitvec",
"ena",
"hercules_ir",
"hercules_rt",
]
[[package]]
name = "hercules_cpu"
name = "hercules_cpu_beta"
version = "0.1.0"
dependencies = [
"clap",
......@@ -280,6 +342,16 @@ dependencies = [
"rand",
]
[[package]]
name = "hercules_driver"
version = "0.1.0"
dependencies = [
"clap",
"hercules_ir",
"hercules_opt",
"ron",
]
[[package]]
name = "hercules_ir"
version = "0.1.0"
......@@ -288,6 +360,7 @@ dependencies = [
"nom",
"ordered-float",
"rand",
"serde",
]
[[package]]
......@@ -304,8 +377,11 @@ name = "hercules_opt"
version = "0.1.0"
dependencies = [
"bitvec",
"hercules_cg",
"hercules_ir",
"ordered-float",
"postcard",
"serde",
"take_mut",
]
......@@ -313,14 +389,17 @@ dependencies = [
name = "hercules_rt"
version = "0.1.0"
dependencies = [
"hercules_ir",
"libc",
"postcard",
"serde",
]
[[package]]
name = "indexmap"
version = "2.2.5"
version = "2.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7b0b929d511467233429c45a44ac1dcaa21ba0f5ba11e4879e6ed28ddb4f9df4"
checksum = "168fb715dda47215e360912c096649d23d58bf392ac62f73919e831745e40f26"
dependencies = [
"equivalent",
"hashbrown",
......@@ -328,9 +407,9 @@ dependencies = [
[[package]]
name = "itoa"
version = "1.0.10"
version = "1.0.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
checksum = "49f1f14873335454500d59611f1cf4a4b0f786f9ac11f4312a78e4cf2566695b"
[[package]]
name = "juno_frontend"
......@@ -358,10 +437,14 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c198f91728a82281a64e1f4f9eeb25d82cb32a5de251c6bd1b5154d63a8e7bd"
[[package]]
name = "log"
version = "0.4.21"
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "lrlex"
......@@ -482,6 +565,18 @@ dependencies = [
"serde",
]
[[package]]
name = "postcard"
version = "1.0.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a55c51ee6c0db07e68448e336cf8ea4131a620edefebf9893e759b2d793420f8"
dependencies = [
"cobs",
"embedded-io",
"heapless",
"serde",
]
[[package]]
name = "powerfmt"
version = "0.2.0"
......@@ -496,9 +591,9 @@ checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de"
[[package]]
name = "proc-macro2"
version = "1.0.78"
version = "1.0.79"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2422ad645d89c99f8f3e6b88a9fdeca7fabeac836b1002371c4367c8f984aae"
checksum = "e835ff2298f5721608eb1a980ecaee1aef2c132bf95ecc026a11b7bf3c01c02e"
dependencies = [
"unicode-ident",
]
......@@ -554,19 +649,19 @@ version = "0.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa"
dependencies = [
"bitflags",
"bitflags 1.3.2",
]
[[package]]
name = "regex"
version = "1.10.3"
version = "1.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15"
checksum = "c117dbdfde9c8308975b6a18d71f3f385c89461f7b3fb054288ecf2a2058ba4c"
dependencies = [
"aho-corasick",
"memchr",
"regex-automata",
"regex-syntax 0.8.2",
"regex-syntax 0.8.3",
]
[[package]]
......@@ -577,7 +672,7 @@ checksum = "86b83b8b9847f9bf95ef68afb0b8e6cdb80f498442f5179a29fad448fcc1eaea"
dependencies = [
"aho-corasick",
"memchr",
"regex-syntax 0.8.2",
"regex-syntax 0.8.3",
]
[[package]]
......@@ -588,9 +683,21 @@ checksum = "dbb5fb1acd8a1a18b3dd5be62d25485eb770e05afb408a9627d14d451bae12da"
[[package]]
name = "regex-syntax"
version = "0.8.2"
version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f"
checksum = "adad44e29e4c806119491a7f06f03de4d1af22c3a680dd47f1e6e179439d1f56"
[[package]]
name = "ron"
version = "0.8.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b91f7eff05f748767f183df4320a63d6936e9c6107d97c9e6bdd9784f4289c94"
dependencies = [
"base64",
"bitflags 2.5.0",
"serde",
"serde_derive",
]
[[package]]
name = "rustc_version"
......@@ -607,6 +714,12 @@ version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "semver"
version = "1.0.22"
......@@ -645,6 +758,21 @@ dependencies = [
"vob",
]
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"lock_api",
]
[[package]]
name = "stable_deref_trait"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3"
[[package]]
name = "static_assertions"
version = "1.1.0"
......@@ -659,9 +787,9 @@ checksum = "5ee073c9e4cd00e28217186dbe12796d692868f432bf2e97ee73bed0c56dfa01"
[[package]]
name = "syn"
version = "2.0.52"
version = "2.0.55"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b699d15b36d1f02c3e7c69f8ffef53de37aefae075d8488d4ba1a7788d574a07"
checksum = "002a1b3dbf967edfafc32655d0f377ab0bb7b994aa1d32c8cc7e9b8bf3ebb8f0"
dependencies = [
"proc-macro2",
"quote",
......
......@@ -6,8 +6,9 @@ members = [
"hercules_opt",
"hercules_rt",
"hercules_tools/hercules_driver",
"hercules_tools/hercules_dot",
"hercules_tools/hercules_cpu",
"hercules_tools/hercules_cpu_beta",
"juno_frontend",
......
......@@ -5,5 +5,5 @@ authors = ["Russel Arbore <rarbore2@illinois.edu>"]
[dependencies]
bitvec = "*"
ena = "*"
hercules_ir = { path = "../hercules_ir" }
hercules_rt = { path = "../hercules_rt" }
This diff is collapsed.
This diff is collapsed.
......@@ -3,6 +3,7 @@ extern crate hercules_ir;
use std::collections::HashMap;
use std::collections::VecDeque;
use std::fmt::Write;
use std::iter::zip;
......
#![feature(let_chains)]
pub mod common;
pub mod cpu;
pub mod cpu_beta;
pub mod top;
pub use crate::common::*;
pub use crate::cpu::*;
pub use crate::cpu_beta::*;
pub use crate::top::*;
extern crate hercules_ir;
extern crate hercules_rt;
use std::collections::HashMap;
use std::fmt::Write;
use self::hercules_ir::*;
use self::hercules_rt::manifest::*;
use crate::*;
/*
* Top level function to generate code for a module. Emits LLVM IR text. Calls
* out to backends to generate code for individual partitions. Creates a
* manifest describing the generated code.
*/
pub fn codegen<W: Write>(
module: &Module,
def_uses: &Vec<ImmutableDefUseMap>,
reverse_postorders: &Vec<Vec<NodeID>>,
typing: &ModuleTyping,
control_subgraphs: &Vec<Subgraph>,
fork_join_maps: &Vec<HashMap<NodeID, NodeID>>,
fork_join_nests: &Vec<HashMap<NodeID, Vec<NodeID>>>,
antideps: &Vec<Vec<(NodeID, NodeID)>>,
bbs: &Vec<Vec<NodeID>>,
plans: &Vec<Plan>,
w: &mut W,
) -> Result<ModuleManifest, std::fmt::Error> {
// Render types, constants, and dynamic constants into LLVM IR.
let llvm_types = generate_type_strings(module);
let llvm_constants = generate_constant_strings(module);
let llvm_dynamic_constants = generate_dynamic_constant_strings(module);
// Generate a dummy uninitialized global - this is needed so that there'll
// be a non-empty .bss section in the ELF object file.
write!(w, "@dummy = dso_local global i32 0, align 4\n")?;
// Do codegen for each function individually. Get each function's manifest.
let mut manifests = vec![];
for function_idx in 0..module.functions.len() {
// There's a bunch of per-function information we use.
let context = FunctionContext {
function: &module.functions[function_idx],
types: &module.types,
constants: &module.constants,
dynamic_constants: &module.dynamic_constants,
def_use: &def_uses[function_idx],
reverse_postorder: &reverse_postorders[function_idx],
typing: &typing[function_idx],
control_subgraph: &control_subgraphs[function_idx],
fork_join_map: &fork_join_maps[function_idx],
fork_join_nest: &fork_join_nests[function_idx],
antideps: &antideps[function_idx],
bbs: &bbs[function_idx],
plan: &plans[function_idx],
llvm_types: &llvm_types,
llvm_constants: &llvm_constants,
llvm_dynamic_constants: &llvm_dynamic_constants,
partitions_inverted_map: plans[function_idx].invert_partition_map(),
};
manifests.push(context.codegen_function(w)?);
}
// Assemble the manifest for the whole module.
Ok(ModuleManifest {
functions: manifests,
types: module.types.clone(),
// TODO: populate array constants.
array_constants: vec![],
})
}
impl<'a> FunctionContext<'a> {
/*
* Each function gets codegened separately.
*/
fn codegen_function<W: Write>(&self, w: &mut W) -> Result<FunctionManifest, std::fmt::Error> {
// Find the "top" control node of each partition. One well-formedness
// condition of partitions is that there is exactly one "top" control
// node.
let top_nodes: Vec<NodeID> = self
.partitions_inverted_map
.iter()
.enumerate()
.map(|(part_idx, part)| {
// For each partition, find the "top" node.
*part
.iter()
.filter(move |id| {
// The "top" node is a control node having at least one
// control predecessor in another partition, or is a
// start node. Every predecessor in the control subgraph
// is a control node.
self.function.nodes[id.idx()].is_start()
|| (self.function.nodes[id.idx()].is_control()
&& self
.control_subgraph
.preds(**id)
.filter(|pred_id| {
self.plan.partitions[pred_id.idx()].idx() != part_idx
})
.count()
> 0)
})
.next()
.unwrap()
})
.collect();
// Generate code for each individual partition. This generates a single
// LLVM function per partition. These functions will be called in async
// tasks by the Hercules runtime.
assert_eq!(self.plan.num_partitions, top_nodes.len());
let mut manifests = vec![];
for part_idx in 0..self.plan.num_partitions {
match self.plan.partition_devices[part_idx] {
Device::CPU => manifests.push(self.codegen_cpu_partition(top_nodes[part_idx], w)?),
Device::GPU => todo!(),
}
}
// Assemble the manifest for the whole function.
Ok(FunctionManifest {
name: self.function.name.clone(),
param_types: self.function.param_types.clone(),
typing: self.typing.clone(),
num_dynamic_constant_parameters: self.function.num_dynamic_constants,
partitions: manifests,
// TODO: populate dynamic constant rules.
dynamic_constant_rules: vec![],
})
}
}
......@@ -7,4 +7,5 @@ authors = ["Russel Arbore <rarbore2@illinois.edu>, Aaron Councilman <aaronjc4@il
rand = "*"
nom = "*"
ordered-float = "*"
bitvec = "*"
\ No newline at end of file
bitvec = "*"
serde = { version = "*", features = ["derive"] }
\ No newline at end of file
extern crate bitvec;
extern crate ordered_float;
extern crate serde;
use std::fmt::Write;
use std::ops::Coroutine;
......@@ -7,6 +8,8 @@ use std::ops::CoroutineState;
use std::pin::Pin;
use self::bitvec::prelude::*;
use self::serde::Deserialize;
use self::serde::Serialize;
use crate::*;
......@@ -52,7 +55,7 @@ pub struct Function {
* parallelism. Summation types are an IR equivalent of Rust's enum types.
* These are lowered into tagged unions during scheduling.
*/
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum Type {
Control(Box<[NodeID]>),
Boolean,
......@@ -379,7 +382,7 @@ impl Module {
let mut stack = (0..self.types.len())
.map(TypeID::new)
.collect::<Vec<TypeID>>();
let coroutine = move || {
let coroutine = #[coroutine] move || {
// Since this is a coroutine, handle recursion manually.
while let Some(id) = stack.pop() {
if visited[id.idx()] {
......@@ -438,7 +441,7 @@ impl Module {
let mut stack = (0..self.constants.len())
.map(ConstantID::new)
.collect::<Vec<ConstantID>>();
let coroutine = move || {
let coroutine = #[coroutine] move || {
// Since this is a coroutine, handle recursion manually.
while let Some(id) = stack.pop() {
if visited[id.idx()] {
......@@ -593,7 +596,8 @@ impl<T: Clone> GraveUpdatable for Vec<T> {
for (data, (idx, mapping)) in
std::iter::zip(self.into_iter(), grave_mapping.iter().enumerate())
{
if idx != 0 && mapping.idx() == 0 {
if idx == 0 || mapping.idx() != 0 {
assert_eq!(new_self.len(), mapping.idx());
new_self.push(data.clone());
}
}
......@@ -695,6 +699,22 @@ impl Constant {
}
}
pub fn try_array_type(&self, types: &[Type]) -> Option<TypeID> {
// Need types, since zero initializer may be for a collection type, ro
// not.
match self {
Constant::Array(ty, _) => Some(*ty),
Constant::Zero(ty) => {
if types[ty.idx()].is_primitive() {
None
} else {
Some(*ty)
}
}
_ => None,
}
}
/*
* Useful for GVN.
*/
......@@ -732,6 +752,16 @@ impl Constant {
}
}
impl DynamicConstant {
pub fn is_parameter(&self) -> bool {
if let DynamicConstant::Parameter(_) = self {
true
} else {
false
}
}
}
/*
* Simple predicate functions on nodes take a lot of space, so use a macro.
*/
......@@ -825,6 +855,9 @@ impl Node {
data: _,
}
);
define_pattern_predicate!(is_parameter, Node::Parameter { index: _ });
define_pattern_predicate!(is_constant, Node::Constant { id: _ });
define_pattern_predicate!(is_dynamic_constant, Node::DynamicConstant { id: _ });
define_pattern_predicate!(
is_read,
Node::Read {
......@@ -1148,7 +1181,18 @@ impl TernaryOperator {
#[macro_export]
macro_rules! define_id_type {
($x: ident) => {
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord)]
#[derive(
Debug,
Clone,
Copy,
PartialEq,
Eq,
Hash,
PartialOrd,
Ord,
serde::Serialize,
serde::Deserialize,
)]
pub struct $x(u32);
impl $x {
......
#![feature(coroutines, coroutine_trait, let_chains)]
#![feature(coroutines, coroutine_trait, let_chains, stmt_expr_attributes)]
pub mod antideps;
pub mod build;
......
......@@ -189,7 +189,7 @@ pub fn default_plan(
schedules: vec![vec![]; function.nodes.len()],
partitions: vec![PartitionID::new(0); function.nodes.len()],
partition_devices: vec![Device::CPU; 1],
num_partitions: 0,
num_partitions: 1,
};
// Infer schedules.
......@@ -198,7 +198,8 @@ pub fn default_plan(
// Infer a partitioning.
partition_out_forks(function, reverse_postorder, fork_join_map, bbs, &mut plan);
place_fork_partitions_on_gpu(function, &mut plan);
// TODO: uncomment once GPU backend is implemented.
// place_fork_partitions_on_gpu(function, &mut plan);
plan
}
......@@ -349,13 +350,15 @@ pub fn partition_out_forks(
reverse_postorder,
|inputs: &[&NodeID], node_id: NodeID| match function.nodes[node_id.idx()] {
Node::Start => NodeID::new(0),
Node::Fork {
control: _,
factor: _,
} => {
Node::Fork { control, factor: _ } => {
// Start a partition if the preceding partition isn't a fork
// partition. Otherwise, be part of the parent fork partition.
if *inputs[0] != NodeID::top() && function.nodes[inputs[0].idx()].is_fork() {
// partition and the predecessor isn't the join for the
// predecessor fork partition. Otherwise, be part of the parent
// fork partition.
if *inputs[0] != NodeID::top()
&& function.nodes[inputs[0].idx()].is_fork()
&& fork_join_map.get(&inputs[0]) != Some(&control)
{
inputs[0].clone()
} else {
node_id
......
......@@ -37,6 +37,12 @@ impl<'a> Iterator for SubgraphIterator<'a> {
}
}
impl<'a> ExactSizeIterator for SubgraphIterator<'a> {
fn len(&self) -> usize {
self.edges.len()
}
}
impl IntoIterator for Subgraph {
type Item = NodeID;
type IntoIter = std::vec::IntoIter<Self::Item>;
......
......@@ -7,4 +7,7 @@ authors = ["Russel Arbore <rarbore2@illinois.edu>, Aaron Councilman <aaronjc4@il
ordered-float = "*"
bitvec = "*"
take_mut = "*"
postcard = { version = "*", features = ["alloc"] }
serde = { version = "*", features = ["derive"] }
hercules_ir = { path = "../hercules_ir" }
hercules_cg = { path = "../hercules_cg" }
extern crate hercules_cg;
extern crate hercules_ir;
extern crate postcard;
extern crate serde;
extern crate take_mut;
use std::collections::HashMap;
use std::fs::File;
use std::io::prelude::*;
use std::iter::zip;
use std::process::*;
use self::hercules_ir::antideps::*;
use self::hercules_ir::dataflow::*;
use self::hercules_ir::def_use::*;
use self::hercules_ir::dom::*;
use self::hercules_ir::dot::*;
use self::hercules_ir::gcm::*;
use self::hercules_ir::ir::*;
use self::hercules_ir::loops::*;
use self::hercules_ir::schedule::*;
use self::hercules_ir::subgraph::*;
use self::hercules_ir::typecheck::*;
use self::hercules_ir::verify::*;
use self::serde::Deserialize;
use self::hercules_cg::*;
use self::hercules_ir::*;
use crate::*;
/*
* Passes that can be run on a module.
*/
#[derive(Debug, Clone)]
#[derive(Debug, Clone, Deserialize)]
pub enum Pass {
DCE,
CCP,
......@@ -31,7 +29,11 @@ pub enum Pass {
PhiElim,
Predication,
Verify,
// Parameterized over whether analyses that aid visualization are necessary.
// Useful to set to false if displaying a potentially broken module.
Xdot(bool),
// Parameterized by output file name.
Codegen(String),
}
/*
......@@ -221,7 +223,7 @@ impl PassManager {
}
pub fn make_bbs(&mut self) {
if self.antideps.is_none() {
if self.bbs.is_none() {
self.make_def_uses();
self.make_reverse_postorders();
self.make_doms();
......@@ -390,6 +392,61 @@ impl PassManager {
// Xdot doesn't require clearing analysis results.
continue;
}
Pass::Codegen(output_file_name) => {
self.make_def_uses();
self.make_reverse_postorders();
self.make_typing();
self.make_control_subgraphs();
self.make_fork_join_maps();
self.make_fork_join_nests();
self.make_antideps();
self.make_bbs();
self.make_plans();
let mut llvm_ir = String::new();
let manifest = codegen(
&self.module,
self.def_uses.as_ref().unwrap(),
self.reverse_postorders.as_ref().unwrap(),
self.typing.as_ref().unwrap(),
self.control_subgraphs.as_ref().unwrap(),
self.fork_join_maps.as_ref().unwrap(),
self.fork_join_nests.as_ref().unwrap(),
self.antideps.as_ref().unwrap(),
self.bbs.as_ref().unwrap(),
self.plans.as_ref().unwrap(),
&mut llvm_ir,
)
.unwrap();
// Compile LLVM IR into ELF object.
let llc_process = Command::new("llc")
.arg("-filetype=obj")
.arg("-O3")
.stdin(Stdio::piped())
.stdout(Stdio::piped())
.spawn()
.unwrap();
llc_process
.stdin
.as_ref()
.unwrap()
.write(llvm_ir.as_bytes())
.unwrap();
let elf_object = llc_process.wait_with_output().unwrap().stdout;
// Package manifest and ELF object into the same file.
let hbin_module = (manifest, elf_object);
let hbin_contents: Vec<u8> = postcard::to_allocvec(&hbin_module).unwrap();
let mut file =
File::create(output_file_name).expect("PANIC: Unable to open output file.");
file.write_all(&hbin_contents)
.expect("PANIC: Unable to write output file contents.");
// Codegen doesn't require clearing analysis results.
continue;
}
}
// Cleanup the module after passes. Delete gravestone nodes. Repair
......
......@@ -5,3 +5,6 @@ authors = ["Russel Arbore <rarbore2@illinois.edu>"]
[dependencies]
libc = "*"
postcard = { version = "*", features = ["alloc"] }
serde = { version = "*", features = ["derive"] }
hercules_ir = { path = "../hercules_ir" }
extern crate postcard;
use std::fs::File;
use std::io::prelude::*;
use std::path::Path;
pub(crate) mod elf;
pub mod manifest;
pub(crate) use crate::elf::*;
pub(crate) use crate::manifest::*;
#[derive(Debug)]
pub struct Module {
manifest: ModuleManifest,
elf: Elf,
}
impl Module {
pub fn get_function_ptr(&self, name: &str) -> *mut u8 {
unsafe {
self.elf.program_section.offset(
self.elf.function_pointers[self
.elf
.function_names
.iter()
.position(|s| s == name)
.unwrap()],
)
}
/*
* Get the function pointer corresponding to a function name. Panic if not
* found.
*/
pub unsafe fn get_function_ptr(&self, name: &str) -> *mut u8 {
self.elf.program_section.offset(
self.elf.function_pointers[self
.elf
.function_names
.iter()
.position(|s| s == name)
.unwrap()],
)
}
}
......@@ -29,8 +36,12 @@ pub fn load_binary(path: &Path) -> Module {
let mut f = File::open(path).unwrap();
let mut buffer = vec![];
f.read_to_end(&mut buffer).unwrap();
let elf = unsafe { parse_elf(buffer.as_slice()) };
Module { elf }
let manifest_and_elf_bytes: (ModuleManifest, Vec<u8>) = postcard::from_bytes(&buffer).unwrap();
let elf = unsafe { parse_elf(&manifest_and_elf_bytes.1) };
Module {
manifest: manifest_and_elf_bytes.0,
elf,
}
}
/*
......
extern crate hercules_ir;
extern crate serde;
use self::serde::Deserialize;
use self::serde::Serialize;
use self::hercules_ir::ir::*;
/*
* Every .hbin file contains a manifest which describes the Hercules functions
* contained in the module. This information is used by the runtime to execute
* the functions properly, the chief concern being how to stitch together the
* execution of each partition.
*/
#[derive(Debug, Serialize, Deserialize)]
pub struct ModuleManifest {
// A module contains a manifest per individual function.
pub functions: Vec<FunctionManifest>,
// All of the types used in the module.
pub types: Vec<Type>,
// The only constants that aren't baked into the generated code are array
// constants. These are explicitly stored in and loaded from the manifest.
// Arrays are composed of the underlying array bytes. We don't need to store
// the dimensions of arrays at this point, since the runtime doesn't
// manipulate or otherwise need the dimensions of constant arrays.
pub array_constants: Vec<Vec<u8>>,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct FunctionManifest {
pub name: String,
// Types of the function parameters.
pub param_types: Vec<TypeID>,
// Types of all of the nodes in this function. Used for figuring out the
// type of partition data inputs and outputs.
pub typing: Vec<TypeID>,
// Number of dynamic constant parameters that need to provided.
pub num_dynamic_constant_parameters: u32,
// Manifests for constituent partitions.
pub partitions: Vec<PartitionManifest>,
// When using dynamic constants, certain constraints are generated. For
// example, using a dynamic constant in a fork means that it must be non-
// zero, since fork-join nests are guaranteed to execute at least one
// iteration. Also, if one uses division in dynamic constant math, the
// resulting dynamic constant must be an integer, so the numerator dynamic
// constant must be divisible by the denominator dynamic constant. These are
// stored per function, since different functions have different contraints
// on their dynamic constant parameters.
pub dynamic_constant_rules: Vec<DynamicConstantRule>,
}
/*
* Rules for validity of provided dynamic constants. Integers refer to dynamic
* constant parameters of a function.
*/
#[derive(Debug, Serialize, Deserialize)]
pub enum DynamicConstantRule {
// Generated from forks.
NonZero(u32),
// Generated from subtraction.
LessThan(u32, u32),
// Generated from division.
Divides(u32, u32),
}
#[derive(Debug, Serialize, Deserialize)]
pub enum PartitionInput {
// Data input from another partition within this function. Integer is the
// node ID used from the other partition.
DataInput(u32),
// An argument from the function parameters. Integer is the parameter index.
FunctionArgument(u32),
// An array constant used in this function. Integer is the array constant
// number.
ArrayConstant(u32),
// A dynamic constant parameter of this function. Integer is the dynamic
// constant parameter number.
DynamicConstant(u32),
}
#[derive(Debug, Serialize, Deserialize)]
pub enum PartitionOutput {
// Data output used by another partition within this function, or to be
// returned from this function. Integer is the node ID used in the other
// partition or by a return node.
DataOutput(u32),
// Value indicating control flow that the runtime should take.
ControlIndicator,
}
#[derive(Debug, Serialize, Deserialize, Default)]
pub struct PartitionManifest {
// Top node for this partition, as an integer.
pub top_node: u32,
pub inputs: Vec<PartitionInput>,
pub outputs: Vec<PartitionOutput>,
}
......@@ -3,17 +3,19 @@ extern crate clap;
use std::path::Path;
fn main() {
let module = hercules_rt::load_binary(Path::new("test.o"));
let module = hercules_rt::load_binary(Path::new("matmul.hbin"));
println!("{:?}", module);
let matmul = hercules_rt::lookup_function!(
module,
"matmul",
"matmul_part_1",
*const f32,
*const f32,
*mut f32,
u64,
u64,
u64,
*mut f32,
=> *const f32
);
......@@ -24,10 +26,10 @@ fn main() {
matmul(
std::mem::transmute(a.as_ptr()),
std::mem::transmute(b.as_ptr()),
std::mem::transmute(c.as_mut_ptr()),
2,
2,
2,
std::mem::transmute(c.as_mut_ptr()),
)
};
println!("{} {}\n{} {}", c[0][0], c[0][1], c[1][0], c[1][1]);
......