3 个版本
0.1.2 | 2022年7月12日 |
---|---|
0.1.1 | 2022年7月12日 |
0.1.0 | 2021年12月18日 |
#149 在 FFI 中
每月 34 次下载
用于 firework_lang
725KB
12K SLoC
Inkwell(s)
It's a New Kind of Wrapper for Exposing LLVM (Safely)
Inkwell旨在通过安全封装llvm-sys来帮助您编写自己的编程语言。它提供了比底层LLVM C API更严格的接口,以便在某些类型的错误可以在编译时而不是在LLVM的运行时被捕获。这意味着我们正在尝试尽可能紧密地复制LLVM IR的强类型。最终目标是使LLVM从Rust端更安全,并且更容易学习(通过文档)和使用。
要求
- Rust 1.42+
- Rust稳定版、Beta版或Nightly版
- LLVM 12.0
用法
您需要将Cargo.toml指向crates.io上的现有预览crate或具有相应LLVM功能标志的主分支
cargo add inkwell_llvm12
请注意,由于我们处于预v1.0.0版本,我们可能会不时在主分支上做出破坏性更改,以符合semver。请尽可能选择crates.io发布版!
文档
文档基于master自动部署到此处。这些文档尚未100%完整,并且仅显示最新的支持LLVM版本,这是由于rustdoc问题。有关更多信息,请参阅#2。
示例
Tari的llvm-sys示例,使用Inkwell以安全代码编写1。
extern inkwell_llvm12 as inkwell;
use inkwell::OptimizationLevel;
use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::execution_engine::{ExecutionEngine, JitFunction};
use inkwell::module::Module;
use inkwell::targets::{InitializationConfig, Target};
use std::error::Error;
/// Convenience type alias for the `sum` function.
///
/// Calling this is innately `unsafe` because there's no guarantee it doesn't
/// do `unsafe` operations internally.
type SumFunc = unsafe extern "C" fn(u64, u64, u64) -> u64;
struct CodeGen<'ctx> {
context: &'ctx Context,
module: Module<'ctx>,
builder: Builder<'ctx>,
execution_engine: ExecutionEngine<'ctx>,
}
impl<'ctx> CodeGen<'ctx> {
fn jit_compile_sum(&self) -> Option<JitFunction<SumFunc>> {
let i64_type = self.context.i64_type();
let fn_type = i64_type.fn_type(&[i64_type.into(), i64_type.into(), i64_type.into()], false);
let function = self.module.add_function("sum", fn_type, None);
let basic_block = self.context.append_basic_block(function, "entry");
self.builder.position_at_end(basic_block);
let x = function.get_nth_param(0)?.into_int_value();
let y = function.get_nth_param(1)?.into_int_value();
let z = function.get_nth_param(2)?.into_int_value();
let sum = self.builder.build_int_add(x, y, "sum");
let sum = self.builder.build_int_add(sum, z, "sum");
self.builder.build_return(Some(&sum));
unsafe { self.execution_engine.get_function("sum").ok() }
}
}
fn main() -> Result<(), Box<dyn Error>> {
let context = Context::create();
let module = context.create_module("sum");
let execution_engine = module.create_jit_execution_engine(OptimizationLevel::None)?;
let codegen = CodeGen {
context: &context,
module,
builder: context.create_builder(),
execution_engine,
};
let sum = codegen.jit_compile_sum().ok_or("Unable to JIT compile `sum`")?;
let x = 1u64;
let y = 2u64;
let z = 3u64;
unsafe {
println!("{} + {} + {} = {}", x, y, z, sum.call(x, y, z));
assert_eq!(sum.call(x, y, z), x + y + z);
}
Ok(())
}
1 在这个例子中,unsafe
有两种用法,因为实际编译和即时执行代码的行为本质上就是 unsafe
。一方面,我们无法验证是否用正确的函数签名调用了 get_function()
。另外,调用我们获取的函数也是 unsafe
的,因为没有保证该代码本身在内部不会执行 unsafe
操作(这与调用 C 代码时需要 unsafe
的原因相同)。
LLVM的Kaleidoscope教程
可以在示例目录中找到。
其他包
贡献
查看我们的贡献指南
依赖
~1.7–2.5MB
~51K SLoC