155 个版本 (96 个破坏性版本)

0.111.0 2024 年 8 月 20 日
0.110.1 2024 年 7 月 22 日
0.106.0 2024 年 3 月 20 日
0.103.0 2023 年 12 月 20 日
0.17.0 2018 年 7 月 24 日

#33编程语言

Download history 109618/week @ 2024-05-02 116457/week @ 2024-05-09 115064/week @ 2024-05-16 121401/week @ 2024-05-23 121579/week @ 2024-05-30 104147/week @ 2024-06-06 117701/week @ 2024-06-13 111051/week @ 2024-06-20 103299/week @ 2024-06-27 108985/week @ 2024-07-04 136479/week @ 2024-07-11 131343/week @ 2024-07-18 116383/week @ 2024-07-25 120311/week @ 2024-08-01 130114/week @ 2024-08-08 131059/week @ 2024-08-15

520,745 每月下载量
453 个crate中使用(直接使用 18 个)

Apache-2.0 WITH LLVM-exception

4.5MB
101K SLoC

此crate提供了一种简单的方法来创建一个Cranelift IR函数,并用从另一种语言翻译的指令填充它。它包含一个SSA构建模块,通过use_vardef_var调用提供方便的方法将非SSA变量转换为SSA Cranelift IR值。


lib.rs:

Cranelift IR 构建库。

提供了一种简单的方法来创建一个Cranelift IR函数,并用与您用另一种语言编写的源程序相对应的指令填充它。

要开始,创建一个FunctionBuilderContext并将其作为参数传递给FunctionBuilder

可变变量和 Cranelift IR 值

这个API最有趣的特点是它提供了一种处理所有变量问题的单一方法。确实,结构体 FunctionBuilder 有一个类型为 Variable 的字段,这个字段应该是你的源语言变量的索引。然后,通过调用函数 declare_vardef_varuse_varFunctionBuilder 将为你创建所有与你的变量对应的 Cranelift IR 值。

这个API被设计用来帮助你将可变变量转换为 SSA 形式。函数 use_var 将返回与程序中特定点上的可变变量对应的 Cranelift IR 值。然而,如果你事先知道其中一个变量只定义了一次,例如它是基于表达式语言中一个中间表达式的结果,那么你可以通过指令构建器返回的 Cranelift IR 值直接转换它。对于这样的不可变变量使用 use_var API 也会起作用,但会有轻微的性能开销(SSA 算法事先不知道变量是否不可变)。

结论是,你应该使用这三个函数来处理所有可变变量,即使它们不在源代码中,而是转换的副产物。保持你的语言中的可变变量和 Cranelift 所使用的 Variable 索引之间的映射是您的责任。注意:因为 Variable 由 Cranelift 用于索引包含关于你的可变变量信息的数组,当你使用 Variable::new(var_index) 创建一个新的 Variable 时,你应该确保 var_index 是每次遇到一个新的可变变量时通过计数器加 1 提供的。

示例

以下是我们想要将其转换为 Cranelift IR 的伪程序

function(x) {
x, y, z : i32
block0:
   y = 2;
   z = x + y;
   jump block1
block1:
   z = z + y;
   brif y, block3, block2
block2:
   z = z - x;
   return y
block3:
   y = y - x
   jump block1
}

以下是如何使用 FunctionBuilderContext 构建相应的 Cranelift IR 函数

use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::types::*;
use cranelift_codegen::ir::{AbiParam, UserFuncName, Function, InstBuilder, Signature};
use cranelift_codegen::isa::CallConv;
use cranelift_codegen::settings;
use cranelift_codegen::verifier::verify_function;
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};

let mut sig = Signature::new(CallConv::SystemV);
sig.returns.push(AbiParam::new(I32));
sig.params.push(AbiParam::new(I32));
let mut fn_builder_ctx = FunctionBuilderContext::new();
let mut func = Function::with_name_signature(UserFuncName::user(0, 0), sig);
{
    let mut builder = FunctionBuilder::new(&mut func, &mut fn_builder_ctx);

    let block0 = builder.create_block();
    let block1 = builder.create_block();
    let block2 = builder.create_block();
    let block3 = builder.create_block();
    let x = Variable::new(0);
    let y = Variable::new(1);
    let z = Variable::new(2);
    builder.declare_var(x, I32);
    builder.declare_var(y, I32);
    builder.declare_var(z, I32);
    builder.append_block_params_for_function_params(block0);

    builder.switch_to_block(block0);
    builder.seal_block(block0);
    {
        let tmp = builder.block_params(block0)[0]; // the first function parameter
        builder.def_var(x, tmp);
    }
    {
        let tmp = builder.ins().iconst(I32, 2);
        builder.def_var(y, tmp);
    }
    {
        let arg1 = builder.use_var(x);
        let arg2 = builder.use_var(y);
        let tmp = builder.ins().iadd(arg1, arg2);
        builder.def_var(z, tmp);
    }
    builder.ins().jump(block1, &[]);

    builder.switch_to_block(block1);
    {
        let arg1 = builder.use_var(y);
        let arg2 = builder.use_var(z);
        let tmp = builder.ins().iadd(arg1, arg2);
        builder.def_var(z, tmp);
    }
    {
        let arg = builder.use_var(y);
        builder.ins().brif(arg, block3, &[], block2, &[]);
    }

    builder.switch_to_block(block2);
    builder.seal_block(block2);
    {
        let arg1 = builder.use_var(z);
        let arg2 = builder.use_var(x);
        let tmp = builder.ins().isub(arg1, arg2);
        builder.def_var(z, tmp);
    }
    {
        let arg = builder.use_var(y);
        builder.ins().return_(&[arg]);
    }

    builder.switch_to_block(block3);
    builder.seal_block(block3);

    {
        let arg1 = builder.use_var(y);
        let arg2 = builder.use_var(x);
        let tmp = builder.ins().isub(arg1, arg2);
        builder.def_var(y, tmp);
    }
    builder.ins().jump(block1, &[]);
    builder.seal_block(block1);

    builder.finalize();
}

let flags = settings::Flags::new(settings::builder());
let res = verify_function(&func, &flags);
println!("{}", func.display());
if let Err(errors) = res {
    panic!("{}", errors);
}

依赖关系

~4.5MB
~83K SLoC