From 47e92dd2fddb75143172db8816f0ad61a2146b01 Mon Sep 17 00:00:00 2001 From: Aaron Councilman <aaronjc4@illinois.edu> Date: Sun, 17 Nov 2024 11:28:56 -0600 Subject: [PATCH] Add ability to compile .hir file through Juno Compiler --- Cargo.lock | 25 +++++ Cargo.toml | 6 +- hercules_samples/dot/Cargo.toml | 5 + hercules_samples/dot/build.rs | 16 ++- hercules_samples/dot/{ => src}/dot.hir | 0 hercules_samples/dot/src/main.rs | 8 +- hercules_samples/fac/Cargo.toml | 5 + hercules_samples/fac/build.rs | 16 ++- hercules_samples/fac/{ => src}/fac.hir | 0 hercules_samples/fac/src/main.rs | 8 +- hercules_samples/matmul/Cargo.toml | 5 + hercules_samples/matmul/build.rs | 16 ++- hercules_samples/matmul/src/main.rs | 8 +- hercules_samples/matmul/{ => src}/matmul.hir | 0 juno_build/Cargo.toml | 1 + juno_build/src/lib.rs | 100 ++++++++++++++++--- juno_frontend/src/lib.rs | 48 +++++++-- 17 files changed, 194 insertions(+), 73 deletions(-) rename hercules_samples/dot/{ => src}/dot.hir (100%) rename hercules_samples/fac/{ => src}/fac.hir (100%) rename hercules_samples/matmul/{ => src}/matmul.hir (100%) diff --git a/Cargo.lock b/Cargo.lock index ff31e6d6..7cbeacf8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -369,6 +369,18 @@ dependencies = [ "powerfmt", ] +[[package]] +name = "dot" +version = "0.1.0" +dependencies = [ + "async-std", + "clap", + "hercules_rt", + "juno_build", + "rand", + "with_builtin_macros", +] + [[package]] name = "either" version = "1.13.0" @@ -682,6 +694,7 @@ dependencies = [ name = "juno_build" version = "0.1.0" dependencies = [ + "hercules_ir", "hercules_rt", "juno_frontend", "with_builtin_macros", @@ -835,6 +848,18 @@ dependencies = [ "vob", ] +[[package]] +name = "matmul" +version = "0.1.0" +dependencies = [ + "async-std", + "clap", + "hercules_rt", + "juno_build", + "rand", + "with_builtin_macros", +] + [[package]] name = "memchr" version = "2.7.4" diff --git a/Cargo.toml b/Cargo.toml index d618b9b5..63579146 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,8 +12,8 @@ members = [ #"hercules_test/hercules_interpreter", #"hercules_test/hercules_tests", - #"hercules_samples/dot", - #"hercules_samples/matmul", + "hercules_samples/dot", + "hercules_samples/matmul", #"hercules_samples/fac", "juno_frontend", @@ -22,4 +22,4 @@ members = [ #"juno_samples/matmul", "juno_samples/simple3", -] \ No newline at end of file +] diff --git a/hercules_samples/dot/Cargo.toml b/hercules_samples/dot/Cargo.toml index ab10aeda..69cd39e3 100644 --- a/hercules_samples/dot/Cargo.toml +++ b/hercules_samples/dot/Cargo.toml @@ -4,8 +4,13 @@ version = "0.1.0" authors = ["Russel Arbore <rarbore2@illinois.edu>"] edition = "2021" +[build-dependencies] +juno_build = { path = "../../juno_build" } + [dependencies] clap = { version = "*", features = ["derive"] } +juno_build = { path = "../../juno_build" } hercules_rt = { path = "../../hercules_rt" } rand = "*" async-std = "*" +with_builtin_macros = "0.1.0" diff --git a/hercules_samples/dot/build.rs b/hercules_samples/dot/build.rs index 47fb55e8..cfa03fd3 100644 --- a/hercules_samples/dot/build.rs +++ b/hercules_samples/dot/build.rs @@ -1,12 +1,10 @@ -use std::env::current_dir; +extern crate juno_build; +use juno_build::JunoCompiler; fn main() { - println!( - "cargo::rustc-link-search=native={}", - current_dir().unwrap().display() - ); - println!("cargo::rustc-link-lib=static=dot"); - - println!("cargo::rerun-if-changed=dot.hman"); - println!("cargo::rerun-if-changed=libdot.a"); + JunoCompiler::new() + .ir_in_src("dot.hir") + .unwrap() + .build() + .unwrap(); } diff --git a/hercules_samples/dot/dot.hir b/hercules_samples/dot/src/dot.hir similarity index 100% rename from hercules_samples/dot/dot.hir rename to hercules_samples/dot/src/dot.hir diff --git a/hercules_samples/dot/src/main.rs b/hercules_samples/dot/src/main.rs index dbf18713..3d282ae2 100644 --- a/hercules_samples/dot/src/main.rs +++ b/hercules_samples/dot/src/main.rs @@ -1,12 +1,8 @@ extern crate async_std; extern crate clap; -extern crate hercules_rt; +extern crate juno_build; -// To compile currently, run from the Hercules project root directory: -// cargo run --bin hercules_driver hercules_samples/dot/dot.hir "Codegen(\"hercules_samples/dot\",\"dot\")" -// Then, you can execute this example with: -// cargo run --bin dot -hercules_rt::use_hman!("hercules_samples/dot/dot.hman"); +juno_build::juno!("dot"); fn main() { async_std::task::block_on(async { diff --git a/hercules_samples/fac/Cargo.toml b/hercules_samples/fac/Cargo.toml index bef11a91..9082a4fc 100644 --- a/hercules_samples/fac/Cargo.toml +++ b/hercules_samples/fac/Cargo.toml @@ -4,8 +4,13 @@ version = "0.1.0" authors = ["Russel Arbore <rarbore2@illinois.edu>"] edition = "2021" +[build-dependencies] +juno_build = { path = "../../juno_build" } + [dependencies] clap = { version = "*", features = ["derive"] } +juno_build = { path = "../../juno_build" } hercules_rt = { path = "../../hercules_rt" } rand = "*" async-std = "*" +with_builtin_macros = "0.1.0" diff --git a/hercules_samples/fac/build.rs b/hercules_samples/fac/build.rs index f43f9fbd..49a60248 100644 --- a/hercules_samples/fac/build.rs +++ b/hercules_samples/fac/build.rs @@ -1,12 +1,10 @@ -use std::env::current_dir; +extern crate juno_build; +use juno_build::JunoCompiler; fn main() { - println!( - "cargo::rustc-link-search=native={}", - current_dir().unwrap().display() - ); - println!("cargo::rustc-link-lib=static=fac"); - - println!("cargo::rerun-if-changed=fac.hman"); - println!("cargo::rerun-if-changed=libfac.a"); + JunoCompiler::new() + .ir_in_src("fac.hir") + .unwrap() + .build() + .unwrap(); } diff --git a/hercules_samples/fac/fac.hir b/hercules_samples/fac/src/fac.hir similarity index 100% rename from hercules_samples/fac/fac.hir rename to hercules_samples/fac/src/fac.hir diff --git a/hercules_samples/fac/src/main.rs b/hercules_samples/fac/src/main.rs index 5e5b4dde..e29860ee 100644 --- a/hercules_samples/fac/src/main.rs +++ b/hercules_samples/fac/src/main.rs @@ -1,12 +1,8 @@ extern crate async_std; extern crate clap; -extern crate hercules_rt; +extern crate juno_build; -// To compile currently, run from the Hercules project root directory: -// cargo run --bin hercules_driver hercules_samples/fac/fac.hir "Codegen(\"hercules_samples/fac\",\"fac\")" -// Then, you can execute this example with: -// cargo run --bin fac -hercules_rt::use_hman!("hercules_samples/fac/fac.hman"); +juno_build::juno!("fac"); fn main() { async_std::task::block_on(async { diff --git a/hercules_samples/matmul/Cargo.toml b/hercules_samples/matmul/Cargo.toml index 744b3f59..9066c153 100644 --- a/hercules_samples/matmul/Cargo.toml +++ b/hercules_samples/matmul/Cargo.toml @@ -4,8 +4,13 @@ version = "0.1.0" authors = ["Russel Arbore <rarbore2@illinois.edu>"] edition = "2021" +[build-dependencies] +juno_build = { path = "../../juno_build" } + [dependencies] clap = { version = "*", features = ["derive"] } +juno_build = { path = "../../juno_build" } hercules_rt = { path = "../../hercules_rt" } rand = "*" async-std = "*" +with_builtin_macros = "0.1.0" diff --git a/hercules_samples/matmul/build.rs b/hercules_samples/matmul/build.rs index aa4cd97f..ec6eb892 100644 --- a/hercules_samples/matmul/build.rs +++ b/hercules_samples/matmul/build.rs @@ -1,12 +1,10 @@ -use std::env::current_dir; +extern crate juno_build; +use juno_build::JunoCompiler; fn main() { - println!( - "cargo::rustc-link-search=native={}", - current_dir().unwrap().display() - ); - println!("cargo::rustc-link-lib=static=matmul"); - - println!("cargo::rerun-if-changed=matmul.hman"); - println!("cargo::rerun-if-changed=libmatmul.a"); + JunoCompiler::new() + .ir_in_src("matmul.hir") + .unwrap() + .build() + .unwrap(); } diff --git a/hercules_samples/matmul/src/main.rs b/hercules_samples/matmul/src/main.rs index ac5e96b2..26168d4b 100644 --- a/hercules_samples/matmul/src/main.rs +++ b/hercules_samples/matmul/src/main.rs @@ -2,13 +2,9 @@ extern crate async_std; extern crate clap; -extern crate hercules_rt; +extern crate juno_build; -// To compile currently, run from the Hercules project root directory: -// 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 matmul -hercules_rt::use_hman!("hercules_samples/matmul/matmul.hman"); +juno_build::juno!("matmul"); fn main() { async_std::task::block_on(async { diff --git a/hercules_samples/matmul/matmul.hir b/hercules_samples/matmul/src/matmul.hir similarity index 100% rename from hercules_samples/matmul/matmul.hir rename to hercules_samples/matmul/src/matmul.hir diff --git a/juno_build/Cargo.toml b/juno_build/Cargo.toml index 2e35059e..4f623498 100644 --- a/juno_build/Cargo.toml +++ b/juno_build/Cargo.toml @@ -7,4 +7,5 @@ edition = "2021" [dependencies] juno_frontend = { path = "../juno_frontend" } hercules_rt = { path = "../hercules_rt" } +hercules_ir = { path = "../hercules_ir" } with_builtin_macros = "0.1.0" diff --git a/juno_build/src/lib.rs b/juno_build/src/lib.rs index c40d8de1..e01a5187 100644 --- a/juno_build/src/lib.rs +++ b/juno_build/src/lib.rs @@ -1,16 +1,21 @@ +extern crate hercules_ir; extern crate hercules_rt; + use juno_compiler::*; use std::env::{current_dir, var}; use std::fmt::Write; -use std::fs::create_dir_all; +use std::fs::{create_dir_all, read_to_string}; use std::path::{Path, PathBuf}; use with_builtin_macros::with_builtin; // JunoCompiler is used to compile juno files into a library and manifest file appropriately to // import the definitions into a rust project via the juno! macro defined below +// You can also specify a Hercules IR file instead of a Juno file and this will compile that IR +// file (though in that case a schedule is not supported) pub struct JunoCompiler { + ir_src_path: Option<PathBuf>, src_path: Option<PathBuf>, out_path: Option<PathBuf>, verify: JunoVerify, @@ -21,6 +26,7 @@ pub struct JunoCompiler { impl JunoCompiler { pub fn new() -> Self { JunoCompiler { + ir_src_path: None, src_path: None, out_path: None, verify: JunoVerify::None, @@ -32,6 +38,33 @@ impl JunoCompiler { // Sets the name of the Juno file, this file should be contained in the src/ // file of the package that the JunoCompiler is used in the build script of pub fn file_in_src<P>(mut self, file: P) -> Result<Self, String> + where + P: AsRef<Path>, + { + self.src_path = Some(Self::make_src_path(&file)?); + self.ir_src_path = None; + self.out_path = Some(Self::get_out_path(&file)?); + Self::print_cargo_info(file); + + Ok(self) + } + + // Sets the name of the input Hercules IR file which is contained in the src/ directory of the + // package that the JunoCompiler is used in the build script of + pub fn ir_in_src<P>(mut self, file: P) -> Result<Self, String> + where + P: AsRef<Path>, + { + self.ir_src_path = Some(Self::make_src_path(&file)?); + self.src_path = None; + self.out_path = Some(Self::get_out_path(&file)?); + Self::print_cargo_info(file); + + Ok(self) + } + + // Construct the path to a file in the source directory + fn make_src_path<P>(file: P) -> Result<PathBuf, String> where P: AsRef<Path>, { @@ -48,34 +81,45 @@ impl JunoCompiler { }; path.push("src"); path.push(file.as_ref()); - self.src_path = Some(path); - // We also set the output file in this process, under the OUT_DIR cargo provides + Ok(path) + } + + // Construct the path to the output directory, under the OUT_DIR cargo provides + fn get_out_path<P>(file: P) -> Result<PathBuf, String> + where + P: AsRef<Path>, + { let mut out = PathBuf::new(); out.push(var("OUT_DIR").unwrap()); out.push(file.as_ref().parent().unwrap().to_str().unwrap()); let Ok(()) = create_dir_all(&out) else { return Err("Failed to create output directory.".to_string()); }; - self.out_path = Some(out); + Ok(out) + } - // Tell cargo to rerun if the Juno file changes + // Prints information to tell cargo the following + // - Rerun if the source file changes + // - Add the output directory to its linker search + // - Link the compiled library file + // Tell cargo to rerun if the Juno file changes + fn print_cargo_info<P>(src_file: P) + where + P: AsRef<Path>, + { println!( "cargo::rerun-if-changed=src/{}", - file.as_ref().to_str().unwrap() + src_file.as_ref().to_str().unwrap() ); - // Tell cargo to include the output directory in its linker search - // (and to link the resulting library) println!( "cargo::rustc-link-search=native={}", var("OUT_DIR").unwrap() ); println!( "cargo::rustc-link-lib=static={}", - file.as_ref().file_stem().unwrap().to_str().unwrap() + src_file.as_ref().file_stem().unwrap().to_str().unwrap() ); - - Ok(self) } pub fn verify(mut self, enabled: bool) -> Self { @@ -139,7 +183,8 @@ impl JunoCompiler { // Builds the juno file into a libary and a manifest file. pub fn build(self) -> Result<(), String> { let JunoCompiler { - src_path: Some(src_path), + ir_src_path: ir_src_path, + src_path: src_path, out_path: Some(out_path), verify, x_dot, @@ -149,12 +194,35 @@ impl JunoCompiler { return Err("No source file specified.".to_string()); }; - let src_file = src_path.to_str().unwrap().to_string(); let out_dir = out_path.to_str().unwrap().to_string(); - match compile(src_file, verify, x_dot, schedule, out_dir) { - Ok(()) => Ok(()), - Err(errs) => Err(format!("{}", errs)), + if let Some(src_path) = src_path { + let src_file = src_path.to_str().unwrap().to_string(); + + match compile(src_file, verify, x_dot, schedule, out_dir) { + Ok(()) => Ok(()), + Err(errs) => Err(format!("{}", errs)), + } + } else { + let Some(ir_src_path) = ir_src_path else { + return Err("No source file specified.".to_string()); + }; + + let ir_src_file = ir_src_path.to_str().unwrap().to_string(); + let ir_src_path = Path::new(&ir_src_file); + let module_name = String::from(ir_src_path.file_stem().unwrap().to_str().unwrap()); + + let Ok(contents) = read_to_string(&ir_src_path) else { + return Err("Unable to open and read input file.".to_string()); + }; + let Ok(ir_mod) = hercules_ir::parse::parse(&contents) else { + return Err("Unable to parse Hercules IR file.".to_string()); + }; + + match compile_ir(ir_mod, None, verify, x_dot, schedule, out_dir, module_name) { + Ok(()) => Ok(()), + Err(errs) => Err(format!("{}", errs)), + } } } } diff --git a/juno_frontend/src/lib.rs b/juno_frontend/src/lib.rs index 1ac61fe5..96fefb7f 100644 --- a/juno_frontend/src/lib.rs +++ b/juno_frontend/src/lib.rs @@ -14,6 +14,8 @@ extern crate hercules_ir; use std::fmt; use std::path::Path; +use juno_scheduler::FunctionMap; + pub enum JunoVerify { None, JunoOpts, @@ -96,6 +98,26 @@ pub fn compile( }; let (module, func_info) = codegen::codegen_program(prg); + compile_ir( + module, + Some(func_info), + verify, + x_dot, + schedule, + output_dir, + module_name, + ) +} + +pub fn compile_ir( + module: hercules_ir::ir::Module, + func_info: Option<FunctionMap>, + verify: JunoVerify, + x_dot: bool, + schedule: JunoSchedule, + output_dir: String, + module_name: String, +) -> Result<(), ErrorMessage> { let mut pm = match schedule { JunoSchedule::None => hercules_opt::pass::PassManager::new(module), JunoSchedule::DefaultSchedule => { @@ -103,16 +125,24 @@ pub fn compile( pm.make_plans(); pm } - JunoSchedule::Schedule(file) => match juno_scheduler::schedule(&module, func_info, file) { - Ok(plans) => { - let mut pm = hercules_opt::pass::PassManager::new(module); - pm.set_plans(plans); - pm - } - Err(msg) => { - return Err(ErrorMessage::SchedulingError(msg)); + JunoSchedule::Schedule(file) => { + let Some(func_info) = func_info else { + return Err(ErrorMessage::SchedulingError( + "Cannot schedule, no function information provided".to_string(), + )); + }; + + match juno_scheduler::schedule(&module, func_info, file) { + Ok(plans) => { + let mut pm = hercules_opt::pass::PassManager::new(module); + pm.set_plans(plans); + pm + } + Err(msg) => { + return Err(ErrorMessage::SchedulingError(msg)); + } } - }, + } }; if verify.verify() || verify.verify_all() { pm.add_pass(hercules_opt::pass::Pass::Verify); -- GitLab