diff --git a/Cargo.lock b/Cargo.lock index 4e695c7..3b5f9b8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1415,6 +1415,13 @@ checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" name = "revive-builtins" version = "0.1.0" +[[package]] +name = "revive-extensions" +version = "0.1.0" +dependencies = [ + "inkwell", +] + [[package]] name = "revive-integration" version = "0.1.0" diff --git a/crates/extensions/Cargo.toml b/crates/extensions/Cargo.toml new file mode 100644 index 0000000..06fc411 --- /dev/null +++ b/crates/extensions/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "revive-extensions" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +inkwell = { workspace = true, no-default-features = true, features = ["target-riscv", "no-libffi-linking", "llvm16-0"] } diff --git a/crates/extensions/bswap.ll b/crates/extensions/bswap.ll new file mode 100644 index 0000000..36a4b4a --- /dev/null +++ b/crates/extensions/bswap.ll @@ -0,0 +1,13 @@ +target datalayout = "e-m:e-p:32:32-i64:64-n32-S128" +target triple = "riscv32-unknown-unknown-elf" + +define dso_local noundef i256 @__bswap(i256 noundef %0) local_unnamed_addr #0 { + %2 = tail call i256 @llvm.bswap.i256(i256 %0) + ret i256 %2 +} + +; Function Attrs: mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) +declare i256 @llvm.bswap.i256(i256) #1 + +attributes #0 = { alwaysinline mustprogress nofree norecurse nosync nounwind willreturn memory(none) } +attributes #1 = { mustprogress nocallback nofree nosync nounwind speculatable willreturn memory(none) } diff --git a/crates/extensions/build.rs b/crates/extensions/build.rs new file mode 100644 index 0000000..c7b657a --- /dev/null +++ b/crates/extensions/build.rs @@ -0,0 +1,40 @@ +use std::{env, fs, path::Path, process::Command}; + +fn compile(source_path: &str, output_path: &str) { + let output = Command::new("llc") + .args([ + "-O3", + "-filetype=asm", + "-mattr=+zbb,+e", + source_path, + "-o", + output_path, + ]) + .output() + .expect("should be able to invoke llc"); + + assert!( + output.status.success(), + "failed to compile {}: {:?}", + source_path, + output + ); +} + +fn main() { + let in_file = "bswap.ll"; + let out_file = "bswap.s"; + let out_dir = env::var_os("OUT_DIR").expect("env should have $OUT_DIR"); + let out_path = Path::new(&out_dir).join(out_file); + compile( + in_file, + out_path.to_str().expect("$OUT_DIR should be UTF-8"), + ); + + let src_path = Path::new(&out_dir).join("bswap.rs"); + let src = format!("pub static ASSEMBLY: &str = include_str!(\"{out_file}\");"); + fs::write(src_path, src).expect("should be able to write in $OUT_DIR"); + + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rerun-if-changed=bswap.ll"); +} diff --git a/crates/extensions/src/lib.rs b/crates/extensions/src/lib.rs new file mode 100644 index 0000000..171705b --- /dev/null +++ b/crates/extensions/src/lib.rs @@ -0,0 +1,40 @@ +//! Custom RISC-V extension in PolkaVM that are partially supported. +//! We use inline assembly to emit partially supported instructions. + +use inkwell::{context::Context, module::Module, support::LLVMString}; + +include!(concat!(env!("OUT_DIR"), "/bswap.rs")); + +/// Returns a LLVM module containing a `__bswap` function, which +/// - Takes a `i256` value argument +/// - Byte swaps it using `rev8` from the `zbb` extension +/// - Returns the `i256` value +/// +/// Returns `Error` if the module fails to validate, which should never happen. +pub fn module<'context>( + context: &'context Context, + module_name: &str, +) -> Result, LLVMString> { + let module = context.create_module(module_name); + + module.set_inline_assembly(ASSEMBLY); + module.verify()?; + + Ok(module) +} + +#[cfg(test)] +mod tests { + #[test] + fn assembly_contains_rev8_instruction() { + assert!(crate::ASSEMBLY.contains("rev8")); + } + + #[test] + fn module_is_valid() { + inkwell::targets::Target::initialize_riscv(&Default::default()); + let context = inkwell::context::Context::create(); + + assert!(crate::module(&context, "polkavm_bswap").is_ok()); + } +} diff --git a/crates/linker/polkavm_guest.bc b/crates/linker/polkavm_guest.bc deleted file mode 100644 index fa532df..0000000 Binary files a/crates/linker/polkavm_guest.bc and /dev/null differ