Skip to content

Commit

Permalink
wip
Browse files Browse the repository at this point in the history
  • Loading branch information
doug-q committed Jul 27, 2024
1 parent b73494f commit e59a5c4
Show file tree
Hide file tree
Showing 9 changed files with 1,216 additions and 87 deletions.
852 changes: 768 additions & 84 deletions Cargo.lock

Large diffs are not rendered by default.

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ categories = ["compilers"]
[features]
default = ["llvm14-0"]
llvm14-0 = ["dep:llvm-sys-140", "inkwell/llvm14-0"]
tket2 = ["dep:tket2"]

[dependencies]
inkwell = { version = "0.4.0", default-features=false }
Expand All @@ -31,6 +32,7 @@ lazy_static = "1.4.0"
downcast-rs= "1.2.1"
serde = "1.0"
serde_json = "1.0"
tket2 = { git = "https://github.com/CQCL/tket2.git", optional = true }

[dev-dependencies]
insta = "1.39.0"
Expand All @@ -43,3 +45,5 @@ serde_json = "1.0.117"
insta.opt-level = 3
similar.opt-level = 3

[workspace]
members = ["hugr-llvm-exec"]
21 changes: 21 additions & 0 deletions hugr-llvm-exec/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
[package]
name = "hugr-llvm-exec"
version = "0.1.0"
edition = "2021"

[lib]
crate-type = ["cdylib"]

[dependencies]
qir-backend = { git = "https://github.com/qir-alliance/qir-runner" }
clap = {version = "4.5", features = ["derive"] }
pathsearch = "*"
anyhow = "*"
hugr = "*"
hugr-llvm = { path = "../.", features = ["tket2"] }
tket2 = { git = "https://github.com/CQCL/tket2.git" }
serde_json = "*"
lazy_static = "*"
inkwell = { version = "0.4.0", default-features=false }
libloading = "0.8.5"
findshlibs = "0.10.2"
1 change: 1 addition & 0 deletions hugr-llvm-exec/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
pub use qir_backend::*;
121 changes: 121 additions & 0 deletions hugr-llvm-exec/src/main.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
use std::{error::Error, fs::File, path::{Path, PathBuf}, process::{Command, Stdio}};
use anyhow::{anyhow, Result};

use clap::Parser;
use findshlibs::{Segment, SharedLibrary, TargetSharedLibrary};
use hugr::{extension::ExtensionRegistry, Hugr, extension::prelude,
std_extensions::arithmetic::{float_types, int_ops, int_types}};
use hugr_llvm::{custom::CodegenExtsMap, emit::{EmitHugr, Namer}, fat::FatExt as _};
use inkwell::{module::{Linkage, Module}, targets::{Target, TargetMachine}};
use tket2::extension::TKET2_EXTENSION;
use lazy_static::lazy_static;

lazy_static! {
static ref EXTENSION_REGISTRY: ExtensionRegistry = ExtensionRegistry::try_new([
int_ops::EXTENSION.to_owned(),
int_types::EXTENSION.to_owned(),
prelude::PRELUDE.to_owned(),
float_types::EXTENSION.to_owned(),
TKET2_EXTENSION.to_owned(),
])
.unwrap();
}

#[derive(Parser)]
struct CliArgs {
guppy_file: PathBuf
}

fn guppy(python_bin: impl AsRef<Path>, file: impl AsRef<Path>) -> Result<Hugr> {
let mut guppy_cmd = Command::new(python_bin.as_ref());
guppy_cmd
.arg(file.as_ref())
.stdout(Stdio::piped());
let mut guppy_proc = guppy_cmd.spawn()?;
let mut hugr: Hugr = serde_json::from_reader(guppy_proc.stdout.take().unwrap())?;
if !guppy_proc.wait()?.success() {
Err(anyhow!("Guppy failed"))?;
}
hugr.update_validate(&EXTENSION_REGISTRY).unwrap();
Ok(hugr)
}

// drives `hugr-llvm` to produce an LLVM module from a Hugr.
fn hugr_to_so<'c>(hugr: &'c Hugr) -> Result<()> {
let context = inkwell::context::Context::create();
let module = context.create_module("hugr_llvm_exec");
let namer = Namer::new("_hugr_llvm_exec_.", false);
let exts = CodegenExtsMap::default()
.add_int_extensions()
.add_float_extensions()
.add_tket2_qir_exts();
let root = hugr.fat_root().unwrap();
let module = EmitHugr::new(&context, module, namer.into(), exts.into())
.emit_module(root)?
.finish();
{
let guppy_entry = module.get_function("_hugr_llvm_exec_.main").ok_or(anyhow!("No main function"))?;
let entry = module.add_function("main", context.void_type().fn_type(&[], false), Some(Linkage::External));
let entry_block = context.append_basic_block(entry, "entry");
let builder = context.create_builder();
builder.position_at_end(entry_block);
builder.build_call(guppy_entry, &[], "")?;
builder.build_return(None)?;
}

Target::initialize_native(&Default::default()).map_err(|e| anyhow!("Failed to initialize native target: {}", e))?;
let triple = TargetMachine::get_default_triple();
let target = Target::from_triple(&triple).map_err(|e| anyhow!("Failed to create target: {e}"))?;
let cpu = TargetMachine::get_host_cpu_name().to_string();
let cpu_features = TargetMachine::get_host_cpu_features().to_string();
let machine = target.create_target_machine(&triple, &cpu, &cpu_features, inkwell::OptimizationLevel::None, inkwell::targets::RelocMode::PIC, inkwell::targets::CodeModel::Default).ok_or(anyhow!("Failed to create target machine"))?;

machine.write_to_file(&module, inkwell::targets::FileType::Object, &PathBuf::from("hugr_llvm_exec.o")).map_err(|e| anyhow!("Failed to write object file: {}", e))?;

if !Command::new("gcc")
.arg("-Wl,-lhugr_llvm_exec")
.arg("hugr_llvm_exec.o")
.arg("-o")
.arg("hugr_llvm_exec")
.status()?.success() {
Err(anyhow!("Failed to link object file"))?;
}
Ok(())
}

fn run(lib: impl AsRef<Path>, entry: impl AsRef<str>) -> Result<()> {
unsafe {
let runtime = libloading::Library::new("libhugr_llvm_exec.so")?;
let lib = libloading::Library::new(&format!("./{}", lib.as_ref().to_string_lossy()))?;

let func: libloading::Symbol<unsafe extern "C" fn()> = lib.get(entry.as_ref().as_bytes())?;
TargetSharedLibrary::each(|shlib| {
println!("{}", shlib.name().to_string_lossy());

for seg in shlib.segments() {
println!(" {}: segment {}",
seg.actual_virtual_memory_address(shlib),
seg.name().to_string());
}
});
Ok(func())
}
}

fn main_impl(args: CliArgs) -> Result<()> {
let python = pathsearch::find_executable_in_path("python3").ok_or(anyhow!("Failed to find python3 executable"))?;
if !args.guppy_file.exists() {
Err(anyhow!("Guppy file does not exist: {:?}", args.guppy_file))?;
}
let hugr = guppy(python, args.guppy_file)?;
hugr_to_so(&hugr)?;
run("hugr_llvm_exec.so", "_hugr_llvm_exec_entry")?;
Ok(())
}

fn main() {
if let Err(e) = main_impl(CliArgs::parse()) {
eprintln!("Error: {}", e);
std::process::exit(1);
}
}
2 changes: 2 additions & 0 deletions src/custom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ use super::emit::EmitOp;
pub mod float;
pub mod int;
pub mod prelude;
#[cfg(feature="tket2")]
pub mod tket2_qir;

/// The extension point for lowering HUGR Extensions to LLVM.
pub trait CodegenExtension<'c, H> {
Expand Down
Loading

0 comments on commit e59a5c4

Please sign in to comment.