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 在 编程语言
520,745 每月下载量
在 453 个crate中使用(直接使用 18 个)
4.5MB
101K SLoC
此crate提供了一种简单的方法来创建一个Cranelift IR函数,并用从另一种语言翻译的指令填充它。它包含一个SSA构建模块,通过use_var
和def_var
调用提供方便的方法将非SSA变量转换为SSA Cranelift IR值。
lib.rs
:
Cranelift IR 构建库。
提供了一种简单的方法来创建一个Cranelift IR函数,并用与您用另一种语言编写的源程序相对应的指令填充它。
要开始,创建一个FunctionBuilderContext
并将其作为参数传递给FunctionBuilder
。
可变变量和 Cranelift IR 值
这个API最有趣的特点是它提供了一种处理所有变量问题的单一方法。确实,结构体 FunctionBuilder
有一个类型为 Variable
的字段,这个字段应该是你的源语言变量的索引。然后,通过调用函数 declare_var
、def_var
和 use_var
,FunctionBuilder
将为你创建所有与你的变量对应的 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