6个版本
0.3.0 | 2023年4月30日 |
---|---|
0.2.1 | 2023年1月21日 |
0.1.2 | 2022年9月13日 |
#172 in FFI
每月 142 次下载
795KB
12K SLoC
Inkwell(s)
It's a New Kind of Wrapper for Eexposing LLVM (Safely)
Inkwell旨在通过安全封装 llvm-sys 帮助您编写自己的编程语言。它提供了一个比底层LLVM C API更强的类型接口,以便在编译时而不是在LLVM的运行时捕获某些类型的错误。这意味着我们试图尽可能地复制LLVM IR的强类型。最终目标是使LLVM从Rust端更安全,并且稍微容易学习(通过文档)和使用。
要求
- Rust 1.56+ (稳定、Beta或Nightly)
- LLVM 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0或15.0
使用方法
您需要将您的Cargo.toml指向crates.io上现有的预览crate或具有相应LLVM功能标志的主分支
[dependencies]
inkwell = { package = "llvm-plugin-inkwell", version = "0.2", features = ["llvm12-0"] }
支持的版本
LLVM版本 | Cargo功能标志 |
---|---|
4.0.x | llvm4-0 |
5.0.x | llvm5-0 |
6.0.x | llvm6-0 |
7.0.x | llvm7-0 |
8.0.x | llvm8-0 |
9.0.x | llvm9-0 |
10.0.x | llvm10-0 |
11.0.x | llvm11-0 |
12.0.x | llvm12-0 |
13.0.x | llvm13-0 |
14.0.x | llvm14-0 |
15.0.x | llvm15-0 |
请注意,由于我们处于预v1.0.0阶段,我们可能会在主分支上进行一些破坏性更改,以符合semver。请尽可能选择crates.io发布版!
示例
Tari的llvm-sys示例使用Inkwell编写了安全的代码1
use inkwell::OptimizationLevel;
use inkwell::builder::Builder;
use inkwell::context::Context;
use inkwell::execution_engine::{ExecutionEngine, JitFunction};
use inkwell::module::Module;
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
有两种用法,因为实时编译和执行代码的行为本质上是不安全的。一方面,我们无法验证是否以正确的函数签名调用 get_function()
。另外,调用我们得到的函数也是不安全的,因为没有保证代码本身在内部不会执行不安全的行为(这与调用 C 时需要 unsafe
的原因相同)。
LLVM 的 Kaleidoscope 教程
可在示例目录中找到。
其他 crate
贡献
查看我们的 贡献指南
依赖项
~0.8–7MB
~35K SLoC