Added FunctionBuilder::{call_memcpy, call_memset, call_memmove}
This commit is contained in:
@@ -38,6 +38,12 @@ pub enum LibCall {
|
|||||||
NearestF32,
|
NearestF32,
|
||||||
/// nearest.f64
|
/// nearest.f64
|
||||||
NearestF64,
|
NearestF64,
|
||||||
|
/// libc.memcpy
|
||||||
|
Memcpy,
|
||||||
|
/// libc.memset
|
||||||
|
Memset,
|
||||||
|
/// libc.memmove
|
||||||
|
Memmove,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for LibCall {
|
impl fmt::Display for LibCall {
|
||||||
@@ -60,6 +66,9 @@ impl FromStr for LibCall {
|
|||||||
"TruncF64" => Ok(LibCall::TruncF64),
|
"TruncF64" => Ok(LibCall::TruncF64),
|
||||||
"NearestF32" => Ok(LibCall::NearestF32),
|
"NearestF32" => Ok(LibCall::NearestF32),
|
||||||
"NearestF64" => Ok(LibCall::NearestF64),
|
"NearestF64" => Ok(LibCall::NearestF64),
|
||||||
|
"Memcpy" => Ok(LibCall::Memcpy),
|
||||||
|
"Memset" => Ok(LibCall::Memset),
|
||||||
|
"Memmove" => Ok(LibCall::Memmove),
|
||||||
_ => Err(()),
|
_ => Err(()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -80,6 +80,9 @@ impl FaerieBuilder {
|
|||||||
ir::LibCall::TruncF64 => "trunc".to_owned(),
|
ir::LibCall::TruncF64 => "trunc".to_owned(),
|
||||||
ir::LibCall::NearestF32 => "nearbyintf".to_owned(),
|
ir::LibCall::NearestF32 => "nearbyintf".to_owned(),
|
||||||
ir::LibCall::NearestF64 => "nearbyint".to_owned(),
|
ir::LibCall::NearestF64 => "nearbyint".to_owned(),
|
||||||
|
ir::LibCall::Memcpy => "memcpy".to_owned(),
|
||||||
|
ir::LibCall::Memset => "memset".to_owned(),
|
||||||
|
ir::LibCall::Memmove => "memmove".to_owned(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ readme = "README.md"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
cranelift-codegen = { path = "../codegen", version = "0.22.0", default-features = false }
|
cranelift-codegen = { path = "../codegen", version = "0.22.0", default-features = false }
|
||||||
|
target-lexicon = { version = "0.0.3", default-features = false }
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
|
|||||||
@@ -4,9 +4,9 @@ use cranelift_codegen::entity::{EntityMap, EntitySet};
|
|||||||
use cranelift_codegen::ir;
|
use cranelift_codegen::ir;
|
||||||
use cranelift_codegen::ir::function::DisplayFunction;
|
use cranelift_codegen::ir::function::DisplayFunction;
|
||||||
use cranelift_codegen::ir::{
|
use cranelift_codegen::ir::{
|
||||||
DataFlowGraph, Ebb, ExtFuncData, FuncRef, Function, GlobalValue, GlobalValueData, Heap,
|
types, AbiParam, DataFlowGraph, Ebb, ExtFuncData, ExternalName, FuncRef, Function, GlobalValue,
|
||||||
HeapData, Inst, InstBuilderBase, InstructionData, JumpTable, JumpTableData, SigRef, Signature,
|
GlobalValueData, Heap, HeapData, Inst, InstBuilder, InstBuilderBase, InstructionData,
|
||||||
StackSlot, StackSlotData, Type, Value,
|
JumpTable, JumpTableData, LibCall, SigRef, Signature, StackSlot, StackSlotData, Type, Value,
|
||||||
};
|
};
|
||||||
use cranelift_codegen::isa::TargetIsa;
|
use cranelift_codegen::isa::TargetIsa;
|
||||||
use cranelift_codegen::packed_option::PackedOption;
|
use cranelift_codegen::packed_option::PackedOption;
|
||||||
@@ -545,6 +545,80 @@ impl<'a> FunctionBuilder<'a> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Helper functions
|
||||||
|
impl<'a> FunctionBuilder<'a> {
|
||||||
|
/// Calls libc.memcpy
|
||||||
|
///
|
||||||
|
/// Copies the `size` bytes from `src` to `dest`, assumes that `src + size`
|
||||||
|
/// won't overlap onto `dest`. If `dest` and `src` overlap, the behavior is
|
||||||
|
/// undefined. Applications in which `dest` and `src` might overlap should
|
||||||
|
/// use `call_memmove` instead.
|
||||||
|
pub fn call_memcpy(&mut self, isa: &TargetIsa, dest: Value, src: Value, size: Value) {
|
||||||
|
let pointer_type = isa.pointer_type();
|
||||||
|
let signature = {
|
||||||
|
let mut s = Signature::new(isa.flags().call_conv());
|
||||||
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
|
self.import_signature(s)
|
||||||
|
};
|
||||||
|
|
||||||
|
let libc_memcpy = self.import_function(ExtFuncData {
|
||||||
|
name: ExternalName::LibCall(LibCall::Memcpy),
|
||||||
|
signature,
|
||||||
|
colocated: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.ins().call(libc_memcpy, &[dest, src, size]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calls libc.memset
|
||||||
|
///
|
||||||
|
/// Writes `len` bytes of value `ch` to memory starting at `buffer`.
|
||||||
|
pub fn call_memset(&mut self, isa: &TargetIsa, buffer: Value, ch: Value, len: Value) {
|
||||||
|
let pointer_type = isa.pointer_type();
|
||||||
|
let signature = {
|
||||||
|
let mut s = Signature::new(isa.flags().call_conv());
|
||||||
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
|
s.params.push(AbiParam::new(types::I32));
|
||||||
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
|
self.import_signature(s)
|
||||||
|
};
|
||||||
|
|
||||||
|
let libc_memset = self.import_function(ExtFuncData {
|
||||||
|
name: ExternalName::LibCall(LibCall::Memset),
|
||||||
|
signature,
|
||||||
|
colocated: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.ins().uextend(types::I32, ch);
|
||||||
|
self.ins().call(libc_memset, &[buffer, ch, len]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Calls libc.memmove
|
||||||
|
///
|
||||||
|
/// Copies `len` bytes from memory starting at `source` to memory starting
|
||||||
|
/// at `dest`. `source` is always read before writing to `dest`.
|
||||||
|
pub fn call_memmove(&mut self, isa: &TargetIsa, dest: Value, source: Value, num: Value) {
|
||||||
|
let pointer_type = isa.pointer_type();
|
||||||
|
let signature = {
|
||||||
|
let mut s = Signature::new(isa.flags().call_conv());
|
||||||
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
|
s.params.push(AbiParam::new(pointer_type));
|
||||||
|
self.import_signature(s)
|
||||||
|
};
|
||||||
|
|
||||||
|
let libc_memmove = self.import_function(ExtFuncData {
|
||||||
|
name: ExternalName::LibCall(LibCall::Memmove),
|
||||||
|
signature,
|
||||||
|
colocated: false,
|
||||||
|
});
|
||||||
|
|
||||||
|
self.ins().call(libc_memmove, &[dest, source, num]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Helper functions
|
// Helper functions
|
||||||
impl<'a> FunctionBuilder<'a> {
|
impl<'a> FunctionBuilder<'a> {
|
||||||
fn move_to_next_basic_block(&mut self) {
|
fn move_to_next_basic_block(&mut self) {
|
||||||
@@ -691,4 +765,65 @@ mod tests {
|
|||||||
fn sample_with_lazy_seal() {
|
fn sample_with_lazy_seal() {
|
||||||
sample_function(true)
|
sample_function(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn memcpy() {
|
||||||
|
use cranelift_codegen::{isa, settings};
|
||||||
|
use std::str::FromStr;
|
||||||
|
|
||||||
|
let shared_builder = settings::builder();
|
||||||
|
let shared_flags = settings::Flags::new(shared_builder);
|
||||||
|
|
||||||
|
let triple = ::target_lexicon::Triple::from_str("arm").expect("Couldn't create arm triple");
|
||||||
|
|
||||||
|
let target = isa::lookup(triple)
|
||||||
|
.ok()
|
||||||
|
.map(|b| b.finish(shared_flags))
|
||||||
|
.expect("This test requires arm support.");
|
||||||
|
|
||||||
|
let mut sig = Signature::new(target.flags().call_conv());
|
||||||
|
sig.returns.push(AbiParam::new(I32));
|
||||||
|
|
||||||
|
let mut fn_ctx = FunctionBuilderContext::new();
|
||||||
|
let mut func = Function::with_name_signature(ExternalName::testcase("sample"), sig);
|
||||||
|
{
|
||||||
|
let mut builder = FunctionBuilder::new(&mut func, &mut fn_ctx);
|
||||||
|
|
||||||
|
let block0 = builder.create_ebb();
|
||||||
|
let x = Variable::new(0);
|
||||||
|
let y = Variable::new(1);
|
||||||
|
let z = Variable::new(2);
|
||||||
|
builder.declare_var(x, target.pointer_type());
|
||||||
|
builder.declare_var(y, target.pointer_type());
|
||||||
|
builder.declare_var(z, I32);
|
||||||
|
builder.append_ebb_params_for_function_params(block0);
|
||||||
|
builder.switch_to_block(block0);
|
||||||
|
|
||||||
|
let src = builder.use_var(x);
|
||||||
|
let dest = builder.use_var(y);
|
||||||
|
let size = builder.use_var(y);
|
||||||
|
builder.call_memcpy(&*target, dest, src, size);
|
||||||
|
builder.ins().return_(&[size]);
|
||||||
|
|
||||||
|
builder.seal_all_blocks();
|
||||||
|
builder.finalize();
|
||||||
|
}
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
func.display(None).to_string(),
|
||||||
|
"function %sample() -> i32 fast {
|
||||||
|
sig0 = (i32, i32, i32) fast
|
||||||
|
fn0 = %Memcpy sig0
|
||||||
|
|
||||||
|
ebb0:
|
||||||
|
v3 = iconst.i32 0
|
||||||
|
v1 -> v3
|
||||||
|
v2 = iconst.i32 0
|
||||||
|
v0 -> v2
|
||||||
|
call fn0(v1, v0, v1)
|
||||||
|
return v1
|
||||||
|
}
|
||||||
|
"
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -177,6 +177,8 @@
|
|||||||
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
||||||
|
|
||||||
extern crate cranelift_codegen;
|
extern crate cranelift_codegen;
|
||||||
|
#[cfg(test)]
|
||||||
|
extern crate target_lexicon;
|
||||||
|
|
||||||
pub use frontend::{FunctionBuilder, FunctionBuilderContext};
|
pub use frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||||
pub use variable::Variable;
|
pub use variable::Variable;
|
||||||
|
|||||||
Reference in New Issue
Block a user