Skip to content

simplify memcpy/memmove/memset intrinsics #10251

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 24 additions & 16 deletions src/librustc/middle/trans/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,24 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
}
}

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;
Expand All @@ -95,14 +105,15 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
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;
Expand Down Expand Up @@ -399,12 +410,9 @@ pub fn trans_intrinsic(ccx: @mut CrateContext,
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),
Expand Down
54 changes: 6 additions & 48 deletions src/librustc/middle/typeck/check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3734,7 +3734,7 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
mutbl: ast::MutImmutable
}))
}
"memcpy32" => {
"copy_nonoverlapping_memory" => {
(1,
~[
ty::mk_ptr(tcx, ty::mt {
Expand All @@ -3745,11 +3745,11 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
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 {
Expand All @@ -3760,61 +3760,19 @@ pub fn check_intrinsic_type(ccx: @mut CrateCtxt, it: @ast::foreign_item) {
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" => {
(1,
~[
ty::mk_ptr(tcx, ty::mt {
ty: param(ccx, 0),
mutbl: ast::MutMutable
}),
ty::mk_u8(),
ty::mk_u32()
],
ty::mk_nil())
}
"memset64" => {
"set_memory" => {
(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())
}
Expand Down
15 changes: 2 additions & 13 deletions src/libstd/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down
48 changes: 42 additions & 6 deletions src/libstd/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand All @@ -101,21 +101,33 @@ 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.
*
* Copies `count` elements (not bytes) from `src` to `dst`. The source
* 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) {
Expand All @@ -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) {
Expand All @@ -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);
}
Expand All @@ -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`
*/
Expand Down
15 changes: 15 additions & 0 deletions src/libstd/unstable/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -345,25 +345,40 @@ extern "rust-intrinsic" {

/// 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;

Expand Down