Merge pull request #67 from oli-obk/master

fix multi field enum variants and some intrinsics + rustup
This commit is contained in:
Scott Olson 2016-10-03 17:40:02 -06:00 committed by GitHub
commit a08f0615fc
11 changed files with 455 additions and 86 deletions

6
Cargo.lock generated
View File

@ -3,7 +3,7 @@ name = "miri"
version = "0.1.0"
dependencies = [
"byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"compiletest_rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"compiletest_rs 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
"env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
"log_settings 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)",
@ -24,7 +24,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "compiletest_rs"
version = "0.2.1"
version = "0.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"log 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -137,7 +137,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aho-corasick 0.5.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2b3fb52b09c1710b961acb35390d514be82e4ac96a9969a8e38565a29b878dc9"
"checksum byteorder 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "96c8b41881888cc08af32d47ac4edd52bc7fa27fef774be47a92443756451304"
"checksum compiletest_rs 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0bcddebf582c5c035cce855a89596eb686cc40b9e77da1026fba735dcca2fbd3"
"checksum compiletest_rs 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "0ac936b073036755b7d176f16d4c660f4d6f1390cbe556316af9cb9724117059"
"checksum env_logger 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "82dcb9ceed3868a03b335657b85a159736c961900f7e7747d3b0b97b9ccb5ccb"
"checksum kernel32-sys 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "7507624b29483431c0ba2d82aece8ca6cdba9382bff4ddd0f7490560c056098d"
"checksum lazy_static 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "49247ec2a285bb3dcb23cbd9c35193c025e7251bfce77c1d5da97e6362dffe7f"

View File

@ -21,4 +21,4 @@ log = "0.3.6"
log_settings = "0.1.1"
[dev-dependencies]
compiletest_rs = "0.2"
compiletest_rs = "0.2.3"

View File

@ -138,5 +138,5 @@ fn main() {
args.push(find_sysroot());
}
rustc_driver::run_compiler(&args, &mut MiriCompilerCalls);
rustc_driver::run_compiler(&args, &mut MiriCompilerCalls, None, None);
}

View File

@ -73,23 +73,13 @@ pub struct Frame<'a, 'tcx: 'a> {
// Return pointer and local allocations
////////////////////////////////////////////////////////////////////////////////
/// A pointer for writing the return value of the current call if it's not a diverging call.
pub return_ptr: Option<Pointer>,
/// The block to return to when returning from the current stack frame
pub return_to_block: StackPopCleanup,
/// The list of locals for the current function, stored in order as
/// `[arguments..., variables..., temporaries...]`. The variables begin at `self.var_offset`
/// and the temporaries at `self.temp_offset`.
/// `[return_ptr, arguments..., variables..., temporaries...]`.
pub locals: Vec<Pointer>,
/// The offset of the first variable in `self.locals`.
pub var_offset: usize,
/// The offset of the first temporary in `self.locals`.
pub temp_offset: usize,
////////////////////////////////////////////////////////////////////////////////
// Current position within the function
////////////////////////////////////////////////////////////////////////////////
@ -336,32 +326,26 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
span: codemap::Span,
mir: CachedMir<'a, 'tcx>,
substs: &'tcx Substs<'tcx>,
return_ptr: Option<Pointer>,
return_ptr: Pointer,
return_to_block: StackPopCleanup,
) -> EvalResult<'tcx, ()> {
let arg_tys = mir.arg_decls.iter().map(|a| a.ty);
let var_tys = mir.var_decls.iter().map(|v| v.ty);
let temp_tys = mir.temp_decls.iter().map(|t| t.ty);
let num_args = mir.arg_decls.len();
let num_vars = mir.var_decls.len();
let local_tys = mir.local_decls.iter().map(|a| a.ty);
::log_settings::settings().indentation += 1;
let locals: EvalResult<'tcx, Vec<Pointer>> = arg_tys.chain(var_tys).chain(temp_tys).map(|ty| {
// directly change the first allocation (the return value) to *be* the allocation where the
// caller stores the result
let locals: EvalResult<'tcx, Vec<Pointer>> = iter::once(Ok(return_ptr)).chain(local_tys.skip(1).map(|ty| {
let size = self.type_size_with_substs(ty, substs);
let align = self.type_align_with_substs(ty, substs);
self.memory.allocate(size, align)
}).collect();
})).collect();
self.stack.push(Frame {
mir: mir.clone(),
block: mir::START_BLOCK,
return_ptr: return_ptr,
return_to_block: return_to_block,
locals: locals?,
var_offset: num_args,
temp_offset: num_args + num_vars,
span: span,
def_id: def_id,
substs: substs,
@ -793,11 +777,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
fn eval_lvalue(&mut self, lvalue: &mir::Lvalue<'tcx>) -> EvalResult<'tcx, Lvalue> {
use rustc::mir::repr::Lvalue::*;
let ptr = match *lvalue {
ReturnPointer => self.frame().return_ptr
.expect("ReturnPointer used in a function with no return value"),
Arg(i) => self.frame().locals[i.index()],
Var(i) => self.frame().locals[self.frame().var_offset + i.index()],
Temp(i) => self.frame().locals[self.frame().temp_offset + i.index()],
Local(i) => self.frame().locals[i.index()],
Static(def_id) => {
let substs = subst::Substs::empty(self.tcx);
@ -819,11 +799,13 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Field(field, field_ty) => {
let field_ty = self.monomorphize(field_ty, self.substs());
use rustc::ty::layout::Layout::*;
let variant = match *base_layout {
Univariant { ref variant, .. } => variant,
let field = field.index();
let offset = match *base_layout {
Univariant { ref variant, .. } => variant.field_offset(field),
General { ref variants, .. } => {
if let LvalueExtra::DowncastVariant(variant_idx) = base.extra {
&variants[variant_idx]
// +1 for the discriminant, which is field 0
variants[variant_idx].field_offset(field + 1)
} else {
bug!("field access on enum had no variant index");
}
@ -832,14 +814,11 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
assert_eq!(field.index(), 0);
return Ok(base);
}
StructWrappedNullablePointer { ref nonnull, .. } => nonnull,
StructWrappedNullablePointer { ref nonnull, .. } => nonnull.field_offset(field),
_ => bug!("field access on non-product type: {:?}", base_layout),
};
let offset = variant.field_offset(field.index()).bytes();
let ptr = base.ptr.offset(offset as isize);
trace!("{:?}", base);
trace!("{:?}", field_ty);
let ptr = base.ptr.offset(offset.bytes() as isize);
if self.type_is_sized(field_ty) {
ptr
} else {
@ -859,9 +838,9 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
Downcast(_, variant) => {
use rustc::ty::layout::Layout::*;
match *base_layout {
General { ref variants, .. } => {
General { .. } => {
return Ok(Lvalue {
ptr: base.ptr.offset(variants[variant].field_offset(1).bytes() as isize),
ptr: base.ptr,
extra: LvalueExtra::DowncastVariant(variant),
});
}
@ -1220,18 +1199,17 @@ pub fn eval_main<'a, 'tcx: 'a>(
let return_ptr = ecx.alloc_ret_ptr(mir.return_ty, substs)
.expect("should at least be able to allocate space for the main function's return value");
ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, Some(return_ptr), StackPopCleanup::None)
ecx.push_stack_frame(def_id, mir.span, CachedMir::Ref(mir), substs, return_ptr, StackPopCleanup::None)
.expect("could not allocate first stack frame");
if mir.arg_decls.len() == 2 {
// FIXME: this is a horrible and wrong way to detect the start function, but overwriting the first two locals shouldn't do much
if mir.local_decls.len() > 2 {
// start function
let ptr_size = ecx.memory().pointer_size();
let nargs = ecx.memory_mut().allocate(ptr_size, ptr_size).expect("can't allocate memory for nargs");
ecx.memory_mut().write_usize(nargs, 0).unwrap();
let args = ecx.memory_mut().allocate(ptr_size, ptr_size).expect("can't allocate memory for arg pointer");
ecx.memory_mut().write_usize(args, 0).unwrap();
ecx.frame_mut().locals[0] = nargs;
ecx.frame_mut().locals[1] = args;
let nargs = ecx.frame_mut().locals[1];
let args = ecx.frame_mut().locals[2];
// ignore errors, if the locals are too small this is not the start function
let _ = ecx.memory_mut().write_usize(nargs, 0);
let _ = ecx.memory_mut().write_usize(args, 0);
}
for _ in 0..step_limit {

View File

@ -134,7 +134,7 @@ impl<'a, 'b, 'tcx> ConstantExtractor<'a, 'b, 'tcx> {
} else {
StackPopCleanup::None
};
this.ecx.push_stack_frame(def_id, span, mir, substs, Some(ptr), cleanup)
this.ecx.push_stack_frame(def_id, span, mir, substs, ptr, cleanup)
});
}
fn try<F: FnOnce(&mut Self) -> EvalResult<'tcx, ()>>(&mut self, f: F) {
@ -183,7 +183,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for ConstantExtractor<'a, 'b, 'tcx> {
constant.span,
mir,
this.substs,
Some(return_ptr),
return_ptr,
StackPopCleanup::Freeze(return_ptr.alloc_id))
});
}

View File

@ -31,7 +31,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let f32 = self.tcx.types.f32;
let f64 = self.tcx.types.f64;
match &self.tcx.item_name(def_id).as_str()[..] {
let intrinsic_name = &self.tcx.item_name(def_id).as_str()[..];
match intrinsic_name {
"add_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Add, &args[0], &args[1], dest, dest_layout)?,
"sub_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Sub, &args[0], &args[1], dest, dest_layout)?,
"mul_with_overflow" => self.intrinsic_with_overflow(mir::BinOp::Mul, &args[0], &args[1], dest, dest_layout)?,
@ -64,30 +65,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
self.memory.copy(src, dest, count as usize * elem_size, elem_align)?;
}
"ctpop" => {
"ctpop" |
"cttz" |
"ctlz" |
"bswap" => {
let elem_ty = substs.type_at(0);
let elem_size = self.type_size(elem_ty);
let num = self.value_to_primval(args_ptrs[2], elem_ty)?.expect_int("ctpop second arg not integral");
let num = num.count_ones();
self.memory.write_uint(dest, num.into(), elem_size)?;
}
"ctlz" => {
let elem_ty = substs.type_at(0);
let elem_size = self.type_size(elem_ty);
let num = self.value_to_primval(args_ptrs[2], elem_ty)?;
let num = match num {
PrimVal::I8(i) => i.leading_zeros(),
PrimVal::U8(i) => i.leading_zeros(),
PrimVal::I16(i) => i.leading_zeros(),
PrimVal::U16(i) => i.leading_zeros(),
PrimVal::I32(i) => i.leading_zeros(),
PrimVal::U32(i) => i.leading_zeros(),
PrimVal::I64(i) => i.leading_zeros(),
PrimVal::U64(i) => i.leading_zeros(),
_ => bug!("ctlz called with non-integer type"),
};
self.memory.write_uint(dest, num.into(), elem_size)?;
let num = self.value_to_primval(args_ptrs[0], elem_ty)?;
let num = numeric_intrinsic(intrinsic_name, num);
self.memory.write_primval(dest, num)?;
}
"discriminant_value" => {
@ -350,3 +335,54 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
self.tcx.normalize_associated_type(&f.ty(self.tcx, param_substs))
}
}
fn numeric_intrinsic(name: &str, val: PrimVal) -> PrimVal {
use primval::PrimVal::*;
match name {
"ctpop" => match val {
I8(i) => I8(i.count_ones() as i8),
U8(i) => U8(i.count_ones() as u8),
I16(i) => I16(i.count_ones() as i16),
U16(i) => U16(i.count_ones() as u16),
I32(i) => I32(i.count_ones() as i32),
U32(i) => U32(i.count_ones() as u32),
I64(i) => I64(i.count_ones() as i64),
U64(i) => U64(i.count_ones() as u64),
other => bug!("invalid `ctpop` argument: {:?}", other),
},
"cttz" => match val {
I8(i) => I8(i.trailing_zeros() as i8),
U8(i) => U8(i.trailing_zeros() as u8),
I16(i) => I16(i.trailing_zeros() as i16),
U16(i) => U16(i.trailing_zeros() as u16),
I32(i) => I32(i.trailing_zeros() as i32),
U32(i) => U32(i.trailing_zeros() as u32),
I64(i) => I64(i.trailing_zeros() as i64),
U64(i) => U64(i.trailing_zeros() as u64),
other => bug!("invalid `cttz` argument: {:?}", other),
},
"ctlz" => match val {
I8(i) => I8(i.leading_zeros() as i8),
U8(i) => U8(i.leading_zeros() as u8),
I16(i) => I16(i.leading_zeros() as i16),
U16(i) => U16(i.leading_zeros() as u16),
I32(i) => I32(i.leading_zeros() as i32),
U32(i) => U32(i.leading_zeros() as u32),
I64(i) => I64(i.leading_zeros() as i64),
U64(i) => U64(i.leading_zeros() as u64),
other => bug!("invalid `ctlz` argument: {:?}", other),
},
"bswap" => match val {
I8(i) => I8(i.swap_bytes() as i8),
U8(i) => U8(i.swap_bytes() as u8),
I16(i) => I16(i.swap_bytes() as i16),
U16(i) => U16(i.swap_bytes() as u16),
I32(i) => I32(i.swap_bytes() as i32),
U32(i) => U32(i.swap_bytes() as u32),
I64(i) => I64(i.swap_bytes() as i64),
U64(i) => U64(i.swap_bytes() as u64),
other => bug!("invalid `bswap` argument: {:?}", other),
},
_ => bug!("not a numeric intrinsic: {}", name),
}
}

View File

@ -186,13 +186,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
let mir = self.load_mir(resolved_def_id)?;
let (return_ptr, return_to_block) = match destination {
Some((ptr, block)) => (Some(ptr), StackPopCleanup::Goto(block)),
None => (None, StackPopCleanup::None),
Some((ptr, block)) => (ptr, StackPopCleanup::Goto(block)),
None => (Pointer::never_ptr(), StackPopCleanup::None),
};
self.push_stack_frame(resolved_def_id, span, mir, resolved_substs, return_ptr, return_to_block)?;
for (i, (arg_val, arg_ty)) in args.into_iter().enumerate() {
let dest = self.frame().locals[i];
// argument start at index 1, since index 0 is reserved for the return allocation
let dest = self.frame().locals[i + 1];
self.write_value(arg_val, dest, arg_ty)?;
}

View File

@ -56,10 +56,10 @@ impl Pointer {
self.alloc_id == ZST_ALLOC_ID
}
pub fn to_int<'tcx>(&self) -> EvalResult<'tcx, usize> {
if self.points_to_zst() {
Ok(self.offset)
} else {
Err(EvalError::ReadPointerAsBytes)
match self.alloc_id {
NEVER_ALLOC_ID |
ZST_ALLOC_ID => Ok(self.offset),
_ => Err(EvalError::ReadPointerAsBytes),
}
}
pub fn from_int(i: usize) -> Self {
@ -74,6 +74,12 @@ impl Pointer {
offset: 0,
}
}
pub fn never_ptr() -> Self {
Pointer {
alloc_id: NEVER_ALLOC_ID,
offset: 0,
}
}
}
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
@ -115,6 +121,7 @@ pub struct Memory<'a, 'tcx> {
}
const ZST_ALLOC_ID: AllocId = AllocId(0);
const NEVER_ALLOC_ID: AllocId = AllocId(1);
impl<'a, 'tcx> Memory<'a, 'tcx> {
pub fn new(layout: &'a TargetDataLayout, max_memory: usize) -> Self {
@ -122,7 +129,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
alloc_map: HashMap::new(),
functions: HashMap::new(),
function_alloc_cache: HashMap::new(),
next_id: AllocId(1),
next_id: AllocId(2),
layout: layout,
memory_size: max_memory,
memory_usage: 0,

View File

@ -0,0 +1,208 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
pub trait DeclaredTrait {
type Type;
}
impl DeclaredTrait for i32 {
type Type = i32;
}
pub trait WhereTrait {
type Type;
}
impl WhereTrait for i32 {
type Type = i32;
}
// Make sure we don't add a bound that just shares a name with an associated
// type.
pub mod module {
pub type Type = i32;
}
#[derive(PartialEq, Debug)]
struct PrivateStruct<T>(T);
#[derive(PartialEq, Debug)]
struct TupleStruct<A, B: DeclaredTrait, C>(
module::Type,
Option<module::Type>,
A,
PrivateStruct<A>,
B,
B::Type,
Option<B::Type>,
<B as DeclaredTrait>::Type,
Option<<B as DeclaredTrait>::Type>,
C,
C::Type,
Option<C::Type>,
<C as WhereTrait>::Type,
Option<<C as WhereTrait>::Type>,
<i32 as DeclaredTrait>::Type,
) where C: WhereTrait;
#[derive(PartialEq, Debug)]
pub struct Struct<A, B: DeclaredTrait, C> where C: WhereTrait {
m1: module::Type,
m2: Option<module::Type>,
a1: A,
a2: PrivateStruct<A>,
b: B,
b1: B::Type,
b2: Option<B::Type>,
b3: <B as DeclaredTrait>::Type,
b4: Option<<B as DeclaredTrait>::Type>,
c: C,
c1: C::Type,
c2: Option<C::Type>,
c3: <C as WhereTrait>::Type,
c4: Option<<C as WhereTrait>::Type>,
d: <i32 as DeclaredTrait>::Type,
}
#[derive(PartialEq, Debug)]
enum Enum<A, B: DeclaredTrait, C> where C: WhereTrait {
Unit,
Seq(
module::Type,
Option<module::Type>,
A,
PrivateStruct<A>,
B,
B::Type,
Option<B::Type>,
<B as DeclaredTrait>::Type,
Option<<B as DeclaredTrait>::Type>,
C,
C::Type,
Option<C::Type>,
<C as WhereTrait>::Type,
Option<<C as WhereTrait>::Type>,
<i32 as DeclaredTrait>::Type,
),
Map {
m1: module::Type,
m2: Option<module::Type>,
a1: A,
a2: PrivateStruct<A>,
b: B,
b1: B::Type,
b2: Option<B::Type>,
b3: <B as DeclaredTrait>::Type,
b4: Option<<B as DeclaredTrait>::Type>,
c: C,
c1: C::Type,
c2: Option<C::Type>,
c3: <C as WhereTrait>::Type,
c4: Option<<C as WhereTrait>::Type>,
d: <i32 as DeclaredTrait>::Type,
},
}
fn main() {
let e: Enum<
i32,
i32,
i32,
> = Enum::Seq(
0,
None,
0,
PrivateStruct(0),
0,
0,
None,
0,
None,
0,
0,
None,
0,
None,
0,
);
assert_eq!(e, e);
let e: Enum<
i32,
i32,
i32,
> = Enum::Map {
m1: 0,
m2: None,
a1: 0,
a2: PrivateStruct(0),
b: 0,
b1: 0,
b2: None,
b3: 0,
b4: None,
c: 0,
c1: 0,
c2: None,
c3: 0,
c4: None,
d: 0,
};
assert_eq!(e, e);
let e: TupleStruct<
i32,
i32,
i32,
> = TupleStruct(
0,
None,
0,
PrivateStruct(0),
0,
0,
None,
0,
None,
0,
0,
None,
0,
None,
0,
);
assert_eq!(e, e);
let e: Struct<
i32,
i32,
i32,
> = Struct {
m1: 0,
m2: None,
a1: 0,
a2: PrivateStruct(0),
b: 0,
b1: 0,
b2: None,
b3: 0,
b4: None,
c: 0,
c1: 0,
c2: None,
c3: 0,
c4: None,
d: 0,
};
assert_eq!(e, e);
let e = Enum::Unit::<i32, i32, i32>;
assert_eq!(e, e);
}

34
tests/run-pass/enums.rs Normal file
View File

@ -0,0 +1,34 @@
enum MyEnum {
MyEmptyVariant,
MyNewtypeVariant(i32),
MyTupleVariant(i32, i32),
MyStructVariant {
my_first_field: i32,
my_second_field: i32,
}
}
fn test(me: MyEnum) {
match me {
MyEnum::MyEmptyVariant => {},
MyEnum::MyNewtypeVariant(ref val) => assert_eq!(val, &42),
MyEnum::MyTupleVariant(ref a, ref b) => {
assert_eq!(a, &43);
assert_eq!(b, &44);
},
MyEnum::MyStructVariant { ref my_first_field, ref my_second_field } => {
assert_eq!(my_first_field, &45);
assert_eq!(my_second_field, &46);
},
}
}
fn main() {
test(MyEnum::MyEmptyVariant);
test(MyEnum::MyNewtypeVariant(42));
test(MyEnum::MyTupleVariant(43, 44));
test(MyEnum::MyStructVariant{
my_first_field: 45,
my_second_field: 46,
});
}

View File

@ -0,0 +1,105 @@
// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
#![feature(intrinsics)]
mod rusti {
extern "rust-intrinsic" {
pub fn ctpop<T>(x: T) -> T;
pub fn ctlz<T>(x: T) -> T;
pub fn cttz<T>(x: T) -> T;
pub fn bswap<T>(x: T) -> T;
}
}
pub fn main() {
unsafe {
use rusti::*;
assert_eq!(ctpop(0u8), 0); assert_eq!(ctpop(0i8), 0);
assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0);
assert_eq!(ctpop(0u32), 0); assert_eq!(ctpop(0i32), 0);
assert_eq!(ctpop(0u64), 0); assert_eq!(ctpop(0i64), 0);
assert_eq!(ctpop(1u8), 1); assert_eq!(ctpop(1i8), 1);
assert_eq!(ctpop(1u16), 1); assert_eq!(ctpop(1i16), 1);
assert_eq!(ctpop(1u32), 1); assert_eq!(ctpop(1i32), 1);
assert_eq!(ctpop(1u64), 1); assert_eq!(ctpop(1i64), 1);
assert_eq!(ctpop(10u8), 2); assert_eq!(ctpop(10i8), 2);
assert_eq!(ctpop(10u16), 2); assert_eq!(ctpop(10i16), 2);
assert_eq!(ctpop(10u32), 2); assert_eq!(ctpop(10i32), 2);
assert_eq!(ctpop(10u64), 2); assert_eq!(ctpop(10i64), 2);
assert_eq!(ctpop(100u8), 3); assert_eq!(ctpop(100i8), 3);
assert_eq!(ctpop(100u16), 3); assert_eq!(ctpop(100i16), 3);
assert_eq!(ctpop(100u32), 3); assert_eq!(ctpop(100i32), 3);
assert_eq!(ctpop(100u64), 3); assert_eq!(ctpop(100i64), 3);
assert_eq!(ctpop(-1i8 as u8), 8); assert_eq!(ctpop(-1i8), 8);
assert_eq!(ctpop(-1i16 as u16), 16); assert_eq!(ctpop(-1i16), 16);
assert_eq!(ctpop(-1i32 as u32), 32); assert_eq!(ctpop(-1i32), 32);
assert_eq!(ctpop(-1i64 as u64), 64); assert_eq!(ctpop(-1i64), 64);
assert_eq!(ctlz(0u8), 8); assert_eq!(ctlz(0i8), 8);
assert_eq!(ctlz(0u16), 16); assert_eq!(ctlz(0i16), 16);
assert_eq!(ctlz(0u32), 32); assert_eq!(ctlz(0i32), 32);
assert_eq!(ctlz(0u64), 64); assert_eq!(ctlz(0i64), 64);
assert_eq!(ctlz(1u8), 7); assert_eq!(ctlz(1i8), 7);
assert_eq!(ctlz(1u16), 15); assert_eq!(ctlz(1i16), 15);
assert_eq!(ctlz(1u32), 31); assert_eq!(ctlz(1i32), 31);
assert_eq!(ctlz(1u64), 63); assert_eq!(ctlz(1i64), 63);
assert_eq!(ctlz(10u8), 4); assert_eq!(ctlz(10i8), 4);
assert_eq!(ctlz(10u16), 12); assert_eq!(ctlz(10i16), 12);
assert_eq!(ctlz(10u32), 28); assert_eq!(ctlz(10i32), 28);
assert_eq!(ctlz(10u64), 60); assert_eq!(ctlz(10i64), 60);
assert_eq!(ctlz(100u8), 1); assert_eq!(ctlz(100i8), 1);
assert_eq!(ctlz(100u16), 9); assert_eq!(ctlz(100i16), 9);
assert_eq!(ctlz(100u32), 25); assert_eq!(ctlz(100i32), 25);
assert_eq!(ctlz(100u64), 57); assert_eq!(ctlz(100i64), 57);
assert_eq!(cttz(-1i8 as u8), 0); assert_eq!(cttz(-1i8), 0);
assert_eq!(cttz(-1i16 as u16), 0); assert_eq!(cttz(-1i16), 0);
assert_eq!(cttz(-1i32 as u32), 0); assert_eq!(cttz(-1i32), 0);
assert_eq!(cttz(-1i64 as u64), 0); assert_eq!(cttz(-1i64), 0);
assert_eq!(cttz(0u8), 8); assert_eq!(cttz(0i8), 8);
assert_eq!(cttz(0u16), 16); assert_eq!(cttz(0i16), 16);
assert_eq!(cttz(0u32), 32); assert_eq!(cttz(0i32), 32);
assert_eq!(cttz(0u64), 64); assert_eq!(cttz(0i64), 64);
assert_eq!(cttz(1u8), 0); assert_eq!(cttz(1i8), 0);
assert_eq!(cttz(1u16), 0); assert_eq!(cttz(1i16), 0);
assert_eq!(cttz(1u32), 0); assert_eq!(cttz(1i32), 0);
assert_eq!(cttz(1u64), 0); assert_eq!(cttz(1i64), 0);
assert_eq!(cttz(10u8), 1); assert_eq!(cttz(10i8), 1);
assert_eq!(cttz(10u16), 1); assert_eq!(cttz(10i16), 1);
assert_eq!(cttz(10u32), 1); assert_eq!(cttz(10i32), 1);
assert_eq!(cttz(10u64), 1); assert_eq!(cttz(10i64), 1);
assert_eq!(cttz(100u8), 2); assert_eq!(cttz(100i8), 2);
assert_eq!(cttz(100u16), 2); assert_eq!(cttz(100i16), 2);
assert_eq!(cttz(100u32), 2); assert_eq!(cttz(100i32), 2);
assert_eq!(cttz(100u64), 2); assert_eq!(cttz(100i64), 2);
assert_eq!(bswap(0x0Au8), 0x0A); // no-op
assert_eq!(bswap(0x0Ai8), 0x0A); // no-op
assert_eq!(bswap(0x0A0Bu16), 0x0B0A);
assert_eq!(bswap(0x0A0Bi16), 0x0B0A);
assert_eq!(bswap(0x0ABBCC0Du32), 0x0DCCBB0A);
assert_eq!(bswap(0x0ABBCC0Di32), 0x0DCCBB0A);
assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201);
assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201);
}
}