Skip to content

Commit

Permalink
Implelemnted 8, 16, and 128 bit bitreverse intrinsic
Browse files Browse the repository at this point in the history
  • Loading branch information
FractalFir committed Aug 9, 2024
1 parent 821558a commit 6c9576c
Show file tree
Hide file tree
Showing 3 changed files with 246 additions and 0 deletions.
196 changes: 196 additions & 0 deletions src/builtin/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,7 @@ pub fn insert_ffi_functions(asm: &mut Assembly, tcx: TyCtxt) {
swap_at_generic(asm);
bounds_check(asm);
atomic::atomics(asm);
bitreverse_u128(asm);
let c_void = crate::r#type::c_void(tcx);

asm.add_typedef(TypeDef::new(
Expand Down Expand Up @@ -1328,3 +1329,198 @@ add_method_from_trees!(
)],
vec![Some("thread_handle".into()), Some("result_ptr".into())]
);

fn shr_u128(value: CILNode, shift: CILNode) -> CILNode {
call!(
CallSite::boxed(
DotnetTypeRef::uint_128().into(),
"op_RightShift".into(),
FnSig::new(&[Type::U128, Type::I32], Type::U128),
true,
),
[value, shift]
)
}
fn or_u128(lhs: CILNode, rhs: CILNode) -> CILNode {
call!(
CallSite::boxed(
DotnetTypeRef::uint_128().into(),
"op_BitwiseOr".into(),
FnSig::new(&[Type::U128, Type::U128], Type::U128),
true,
),
[lhs, rhs]
)
}
fn and_u128(lhs: CILNode, rhs: CILNode) -> CILNode {
call!(
CallSite::boxed(
DotnetTypeRef::uint_128().into(),
"op_BitwiseAnd".into(),
FnSig::new(&[Type::U128, Type::U128], Type::U128),
true,
),
[lhs, rhs]
)
}
fn shl_u128(value: CILNode, shift: CILNode) -> CILNode {
call!(
CallSite::boxed(
DotnetTypeRef::uint_128().into(),
"op_LeftShift".into(),
FnSig::new(&[Type::U128, Type::I32], Type::U128),
true,
),
[value, shift]
)
}
fn const_u128(value: u128) -> CILNode {
let low = u128_low_u64(value);
let high = (value >> 64) as u64;
let ctor_sig = FnSig::new(
&[
Type::ManagedReference(Type::U128.into()),
Type::U64,
Type::U64,
],
Type::Void,
);
CILNode::NewObj(Box::new(CallOpArgs {
site: CallSite::boxed(
Some(DotnetTypeRef::uint_128()),
".ctor".into(),
ctor_sig,
false,
),
args: [conv_u64!(ldc_u64!(high)), conv_u64!(ldc_u64!(low))].into(),
}))
}
add_method_from_trees!(
bitreverse_u128,
&[Type::U128],
Type::U128,
vec![BasicBlock::new(
vec![
CILRoot::STLoc {
local: 0,
tree: or_u128(
and_u128(
shr_u128(CILNode::LDArg(0), ldc_i32!(1)),
const_u128(0x5555_5555_5555_5555_5555_5555_5555_5555_u128),
),
shl_u128(
and_u128(
CILNode::LDArg(0),
const_u128(0x5555_5555_5555_5555_5555_5555_5555_5555_u128),
),
ldc_i32!(1),
),
),
}
.into(),
CILRoot::STLoc {
local: 0,
tree: or_u128(
and_u128(
shr_u128(CILNode::LDLoc(0), ldc_i32!(2)),
const_u128(0x3333_3333_3333_3333_3333_3333_3333_3333_u128),
),
shl_u128(
and_u128(
CILNode::LDLoc(0),
const_u128(0x3333_3333_3333_3333_3333_3333_3333_3333_u128),
),
ldc_i32!(2),
),
),
}
.into(),
CILRoot::STLoc {
local: 0,
tree: or_u128(
and_u128(
shr_u128(CILNode::LDLoc(0), ldc_i32!(4)),
const_u128(0x0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_u128),
),
shl_u128(
and_u128(
CILNode::LDLoc(0),
const_u128(0x0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_u128),
),
ldc_i32!(4),
),
),
}
.into(),
CILRoot::STLoc {
local: 0,
tree: or_u128(
and_u128(
shr_u128(CILNode::LDLoc(0), ldc_i32!(8)),
const_u128(0x00FF_00FF_00FF_00FF_00FF_00FF_00FF_00FF_u128),
),
shl_u128(
and_u128(
CILNode::LDLoc(0),
const_u128(0x00FF_00FF_00FF_00FF_00FF_00FF_00FF_00FF_u128),
),
ldc_i32!(8),
),
),
}
.into(),
CILRoot::STLoc {
local: 0,
tree: or_u128(
and_u128(
shr_u128(CILNode::LDLoc(0), ldc_i32!(16)),
const_u128(0x0000_FFFF_0000_FFFF_0000_FFFF_0000_FFFF_u128),
),
shl_u128(
and_u128(
CILNode::LDLoc(0),
const_u128(0x0000_FFFF_0000_FFFF_0000_FFFF_0000_FFFF_u128),
),
ldc_i32!(16),
),
),
}
.into(),
CILRoot::STLoc {
local: 0,
tree: or_u128(
and_u128(
shr_u128(CILNode::LDLoc(0), ldc_i32!(32)),
const_u128(0x0000_0000_FFFF_FFFF_0000_0000_FFFF_FFFF_u128),
),
shl_u128(
and_u128(
CILNode::LDLoc(0),
const_u128(0x0000_0000_FFFF_FFFF_0000_0000_FFFF_FFFF_u128),
),
ldc_i32!(32),
),
),
}
.into(),
CILRoot::Ret {
tree: or_u128(
shr_u128(CILNode::LDLoc(0), ldc_i32!(64)),
shl_u128(CILNode::LDLoc(0), ldc_i32!(64)),
),
}
.into(),
],
0,
None
)],
vec![(Some("n".into()), Type::U128)],
vec![
Some("buf1".into()),
Some("buf2".into()),
Some("size".into())
]
);
fn u128_low_u64(value: u128) -> u64 {
u64::try_from(value & u128::from(u64::MAX)).expect("trucating cast error")
}
20 changes: 20 additions & 0 deletions src/terminator/intrinsics/ints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -657,6 +657,26 @@ pub fn bitreverse<'tcx>(
Type::I8 => conv_i8!(bitreverse_u8(val)),
Type::U16 => bitreverse_u16(val),
Type::I16 => conv_i16!(bitreverse_u16(conv_u16!(val))),
Type::U128 => call!(
CallSite::builtin(
"bitreverse_u128".into(),
FnSig::new(&[Type::U128], Type::U128,),
true
),
[val]
),
Type::I128 => crate::casts::int_to_int(
Type::U128,
&Type::I128,
call!(
CallSite::builtin(
"bitreverse_u128".into(),
FnSig::new(&[Type::U128], Type::U128,),
true
),
[crate::casts::int_to_int(Type::I128, &Type::U128, val)]
),
),
_ => todo!("can't yet bitreverse {val_tpe:?}"),
},
ctx,
Expand Down
30 changes: 30 additions & 0 deletions test/arthm/num_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,4 +69,34 @@ fn main() {
for b in 0..u16::MAX {
test_eq!(bitreverse_u16(b), core::intrinsics::bitreverse(b));
}
#[cfg(not(debug_assertions))]
fn bitreverse_u128(mut n: u128) -> u128 {
n = (n >> 1) & 0x55555555555555555555555555555555u128
| (n & 0x55555555555555555555555555555555u128) << 1;
n = (n >> 2) & 0x33333333333333333333333333333333u128
| (n & 0x33333333333333333333333333333333u128) << 2;
n = (n >> 4) & 0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0Fu128
| (n & 0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0Fu128) << 4;
n = (n >> 8) & 0x00FF00FF00FF00FF00FF00FF00FF00FFu128
| (n & 0x00FF00FF00FF00FF00FF00FF00FF00FFu128) << 8;
n = (n >> 16) & 0x0000FFFF0000FFFF0000FFFF0000FFFFu128
| (n & 0x0000FFFF0000FFFF0000FFFF0000FFFFu128) << 16;
n = (n >> 32) & 0x00000000FFFFFFFF00000000FFFFFFFFu128
| (n & 0x00000000FFFFFFFF00000000FFFFFFFFu128) << 32;
n = (n >> 64) | (n << 64);
n
}
#[cfg(not(debug_assertions))]
for b in 0..u16::MAX {
let b = b as u128 + b as u128 * (u64::MAX as u128);
assert_eq!(bitreverse_u128(b), core::intrinsics::bitreverse(b));
}
#[cfg(not(debug_assertions))]
for b in 0..u16::MAX {
let b = b as i128 + b as i128 * (u64::MAX as i128);
assert_eq!(
bitreverse_u128(b as u128) as i128,
core::intrinsics::bitreverse(b)
);
}
}

0 comments on commit 6c9576c

Please sign in to comment.