From dbc6216ce62539d660fa1cd80e1a428ba93d1ee5 Mon Sep 17 00:00:00 2001 From: Russel Arbore <russel.jma@gmail.com> Date: Thu, 31 Oct 2024 16:07:10 -0500 Subject: [PATCH] Refactor PM, add pass to seralize module --- Cargo.lock | 7 +++- hercules_ir/Cargo.toml | 2 +- hercules_ir/src/ir.rs | 18 +++++----- hercules_opt/src/pass.rs | 37 ++++++++++---------- hercules_rt_proc/src/lib.rs | 24 ++++++++----- hercules_samples/matmul/src/main.rs | 2 +- hercules_tools/hercules_driver/Cargo.toml | 1 + hercules_tools/hercules_driver/src/main.rs | 39 +++++++++++++++------- 8 files changed, 81 insertions(+), 49 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 6ef91b76..27bf3c1e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1,6 +1,6 @@ # This file is automatically @generated by Cargo. # It is not intended for manual editing. -version = 3 +version = 4 [[package]] name = "aho-corasick" @@ -609,6 +609,7 @@ dependencies = [ "clap", "hercules_ir", "hercules_opt", + "postcard", "ron", ] @@ -950,6 +951,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a76df7075c7d4d01fdcb46c912dd17fba5b60c78ea480b475f2b6ab6f666584e" dependencies = [ "num-traits", + "rand", + "serde", ] [[package]] @@ -1105,6 +1108,7 @@ dependencies = [ "libc", "rand_chacha", "rand_core", + "serde", ] [[package]] @@ -1124,6 +1128,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" dependencies = [ "getrandom", + "serde", ] [[package]] diff --git a/hercules_ir/Cargo.toml b/hercules_ir/Cargo.toml index b99c0877..44648c11 100644 --- a/hercules_ir/Cargo.toml +++ b/hercules_ir/Cargo.toml @@ -6,6 +6,6 @@ authors = ["Russel Arbore <rarbore2@illinois.edu>, Aaron Councilman <aaronjc4@il [dependencies] rand = "*" nom = "*" -ordered-float = "*" +ordered-float = { version = "*", features = ["serde"] } bitvec = "*" serde = { version = "*", features = ["derive"] } \ No newline at end of file diff --git a/hercules_ir/src/ir.rs b/hercules_ir/src/ir.rs index 4c487c59..7b96f6b0 100644 --- a/hercules_ir/src/ir.rs +++ b/hercules_ir/src/ir.rs @@ -19,7 +19,7 @@ use crate::*; * wants to run an intraprocedural pass in parallel, it is advised to first * destruct the module, then reconstruct it once finished. */ -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, Serialize, Deserialize)] pub struct Module { pub functions: Vec<Function>, pub types: Vec<Type>, @@ -35,7 +35,7 @@ pub struct Module { * constants are 64-bit unsigned integers (usize / u64), so it is sufficient to * just store how many of them the function takes as arguments. */ -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Serialize, Deserialize)] pub struct Function { pub name: String, pub param_types: Vec<TypeID>, @@ -77,7 +77,7 @@ pub enum Type { * interning constants during IR construction). Product, summation, and array * constants all contain their own type. */ -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Constant { Boolean(bool), Integer8(i8), @@ -128,7 +128,7 @@ pub enum DynamicConstant { * operate on an index list, composing indices at different levels in a type * tree. Each type that can be indexed has a unique variant in the index enum. */ -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Index { Field(usize), Variant(usize), @@ -146,7 +146,7 @@ pub enum Index { * side effects, so call nodes don't take as input or output control tokens. * There is also no global memory - use arrays. */ -#[derive(Debug, Clone, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Node { Start, Region { @@ -232,14 +232,14 @@ pub enum Node { }, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum UnaryOperator { Not, Neg, Cast(TypeID), } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum BinaryOperator { Add, Sub, @@ -259,12 +259,12 @@ pub enum BinaryOperator { RSh, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum TernaryOperator { Select, } -#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)] pub enum Intrinsic { Abs, ACos, diff --git a/hercules_opt/src/pass.rs b/hercules_opt/src/pass.rs index e96fb4b6..5866c57c 100644 --- a/hercules_opt/src/pass.rs +++ b/hercules_opt/src/pass.rs @@ -9,7 +9,6 @@ use std::env::temp_dir; use std::fs::File; use std::io::Write; use std::iter::zip; -use std::path::Path; use std::process::{Command, Stdio}; use self::serde::Deserialize; @@ -37,7 +36,10 @@ pub enum Pass { // Useful to set to false if displaying a potentially broken module. Xdot(bool), SchedXdot, - Codegen, + // Parameterized over output directory and module name. + Codegen(String, String), + // Parameterized over where to serialize module to. + Serialize(String), } /* @@ -321,7 +323,7 @@ impl PassManager { } } - pub fn run_passes(&mut self, input_file: &Path) { + pub fn run_passes(&mut self) { for pass in self.passes.clone().iter() { match pass { Pass::DCE => { @@ -536,7 +538,7 @@ impl PassManager { xdot_sched_module(&smodule); } - Pass::Codegen => { + Pass::Codegen(output_dir, module_name) => { self.make_def_uses(); self.make_typing(); self.make_control_subgraphs(); @@ -568,44 +570,45 @@ impl PassManager { println!("{}", llvm_ir); // Write the LLVM IR into a temporary file. - let output_file_prefix = input_file.file_stem().unwrap().to_str().unwrap(); let mut tmp_path = temp_dir(); - tmp_path.push(format!("{}.ll", output_file_prefix)); + tmp_path.push(format!("{}.ll", module_name)); let mut file = File::create(&tmp_path) .expect("PANIC: Unable to open output LLVM IR file."); file.write_all(llvm_ir.as_bytes()) .expect("PANIC: Unable to write output LLVM IR file contents."); + println!("{}", tmp_path.display()); // Compile LLVM IR into an ELF object file. + let output_archive = format!("{}/lib{}.a", output_dir, module_name); let mut clang_process = Command::new("clang") .arg(&tmp_path) .arg("--emit-static-lib") .arg("-O3") .arg("-march=native") .arg("-o") - .arg({ - let mut lib_path = input_file.parent().unwrap().to_path_buf(); - lib_path.push(format!("lib{}.a", output_file_prefix)); - lib_path - }) + .arg(&output_archive) .stdin(Stdio::piped()) .stdout(Stdio::piped()) .spawn() .unwrap(); assert!(clang_process.wait().unwrap().success()); + println!("{}", output_archive); // Package manifest into a file. let hman_contents: Vec<u8> = postcard::to_allocvec(&smodule.manifests).unwrap(); - let mut file = File::create({ - let mut hman_path = input_file.parent().unwrap().to_path_buf(); - hman_path.push(format!("{}.hman", output_file_prefix)); - hman_path - }) - .expect("PANIC: Unable to open output manifest file."); + let mut file = File::create(format!("{}/{}.hman", output_dir, module_name)) + .expect("PANIC: Unable to open output manifest file."); file.write_all(&hman_contents) .expect("PANIC: Unable to write output manifest file contents."); self.manifests = Some(smodule.manifests); } + Pass::Serialize(output_file) => { + let module_contents: Vec<u8> = postcard::to_allocvec(&self.module).unwrap(); + let mut file = File::create(&output_file) + .expect("PANIC: Unable to open output module file."); + file.write_all(&module_contents) + .expect("PANIC: Unable to write output module file contents."); + } } } } diff --git a/hercules_rt_proc/src/lib.rs b/hercules_rt_proc/src/lib.rs index dc9f8f6f..f3df33aa 100644 --- a/hercules_rt_proc/src/lib.rs +++ b/hercules_rt_proc/src/lib.rs @@ -116,7 +116,10 @@ fn compute_dynamic_constant<W: Write>( /* * Generate async Rust code orchestrating partition execution. */ -fn codegen(manifests: &HashMap<String, Manifest>, link_library: &Option<String>) -> Result<String, anyhow::Error> { +fn codegen( + manifests: &HashMap<String, Manifest>, + link_library: &Option<String>, +) -> Result<String, anyhow::Error> { // Write to a String containing all of the Rust code. let mut rust_code = "".to_string(); @@ -481,12 +484,17 @@ pub fn use_hman(path: TokenStream) -> TokenStream { #[proc_macro] pub fn use_hir(hir_tokens: TokenStream) -> TokenStream { - use TokenTree::Literal; use std::env; + use TokenTree::Literal; let mut tokens_iter = hir_tokens.into_iter(); - let token = tokens_iter.next().expect("Please provide Hercules IR to use the use_hir! macro."); - assert!(tokens_iter.next().is_none(), "Too many tokens provided to use the use_hir! macro. Please provide only Hercules IR."); + let token = tokens_iter + .next() + .expect("Please provide Hercules IR to use the use_hir! macro."); + assert!( + tokens_iter.next().is_none(), + "Too many tokens provided to use the use_hir! macro. Please provide only Hercules IR." + ); let literal = if let Literal(literal) = token { literal } else { @@ -494,15 +502,15 @@ pub fn use_hir(hir_tokens: TokenStream) -> TokenStream { }; let literal_string = literal.to_string(); - let module = - hercules_ir::parse::parse(&literal_string[1..(literal_string.len() - 1)]).expect("PANIC: Failed to parse Hercules IR string."); + let module = hercules_ir::parse::parse(&literal_string[1..(literal_string.len() - 1)]) + .expect("PANIC: Failed to parse Hercules IR string."); let out_dir = env::var("OUT_DIR").unwrap(); let libname = format!("hir_generated_{}", uuid::Uuid::new_v4().simple()); let mut p = hercules_opt::pass::PassManager::new(module); - p.add_pass(hercules_opt::pass::Pass::Codegen); + p.add_pass(hercules_opt::pass::Pass::Codegen(out_dir, libname.clone())); - p.run_passes(&std::path::Path::new(&out_dir).join(&libname)); + p.run_passes(); let manifests = p.get_manifests(); let rust_code = codegen(&manifests, &Some(libname)).unwrap(); diff --git a/hercules_samples/matmul/src/main.rs b/hercules_samples/matmul/src/main.rs index 9a84c6ef..1fcee18c 100644 --- a/hercules_samples/matmul/src/main.rs +++ b/hercules_samples/matmul/src/main.rs @@ -5,7 +5,7 @@ extern crate clap; extern crate hercules_rt; // To compile currently, run from the Hercules project root directory: -// cargo run --bin hercules_driver hercules_samples/matmul/matmul.hir "Codegen" +// cargo run --bin hercules_driver hercules_samples/matmul/matmul.hir "Codegen(\"hercules_samples/matmul\",\"matmul\")" // Then, you can execute this example with: // cargo run --bin hercules_matmul hercules_rt::use_hman!("hercules_samples/matmul/matmul.hman"); diff --git a/hercules_tools/hercules_driver/Cargo.toml b/hercules_tools/hercules_driver/Cargo.toml index aa6d4f5e..9236c34a 100644 --- a/hercules_tools/hercules_driver/Cargo.toml +++ b/hercules_tools/hercules_driver/Cargo.toml @@ -6,5 +6,6 @@ authors = ["Russel Arbore <rarbore2@illinois.edu>"] [dependencies] clap = { version = "*", features = ["derive"] } ron = "*" +postcard = { version = "*", features = ["alloc"] } hercules_ir = { path = "../../hercules_ir" } hercules_opt = { path = "../../hercules_opt" } diff --git a/hercules_tools/hercules_driver/src/main.rs b/hercules_tools/hercules_driver/src/main.rs index 70a7bafb..97c9fe2e 100644 --- a/hercules_tools/hercules_driver/src/main.rs +++ b/hercules_tools/hercules_driver/src/main.rs @@ -1,4 +1,5 @@ extern crate clap; +extern crate postcard; use std::fs::File; use std::io::prelude::*; @@ -9,23 +10,37 @@ use clap::Parser; #[derive(Parser, Debug)] #[command(author, version, about, long_about = None)] struct Args { - hir_file: String, + file: String, passes: String, } -fn main() { - let args = Args::parse(); - if !args.hir_file.ends_with(".hir") { - eprintln!("WARNING: Running hercules_driver on a file without a .hir extension - interpreting as a textual Hercules IR file."); - } - - let hir_path = Path::new(&args.hir_file); - let mut file = File::open(hir_path).expect("PANIC: Unable to open input file."); +fn parse_file_from_hir(path: &Path) -> hercules_ir::ir::Module { + let mut file = File::open(path).expect("PANIC: Unable to open input file."); let mut contents = String::new(); file.read_to_string(&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."); + hercules_ir::parse::parse(&contents).expect("PANIC: Failed to parse Hercules IR file.") +} + +fn parse_file_from_hbin(path: &Path) -> hercules_ir::ir::Module { + let mut file = File::open(path).expect("PANIC: Unable to open input file."); + let mut buffer = vec![]; + file.read_to_end(&mut buffer).unwrap(); + postcard::from_bytes(&buffer).unwrap() +} + +fn main() { + let args = Args::parse(); + assert!( + args.file.ends_with(".hir") || args.file.ends_with(".hbin"), + "PANIC: Running hercules_driver on a file without a .hir or .hbin extension." + ); + let path = Path::new(&args.file); + let module = if args.file.ends_with(".hir") { + parse_file_from_hir(path) + } else { + parse_file_from_hbin(path) + }; let mut pm = hercules_opt::pass::PassManager::new(module); let passes: Vec<hercules_opt::pass::Pass> = args @@ -42,5 +57,5 @@ fn main() { for pass in passes { pm.add_pass(pass); } - pm.run_passes(hir_path); + pm.run_passes(); } -- GitLab