Auto merge of #27845 - dylanmckay:abstract-pointer-size-away, r=alexcrichton
This patch rewrites code in several places which assume that the current target has either 32-bit or 64-bit pointers so that it can support arbitrary-width pointers. It does not completely remove all assumptions of pointer width, but it does reduce them significantly. There is a discussion [here](https://internals.rust-lang.org/t/adding-16-bit-pointer-support/2484/10) about the change.
This commit is contained in:
commit
f05b22efb5
@ -83,6 +83,7 @@
|
||||
#![feature(lang_items)]
|
||||
#![feature(no_std)]
|
||||
#![feature(nonzero)]
|
||||
#![feature(num_bits_bytes)]
|
||||
#![feature(optin_builtin_traits)]
|
||||
#![feature(placement_in_syntax)]
|
||||
#![feature(placement_new_protocol)]
|
||||
|
@ -15,6 +15,7 @@
|
||||
use super::oom;
|
||||
use super::boxed::Box;
|
||||
use core::ops::Drop;
|
||||
use core;
|
||||
|
||||
/// A low-level utility for more ergonomically allocating, reallocating, and deallocating a
|
||||
/// a buffer of memory on the heap without having to worry about all the corner cases
|
||||
@ -443,11 +444,8 @@ fn drop(&mut self) {
|
||||
// user-space. e.g. PAE or x32
|
||||
|
||||
#[inline]
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
fn alloc_guard(_alloc_size: usize) { }
|
||||
|
||||
#[inline]
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
fn alloc_guard(alloc_size: usize) {
|
||||
assert!(alloc_size <= ::core::isize::MAX as usize, "capacity overflow");
|
||||
if core::usize::BITS < 64 {
|
||||
assert!(alloc_size <= ::core::isize::MAX as usize, "capacity overflow");
|
||||
}
|
||||
}
|
||||
|
@ -1340,12 +1340,7 @@ fn fmt(&self, f: &mut Formatter) -> Result {
|
||||
f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32);
|
||||
|
||||
if let None = f.width {
|
||||
// The formats need two extra bytes, for the 0x
|
||||
if cfg!(target_pointer_width = "32") {
|
||||
f.width = Some(10);
|
||||
} else {
|
||||
f.width = Some(18);
|
||||
}
|
||||
f.width = Some((::usize::BITS/4) + 2);
|
||||
}
|
||||
}
|
||||
f.flags |= 1 << (FlagV1::Alternate as u32);
|
||||
|
@ -144,11 +144,11 @@ fn write_u64(&mut self, i: u64) {
|
||||
#[inline]
|
||||
#[stable(feature = "hasher_write", since = "1.3.0")]
|
||||
fn write_usize(&mut self, i: usize) {
|
||||
if cfg!(target_pointer_width = "32") {
|
||||
self.write_u32(i as u32)
|
||||
} else {
|
||||
self.write_u64(i as u64)
|
||||
}
|
||||
let bytes = unsafe {
|
||||
::slice::from_raw_parts(&i as *const usize as *const u8,
|
||||
mem::size_of::<usize>())
|
||||
};
|
||||
self.write(bytes);
|
||||
}
|
||||
|
||||
/// Write a single `i8` into this hasher.
|
||||
|
@ -2236,7 +2236,9 @@ fn steps_between(_a: &$t, _b: &$t, _by: &$t) -> Option<usize> {
|
||||
step_impl_unsigned!(u64);
|
||||
#[cfg(target_pointer_width = "64")]
|
||||
step_impl_signed!(i64);
|
||||
#[cfg(target_pointer_width = "32")]
|
||||
// If the target pointer width is not 64-bits, we
|
||||
// assume here that it is less than 64-bits.
|
||||
#[cfg(not(target_pointer_width = "64"))]
|
||||
step_impl_no_between!(u64 i64);
|
||||
|
||||
/// An adapter for stepping range iterators by a custom amount.
|
||||
|
@ -943,11 +943,8 @@ pub fn call_lifetime_end(cx: Block, ptr: ValueRef) {
|
||||
pub fn call_memcpy(cx: Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) {
|
||||
let _icx = push_ctxt("call_memcpy");
|
||||
let ccx = cx.ccx();
|
||||
let key = match &ccx.sess().target.target.target_pointer_width[..] {
|
||||
"32" => "llvm.memcpy.p0i8.p0i8.i32",
|
||||
"64" => "llvm.memcpy.p0i8.p0i8.i64",
|
||||
tws => panic!("Unsupported target word size for memcpy: {}", tws),
|
||||
};
|
||||
let ptr_width = &ccx.sess().target.target.target_pointer_width[..];
|
||||
let key = format!("llvm.memcpy.p0i8.p0i8.i{}", ptr_width);
|
||||
let memcpy = ccx.get_intrinsic(&key);
|
||||
let src_ptr = PointerCast(cx, src, Type::i8p(ccx));
|
||||
let dst_ptr = PointerCast(cx, dst, Type::i8p(ccx));
|
||||
@ -996,12 +993,8 @@ fn memfill<'a, 'tcx>(b: &Builder<'a, 'tcx>, llptr: ValueRef, ty: Ty<'tcx>, byte:
|
||||
let ccx = b.ccx;
|
||||
|
||||
let llty = type_of::type_of(ccx, ty);
|
||||
|
||||
let intrinsic_key = match &ccx.sess().target.target.target_pointer_width[..] {
|
||||
"32" => "llvm.memset.p0i8.i32",
|
||||
"64" => "llvm.memset.p0i8.i64",
|
||||
tws => panic!("Unsupported target word size for memset: {}", tws),
|
||||
};
|
||||
let ptr_width = &ccx.sess().target.target.target_pointer_width[..];
|
||||
let intrinsic_key = format!("llvm.memset.p0i8.i{}", ptr_width);
|
||||
|
||||
let llintrinsicfn = ccx.get_intrinsic(&intrinsic_key);
|
||||
let llptr = b.pointercast(llptr, Type::i8(ccx).ptr_to());
|
||||
|
@ -833,10 +833,11 @@ pub fn C_u64(ccx: &CrateContext, i: u64) -> ValueRef {
|
||||
pub fn C_int<I: AsI64>(ccx: &CrateContext, i: I) -> ValueRef {
|
||||
let v = i.as_i64();
|
||||
|
||||
match machine::llbitsize_of_real(ccx, ccx.int_type()) {
|
||||
32 => assert!(v < (1<<31) && v >= -(1<<31)),
|
||||
64 => {},
|
||||
n => panic!("unsupported target size: {}", n)
|
||||
let bit_size = machine::llbitsize_of_real(ccx, ccx.int_type());
|
||||
|
||||
if bit_size < 64 {
|
||||
// make sure it doesn't overflow
|
||||
assert!(v < (1<<(bit_size-1)) && v >= -(1<<(bit_size-1)));
|
||||
}
|
||||
|
||||
C_integral(ccx.int_type(), v as u64, true)
|
||||
@ -845,10 +846,11 @@ pub fn C_int<I: AsI64>(ccx: &CrateContext, i: I) -> ValueRef {
|
||||
pub fn C_uint<I: AsU64>(ccx: &CrateContext, i: I) -> ValueRef {
|
||||
let v = i.as_u64();
|
||||
|
||||
match machine::llbitsize_of_real(ccx, ccx.int_type()) {
|
||||
32 => assert!(v < (1<<32)),
|
||||
64 => {},
|
||||
n => panic!("unsupported target size: {}", n)
|
||||
let bit_size = machine::llbitsize_of_real(ccx, ccx.int_type());
|
||||
|
||||
if bit_size < 64 {
|
||||
// make sure it doesn't overflow
|
||||
assert!(v < (1<<bit_size));
|
||||
}
|
||||
|
||||
C_integral(ccx.int_type(), v, false)
|
||||
|
@ -560,13 +560,13 @@ pub fn raw_builder<'a>(&'a self) -> BuilderRef {
|
||||
self.local.builder.b
|
||||
}
|
||||
|
||||
pub fn get_intrinsic(&self, key: & &'static str) -> ValueRef {
|
||||
pub fn get_intrinsic(&self, key: &str) -> ValueRef {
|
||||
if let Some(v) = self.intrinsics().borrow().get(key).cloned() {
|
||||
return v;
|
||||
}
|
||||
match declare_intrinsic(self, key) {
|
||||
Some(v) => return v,
|
||||
None => panic!()
|
||||
None => panic!("unknown intrinsic '{}'", key)
|
||||
}
|
||||
}
|
||||
|
||||
@ -791,10 +791,10 @@ pub fn use_dll_storage_attrs(&self) -> bool {
|
||||
}
|
||||
|
||||
/// Declare any llvm intrinsics that you might need
|
||||
fn declare_intrinsic(ccx: &CrateContext, key: & &'static str) -> Option<ValueRef> {
|
||||
fn declare_intrinsic(ccx: &CrateContext, key: &str) -> Option<ValueRef> {
|
||||
macro_rules! ifn {
|
||||
($name:expr, fn() -> $ret:expr) => (
|
||||
if *key == $name {
|
||||
if key == $name {
|
||||
let f = declare::declare_cfn(ccx, $name, Type::func(&[], &$ret),
|
||||
ccx.tcx().mk_nil());
|
||||
ccx.intrinsics().borrow_mut().insert($name, f.clone());
|
||||
@ -802,7 +802,7 @@ macro_rules! ifn {
|
||||
}
|
||||
);
|
||||
($name:expr, fn($($arg:expr),*) -> $ret:expr) => (
|
||||
if *key == $name {
|
||||
if key == $name {
|
||||
let f = declare::declare_cfn(ccx, $name, Type::func(&[$($arg),*], &$ret),
|
||||
ccx.tcx().mk_nil());
|
||||
ccx.intrinsics().borrow_mut().insert($name, f.clone());
|
||||
@ -824,10 +824,13 @@ macro_rules! mk_struct {
|
||||
let t_f32 = Type::f32(ccx);
|
||||
let t_f64 = Type::f64(ccx);
|
||||
|
||||
ifn!("llvm.memcpy.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void);
|
||||
ifn!("llvm.memcpy.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void);
|
||||
ifn!("llvm.memcpy.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void);
|
||||
ifn!("llvm.memmove.p0i8.p0i8.i16", fn(i8p, i8p, t_i16, t_i32, i1) -> void);
|
||||
ifn!("llvm.memmove.p0i8.p0i8.i32", fn(i8p, i8p, t_i32, t_i32, i1) -> void);
|
||||
ifn!("llvm.memmove.p0i8.p0i8.i64", fn(i8p, i8p, t_i64, t_i32, i1) -> void);
|
||||
ifn!("llvm.memset.p0i8.i16", fn(i8p, t_i8, t_i16, t_i32, i1) -> void);
|
||||
ifn!("llvm.memset.p0i8.i32", fn(i8p, t_i8, t_i32, t_i32, i1) -> void);
|
||||
ifn!("llvm.memset.p0i8.i64", fn(i8p, t_i8, t_i64, t_i32, i1) -> void);
|
||||
|
||||
@ -942,7 +945,7 @@ macro_rules! compatible_ifn {
|
||||
if unsafe { llvm::LLVMVersionMinor() >= $llvm_version } {
|
||||
// The `if key == $name` is already in ifn!
|
||||
ifn!($name, fn($($arg),*) -> void);
|
||||
} else if *key == $name {
|
||||
} else if key == $name {
|
||||
let f = declare::declare_cfn(ccx, stringify!($cname),
|
||||
Type::func(&[$($arg),*], &void),
|
||||
ccx.tcx().mk_nil());
|
||||
@ -965,7 +968,7 @@ macro_rules! compatible_ifn {
|
||||
if unsafe { llvm::LLVMVersionMinor() >= $llvm_version } {
|
||||
// The `if key == $name` is already in ifn!
|
||||
ifn!($name, fn($($arg),*) -> $ret);
|
||||
} else if *key == $name {
|
||||
} else if key == $name {
|
||||
let f = declare::declare_cfn(ccx, stringify!($cname),
|
||||
Type::func(&[$($arg),*], &$ret),
|
||||
ccx.tcx().mk_nil());
|
||||
|
@ -932,20 +932,15 @@ fn copy_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
let align = C_i32(ccx, type_of::align_of(ccx, tp_ty) as i32);
|
||||
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"
|
||||
}
|
||||
|
||||
let operation = if allow_overlap {
|
||||
"memmove"
|
||||
} else {
|
||||
if int_size == 32 {
|
||||
"llvm.memcpy.p0i8.p0i8.i32"
|
||||
} else {
|
||||
"llvm.memcpy.p0i8.p0i8.i64"
|
||||
}
|
||||
"memcpy"
|
||||
};
|
||||
|
||||
let name = format!("llvm.{}.p0i8.p0i8.i{}", operation, int_size);
|
||||
|
||||
let dst_ptr = PointerCast(bcx, dst, Type::i8p(ccx));
|
||||
let src_ptr = PointerCast(bcx, src, Type::i8p(ccx));
|
||||
let llfn = ccx.get_intrinsic(&name);
|
||||
@ -973,11 +968,9 @@ fn memset_intrinsic<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
|
||||
let lltp_ty = type_of::type_of(ccx, tp_ty);
|
||||
let align = C_i32(ccx, type_of::align_of(ccx, tp_ty) as i32);
|
||||
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 int_size = machine::llbitsize_of_real(ccx, ccx.int_type());
|
||||
|
||||
let name = format!("llvm.memset.p0i8.i{}", int_size);
|
||||
|
||||
let dst_ptr = PointerCast(bcx, dst, Type::i8p(ccx));
|
||||
let llfn = ccx.get_intrinsic(&name);
|
||||
|
Loading…
Reference in New Issue
Block a user