diff --git a/Cargo.lock b/Cargo.lock index ff31e6d6b970b17bc0c32a6ac9b1b4ae3a615f23..7cbeacf84634f85cca65a8c06247bbe7d19634fc 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 d618b9b5c210fbdd636b9b4ed42b7434cdc98fb7..63579146428581973a4c93e987160ad415ea0418 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 ab10aedaeb3c680c1c26f3bc425178f34c6485c9..69cd39e388661b3f7f6dca53cf9210ab7050902c 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 47fb55e82fc0266b03c6a7ba94717738038b489c..cfa03fd3b989748fe530071f289fb31f036283b4 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 dbf18713465c10f7fafc7de0e180a6d43f0003a6..3d282ae2568a778edd70fc8cb077ac509f29536e 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 bef11a91f027edf84f1e719538168e4ce8fd21e7..9082a4fc4194ac3fa9c694a5a5973f605772a384 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 f43f9fbd956813de7f530d93c3afbb94a29995c6..49a6024828516f994522e66bf1de1d714f63e75b 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 5e5b4ddefb73835c45b399009e9709b06e056217..e29860ee6942b8cbea3d084d4de0310f7fb6cf2a 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 744b3f596a1007d0e22f55e2975b0357f70c663e..9066c1535e2c40400bdb3b5ca20a3e38237ef597 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 aa4cd97f33d5f06754a3306f2d824e0cf38eb4ea..ec6eb892326c5d6eb341c89239b0465de0cf4a49 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 ac5e96b26e65aa16adc266a784a9a727ce5d76e0..26168d4b55c270b50957b0dc5a8792dbff65c5dc 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 2e35059ef535fc32780d0fbd41bbc6de96771932..4f6234988f7e30ade972933dcec56b29412369ba 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 c40d8de1b255190dcfda5508188eaf577b1c8047..e01a518722d8e074905593f04e14391e0d905a9e 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 1ac61fe519f3a3eb85a09cae26d53e78cbe0230c..96fefb7f0e9d374a48ddc4691545aa9910edaf69 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);