simplify memcpy/memmove/memset intrinsics

This moves the per-architecture difference into the compiler.
This commit is contained in:
Daniel Micay 2013-11-03 16:54:58 -05:00
parent dc079e1596
commit 67966fa9de
5 changed files with 89 additions and 83 deletions

View File

@ -74,14 +74,24 @@ fn with_overflow_instrinsic(bcx: @mut Block, name: &'static str, t: ty::t) {
}
}
fn memcpy_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
fn copy_intrinsic(bcx: @mut Block, allow_overlap: bool, tp_ty: ty::t) {
let ccx = bcx.ccx();
let lltp_ty = type_of::type_of(ccx, tp_ty);
let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
let size = match sizebits {
32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
_ => ccx.sess.fatal("Invalid value for sizebits")
let size = machine::llsize_of(ccx, lltp_ty);
let int_size = machine::llbitsize_of_real(ccx, ccx.int_type);
let name = if allow_overlap {
if int_size == 32 {
"llvm.memmove.p0i8.p0i8.i32"
} else {
"llvm.memmove.p0i8.p0i8.i64"
}
} else {
if int_size == 32 {
"llvm.memcpy.p0i8.p0i8.i32"
} else {
"llvm.memcpy.p0i8.p0i8.i64"
}
};
let decl = bcx.fcx.llfn;
@ -95,14 +105,15 @@ fn memcpy_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits:
RetVoid(bcx);
}
fn memset_intrinsic(bcx: @mut Block, name: &'static str, tp_ty: ty::t, sizebits: u8) {
fn memset_intrinsic(bcx: @mut Block, tp_ty: ty::t) {
let ccx = bcx.ccx();
let lltp_ty = type_of::type_of(ccx, tp_ty);
let align = C_i32(machine::llalign_of_min(ccx, lltp_ty) as i32);
let size = match sizebits {
32 => C_i32(machine::llsize_of_real(ccx, lltp_ty) as i32),
64 => C_i64(machine::llsize_of_real(ccx, lltp_ty) as i64),
_ => ccx.sess.fatal("Invalid value for sizebits")
let size = machine::llsize_of(ccx, lltp_ty);
let name = if machine::llbitsize_of_real(ccx, ccx.int_type) == 32 {
"llvm.memset.p0i8.i32"
} else {
"llvm.memset.p0i8.i64"
};
let decl = bcx.fcx.llfn;
@ -399,12 +410,9 @@ fn count_zeros_intrinsic(bcx: @mut Block, name: &'static str) {
let lladdr = InBoundsGEP(bcx, ptr, [offset]);
Ret(bcx, lladdr);
}
"memcpy32" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i32", substs.tys[0], 32),
"memcpy64" => memcpy_intrinsic(bcx, "llvm.memcpy.p0i8.p0i8.i64", substs.tys[0], 64),
"memmove32" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i32", substs.tys[0], 32),
"memmove64" => memcpy_intrinsic(bcx, "llvm.memmove.p0i8.p0i8.i64", substs.tys[0], 64),
"memset32" => memset_intrinsic(bcx, "llvm.memset.p0i8.i32", substs.tys[0], 32),
"memset64" => memset_intrinsic(bcx, "llvm.memset.p0i8.i64", substs.tys[0], 64),
"copy_nonoverlapping_memory" => copy_intrinsic(bcx, false, substs.tys[0]),
"copy_memory" => copy_intrinsic(bcx, true, substs.tys[0]),
"set_memory" => memset_intrinsic(bcx, substs.tys[0]),
"sqrtf32" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f32", 1),
"sqrtf64" => simple_llvm_intrinsic(bcx, "llvm.sqrt.f64", 1),
"powif32" => simple_llvm_intrinsic(bcx, "llvm.powi.f32", 2),

View File

@ -3734,7 +3734,7 @@ fn param(ccx: @mut CrateCtxt, n: uint) -> ty::t {
mutbl: ast::MutImmutable
}))
}
"memcpy32" => {
"copy_nonoverlapping_memory" => {
(1,
~[
ty::mk_ptr(tcx, ty::mt {
@ -3745,11 +3745,11 @@ fn param(ccx: @mut CrateCtxt, n: uint) -> ty::t {
ty: param(ccx, 0),
mutbl: ast::MutImmutable
}),
ty::mk_u32()
ty::mk_uint()
],
ty::mk_nil())
}
"memcpy64" => {
"copy_memory" => {
(1,
~[
ty::mk_ptr(tcx, ty::mt {
@ -3760,41 +3760,11 @@ fn param(ccx: @mut CrateCtxt, n: uint) -> ty::t {
ty: param(ccx, 0),
mutbl: ast::MutImmutable
}),
ty::mk_u64()
ty::mk_uint()
],
ty::mk_nil())
}
"memmove32" => {
(1,
~[
ty::mk_ptr(tcx, ty::mt {
ty: param(ccx, 0),
mutbl: ast::MutMutable
}),
ty::mk_ptr(tcx, ty::mt {
ty: param(ccx, 0),
mutbl: ast::MutImmutable
}),
ty::mk_u32()
],
ty::mk_nil())
}
"memmove64" => {
(1,
~[
ty::mk_ptr(tcx, ty::mt {
ty: param(ccx, 0),
mutbl: ast::MutMutable
}),
ty::mk_ptr(tcx, ty::mt {
ty: param(ccx, 0),
mutbl: ast::MutImmutable
}),
ty::mk_u64()
],
ty::mk_nil())
}
"memset32" => {
"set_memory" => {
(1,
~[
ty::mk_ptr(tcx, ty::mt {
@ -3802,19 +3772,7 @@ fn param(ccx: @mut CrateCtxt, n: uint) -> ty::t {
mutbl: ast::MutMutable
}),
ty::mk_u8(),
ty::mk_u32()
],
ty::mk_nil())
}
"memset64" => {
(1,
~[
ty::mk_ptr(tcx, ty::mt {
ty: param(ccx, 0),
mutbl: ast::MutMutable
}),
ty::mk_u8(),
ty::mk_u64()
ty::mk_uint()
],
ty::mk_nil())
}

View File

@ -13,26 +13,15 @@
use ptr::RawPtr;
use mem;
use unstable::intrinsics;
use ptr::copy_nonoverlapping_memory;
/// Casts the value at `src` to U. The two types must have the same length.
#[cfg(target_word_size = "32")]
#[inline]
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
let mut dest: U = intrinsics::uninit();
let dest_ptr: *mut u8 = transmute(&mut dest);
let src_ptr: *u8 = transmute(src);
intrinsics::memcpy32(dest_ptr, src_ptr, mem::size_of::<U>() as u32);
dest
}
/// Casts the value at `src` to U. The two types must have the same length.
#[cfg(target_word_size = "64")]
#[inline]
pub unsafe fn transmute_copy<T, U>(src: &T) -> U {
let mut dest: U = intrinsics::uninit();
let dest_ptr: *mut u8 = transmute(&mut dest);
let src_ptr: *u8 = transmute(src);
intrinsics::memcpy64(dest_ptr, src_ptr, mem::size_of::<U>() as u64);
copy_nonoverlapping_memory(dest_ptr, src_ptr, mem::size_of::<U>());
dest
}

View File

@ -87,7 +87,7 @@ pub fn is_not_null<T,P:RawPtr<T>>(ptr: P) -> bool { ptr.is_not_null() }
* and destination may overlap.
*/
#[inline]
#[cfg(target_word_size = "32")]
#[cfg(target_word_size = "32", stage0)]
pub unsafe fn copy_memory<T,P:RawPtr<T>>(dst: *mut T, src: P, count: uint) {
intrinsics::memmove32(dst,
cast::transmute_immut_unsafe(src),
@ -101,13 +101,25 @@ pub unsafe fn copy_memory<T,P:RawPtr<T>>(dst: *mut T, src: P, count: uint) {
* and destination may overlap.
*/
#[inline]
#[cfg(target_word_size = "64")]
#[cfg(target_word_size = "64", stage0)]
pub unsafe fn copy_memory<T,P:RawPtr<T>>(dst: *mut T, src: P, count: uint) {
intrinsics::memmove64(dst,
cast::transmute_immut_unsafe(src),
count as u64);
}
/**
* Copies data from one location to another.
*
* Copies `count` elements (not bytes) from `src` to `dst`. The source
* and destination may overlap.
*/
#[inline]
#[cfg(not(stage0))]
pub unsafe fn copy_memory<T,P:RawPtr<T>>(dst: *mut T, src: P, count: uint) {
intrinsics::copy_memory(dst, cast::transmute_immut_unsafe(src), count)
}
/**
* Copies data from one location to another.
*
@ -115,7 +127,7 @@ pub unsafe fn copy_memory<T,P:RawPtr<T>>(dst: *mut T, src: P, count: uint) {
* and destination may *not* overlap.
*/
#[inline]
#[cfg(target_word_size = "32")]
#[cfg(target_word_size = "32", stage0)]
pub unsafe fn copy_nonoverlapping_memory<T,P:RawPtr<T>>(dst: *mut T,
src: P,
count: uint) {
@ -131,7 +143,7 @@ pub unsafe fn copy_nonoverlapping_memory<T,P:RawPtr<T>>(dst: *mut T,
* and destination may *not* overlap.
*/
#[inline]
#[cfg(target_word_size = "64")]
#[cfg(target_word_size = "64", stage0)]
pub unsafe fn copy_nonoverlapping_memory<T,P:RawPtr<T>>(dst: *mut T,
src: P,
count: uint) {
@ -140,12 +152,26 @@ pub unsafe fn copy_nonoverlapping_memory<T,P:RawPtr<T>>(dst: *mut T,
count as u64);
}
/**
* Copies data from one location to another.
*
* Copies `count` elements (not bytes) from `src` to `dst`. The source
* and destination may *not* overlap.
*/
#[inline]
#[cfg(not(stage0))]
pub unsafe fn copy_nonoverlapping_memory<T,P:RawPtr<T>>(dst: *mut T,
src: P,
count: uint) {
intrinsics::copy_nonoverlapping_memory(dst, cast::transmute_immut_unsafe(src), count)
}
/**
* Invokes memset on the specified pointer, setting `count * size_of::<T>()`
* bytes of memory starting at `dst` to `c`.
*/
#[inline]
#[cfg(target_word_size = "32")]
#[cfg(target_word_size = "32", stage0)]
pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) {
intrinsics::memset32(dst, c, count as u32);
}
@ -155,11 +181,21 @@ pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) {
* bytes of memory starting at `dst` to `c`.
*/
#[inline]
#[cfg(target_word_size = "64")]
#[cfg(target_word_size = "64", stage0)]
pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) {
intrinsics::memset64(dst, c, count as u64);
}
/**
* Invokes memset on the specified pointer, setting `count * size_of::<T>()`
* bytes of memory starting at `dst` to `c`.
*/
#[inline]
#[cfg(not(stage0))]
pub unsafe fn set_memory<T>(dst: *mut T, c: u8, count: uint) {
intrinsics::set_memory(dst, c, count)
}
/**
* Zeroes out `count * size_of::<T>` bytes of memory at `dst`
*/

View File

@ -345,25 +345,40 @@ fn visit_leave_fn(&mut self, purity: uint, proto: uint,
/// Equivalent to the `llvm.memcpy.p0i8.0i8.i32` intrinsic, with a size of
/// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
#[cfg(stage0)]
pub fn memcpy32<T>(dst: *mut T, src: *T, count: u32);
/// Equivalent to the `llvm.memcpy.p0i8.0i8.i64` intrinsic, with a size of
/// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
#[cfg(stage0)]
pub fn memcpy64<T>(dst: *mut T, src: *T, count: u64);
/// Equivalent to the `llvm.memmove.p0i8.0i8.i32` intrinsic, with a size of
/// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
#[cfg(stage0)]
pub fn memmove32<T>(dst: *mut T, src: *T, count: u32);
/// Equivalent to the `llvm.memmove.p0i8.0i8.i64` intrinsic, with a size of
/// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
#[cfg(stage0)]
pub fn memmove64<T>(dst: *mut T, src: *T, count: u64);
/// Equivalent to the `llvm.memset.p0i8.i32` intrinsic, with a size of
/// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
#[cfg(stage0)]
pub fn memset32<T>(dst: *mut T, val: u8, count: u32);
/// Equivalent to the `llvm.memset.p0i8.i64` intrinsic, with a size of
/// `count` * `size_of::<T>()` and an alignment of `min_align_of::<T>()`
#[cfg(stage0)]
pub fn memset64<T>(dst: *mut T, val: u8, count: u64);
#[cfg(not(stage0))]
pub fn copy_nonoverlapping_memory<T>(dst: *mut T, src: *T, count: uint);
#[cfg(not(stage0))]
pub fn copy_memory<T>(dst: *mut T, src: *T, count: uint);
#[cfg(not(stage0))]
pub fn set_memory<T>(dst: *mut T, val: u8, count: uint);
pub fn sqrtf32(x: f32) -> f32;
pub fn sqrtf64(x: f64) -> f64;