Skip to content

Commit

Permalink
Use libcore's align_offset
Browse files Browse the repository at this point in the history
  • Loading branch information
pvdrz committed Sep 9, 2019
1 parent dd94c7c commit 7082187
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 3 deletions.
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#![feature(core_intrinsics)]
#![feature(rustc_private)]

#![warn(rust_2018_idioms)]
Expand Down
72 changes: 69 additions & 3 deletions src/shims/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@

pub mod foreign_items;
pub mod intrinsics;
pub mod tls;
Expand Down Expand Up @@ -27,9 +28,74 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}
// There are some more lang items we want to hook that CTFE does not hook (yet).
if this.tcx.lang_items().align_offset_fn() == Some(instance.def.def_id()) {
// FIXME: return a real value in case the target allocation has an
// alignment bigger than the one requested.
let n = u128::max_value();
let ptr = this.read_scalar(args[0])?.not_undef()?;
let align = this.read_scalar(args[1])?.not_undef()?;

let n = {
let p = this.force_bits(ptr, this.pointer_size())?;
let a = this.force_bits(align, this.pointer_size())?;

let stride = this.memory().get(ptr.assert_ptr().alloc_id)?.align.bytes() as u128;
// if the allocation alignment is at least the required alignment, we use the
// libcore implementation
if stride >= a {
// This code was copied from the original `align_offset` implementation in
// rust/src/libcore/ptr/mod.rs, refer to it for its documentation
use std::intrinsics::{unchecked_rem, cttz_nonzero};
#[inline]
fn mod_inv(x: usize, m: usize) -> usize {
const INV_TABLE_MOD_16: [u8; 8] = [1, 11, 13, 7, 9, 3, 5, 15];
const INV_TABLE_MOD: usize = 16;
const INV_TABLE_MOD_SQUARED: usize = INV_TABLE_MOD * INV_TABLE_MOD;

let table_inverse = INV_TABLE_MOD_16[(x & (INV_TABLE_MOD - 1)) >> 1] as usize;
if m <= INV_TABLE_MOD {
table_inverse & (m - 1)
} else {
let mut inverse = table_inverse;
let mut going_mod = INV_TABLE_MOD_SQUARED;
loop {
inverse = inverse.wrapping_mul(
2usize.wrapping_sub(x.wrapping_mul(inverse))
) & (going_mod - 1);
if going_mod > m {
return inverse & (m - 1);
}
going_mod = going_mod.wrapping_mul(going_mod);
}
}
}

let a_minus_one = a.wrapping_sub(1);
let pmoda = p & a_minus_one;

if pmoda == 0 {
0
} else if stride <= 1 {
if stride == 0 {
!0
} else {
a.wrapping_sub(pmoda)
}
} else {
let smoda = stride & a_minus_one;
// `Align`s are always a power of two
let gcdpow = unsafe { cttz_nonzero(stride).min(cttz_nonzero(a)) };
let gcd = 1usize << gcdpow;

if p as usize & (gcd - 1) == 0 {
let j = a.wrapping_sub(pmoda) >> gcdpow;
let k = smoda >> gcdpow;
unsafe { unchecked_rem(j.wrapping_mul(mod_inv(k as usize, a as usize) as u128), a >> gcdpow) }
} else {
u128::max_value()
}
}
} else {
u128::max_value()
}
};

let dest = dest.unwrap();
let n = this.truncate(n, dest.layout);
this.write_scalar(Scalar::from_uint(n, dest.layout.size), dest)?;
Expand Down

0 comments on commit 7082187

Please sign in to comment.