#llvm #safe-wrapper #wrapper #safe #programming-language #strong-typing #compile-time

llvm-plugin-inkwell

Inkwell旨在通过安全封装 llvm-sys 帮助您编写自己的编程语言。

6个版本

0.3.0 2023年4月30日
0.2.1 2023年1月21日
0.1.2 2022年9月13日

#172 in FFI

Download history 7/week @ 2024-03-11 1/week @ 2024-03-18 26/week @ 2024-04-01 5/week @ 2024-05-20

每月 142 次下载

Apache-2.0

795KB
12K SLoC

Inkwell(s)

Crates.io Build Status codecov lines of code Join the chat at https://gitter.im/inkwell-rs/Lobby Minimum rustc 1.56

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