Skip to content

Commit 6c9576c

Browse files
committed
Implelemnted 8, 16, and 128 bit bitreverse intrinsic
1 parent 821558a commit 6c9576c

File tree

3 files changed

+246
-0
lines changed

3 files changed

+246
-0
lines changed

src/builtin/mod.rs

Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,7 @@ pub fn insert_ffi_functions(asm: &mut Assembly, tcx: TyCtxt) {
205205
swap_at_generic(asm);
206206
bounds_check(asm);
207207
atomic::atomics(asm);
208+
bitreverse_u128(asm);
208209
let c_void = crate::r#type::c_void(tcx);
209210

210211
asm.add_typedef(TypeDef::new(
@@ -1328,3 +1329,198 @@ add_method_from_trees!(
13281329
)],
13291330
vec![Some("thread_handle".into()), Some("result_ptr".into())]
13301331
);
1332+
1333+
fn shr_u128(value: CILNode, shift: CILNode) -> CILNode {
1334+
call!(
1335+
CallSite::boxed(
1336+
DotnetTypeRef::uint_128().into(),
1337+
"op_RightShift".into(),
1338+
FnSig::new(&[Type::U128, Type::I32], Type::U128),
1339+
true,
1340+
),
1341+
[value, shift]
1342+
)
1343+
}
1344+
fn or_u128(lhs: CILNode, rhs: CILNode) -> CILNode {
1345+
call!(
1346+
CallSite::boxed(
1347+
DotnetTypeRef::uint_128().into(),
1348+
"op_BitwiseOr".into(),
1349+
FnSig::new(&[Type::U128, Type::U128], Type::U128),
1350+
true,
1351+
),
1352+
[lhs, rhs]
1353+
)
1354+
}
1355+
fn and_u128(lhs: CILNode, rhs: CILNode) -> CILNode {
1356+
call!(
1357+
CallSite::boxed(
1358+
DotnetTypeRef::uint_128().into(),
1359+
"op_BitwiseAnd".into(),
1360+
FnSig::new(&[Type::U128, Type::U128], Type::U128),
1361+
true,
1362+
),
1363+
[lhs, rhs]
1364+
)
1365+
}
1366+
fn shl_u128(value: CILNode, shift: CILNode) -> CILNode {
1367+
call!(
1368+
CallSite::boxed(
1369+
DotnetTypeRef::uint_128().into(),
1370+
"op_LeftShift".into(),
1371+
FnSig::new(&[Type::U128, Type::I32], Type::U128),
1372+
true,
1373+
),
1374+
[value, shift]
1375+
)
1376+
}
1377+
fn const_u128(value: u128) -> CILNode {
1378+
let low = u128_low_u64(value);
1379+
let high = (value >> 64) as u64;
1380+
let ctor_sig = FnSig::new(
1381+
&[
1382+
Type::ManagedReference(Type::U128.into()),
1383+
Type::U64,
1384+
Type::U64,
1385+
],
1386+
Type::Void,
1387+
);
1388+
CILNode::NewObj(Box::new(CallOpArgs {
1389+
site: CallSite::boxed(
1390+
Some(DotnetTypeRef::uint_128()),
1391+
".ctor".into(),
1392+
ctor_sig,
1393+
false,
1394+
),
1395+
args: [conv_u64!(ldc_u64!(high)), conv_u64!(ldc_u64!(low))].into(),
1396+
}))
1397+
}
1398+
add_method_from_trees!(
1399+
bitreverse_u128,
1400+
&[Type::U128],
1401+
Type::U128,
1402+
vec![BasicBlock::new(
1403+
vec![
1404+
CILRoot::STLoc {
1405+
local: 0,
1406+
tree: or_u128(
1407+
and_u128(
1408+
shr_u128(CILNode::LDArg(0), ldc_i32!(1)),
1409+
const_u128(0x5555_5555_5555_5555_5555_5555_5555_5555_u128),
1410+
),
1411+
shl_u128(
1412+
and_u128(
1413+
CILNode::LDArg(0),
1414+
const_u128(0x5555_5555_5555_5555_5555_5555_5555_5555_u128),
1415+
),
1416+
ldc_i32!(1),
1417+
),
1418+
),
1419+
}
1420+
.into(),
1421+
CILRoot::STLoc {
1422+
local: 0,
1423+
tree: or_u128(
1424+
and_u128(
1425+
shr_u128(CILNode::LDLoc(0), ldc_i32!(2)),
1426+
const_u128(0x3333_3333_3333_3333_3333_3333_3333_3333_u128),
1427+
),
1428+
shl_u128(
1429+
and_u128(
1430+
CILNode::LDLoc(0),
1431+
const_u128(0x3333_3333_3333_3333_3333_3333_3333_3333_u128),
1432+
),
1433+
ldc_i32!(2),
1434+
),
1435+
),
1436+
}
1437+
.into(),
1438+
CILRoot::STLoc {
1439+
local: 0,
1440+
tree: or_u128(
1441+
and_u128(
1442+
shr_u128(CILNode::LDLoc(0), ldc_i32!(4)),
1443+
const_u128(0x0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_u128),
1444+
),
1445+
shl_u128(
1446+
and_u128(
1447+
CILNode::LDLoc(0),
1448+
const_u128(0x0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_0F0F_u128),
1449+
),
1450+
ldc_i32!(4),
1451+
),
1452+
),
1453+
}
1454+
.into(),
1455+
CILRoot::STLoc {
1456+
local: 0,
1457+
tree: or_u128(
1458+
and_u128(
1459+
shr_u128(CILNode::LDLoc(0), ldc_i32!(8)),
1460+
const_u128(0x00FF_00FF_00FF_00FF_00FF_00FF_00FF_00FF_u128),
1461+
),
1462+
shl_u128(
1463+
and_u128(
1464+
CILNode::LDLoc(0),
1465+
const_u128(0x00FF_00FF_00FF_00FF_00FF_00FF_00FF_00FF_u128),
1466+
),
1467+
ldc_i32!(8),
1468+
),
1469+
),
1470+
}
1471+
.into(),
1472+
CILRoot::STLoc {
1473+
local: 0,
1474+
tree: or_u128(
1475+
and_u128(
1476+
shr_u128(CILNode::LDLoc(0), ldc_i32!(16)),
1477+
const_u128(0x0000_FFFF_0000_FFFF_0000_FFFF_0000_FFFF_u128),
1478+
),
1479+
shl_u128(
1480+
and_u128(
1481+
CILNode::LDLoc(0),
1482+
const_u128(0x0000_FFFF_0000_FFFF_0000_FFFF_0000_FFFF_u128),
1483+
),
1484+
ldc_i32!(16),
1485+
),
1486+
),
1487+
}
1488+
.into(),
1489+
CILRoot::STLoc {
1490+
local: 0,
1491+
tree: or_u128(
1492+
and_u128(
1493+
shr_u128(CILNode::LDLoc(0), ldc_i32!(32)),
1494+
const_u128(0x0000_0000_FFFF_FFFF_0000_0000_FFFF_FFFF_u128),
1495+
),
1496+
shl_u128(
1497+
and_u128(
1498+
CILNode::LDLoc(0),
1499+
const_u128(0x0000_0000_FFFF_FFFF_0000_0000_FFFF_FFFF_u128),
1500+
),
1501+
ldc_i32!(32),
1502+
),
1503+
),
1504+
}
1505+
.into(),
1506+
CILRoot::Ret {
1507+
tree: or_u128(
1508+
shr_u128(CILNode::LDLoc(0), ldc_i32!(64)),
1509+
shl_u128(CILNode::LDLoc(0), ldc_i32!(64)),
1510+
),
1511+
}
1512+
.into(),
1513+
],
1514+
0,
1515+
None
1516+
)],
1517+
vec![(Some("n".into()), Type::U128)],
1518+
vec![
1519+
Some("buf1".into()),
1520+
Some("buf2".into()),
1521+
Some("size".into())
1522+
]
1523+
);
1524+
fn u128_low_u64(value: u128) -> u64 {
1525+
u64::try_from(value & u128::from(u64::MAX)).expect("trucating cast error")
1526+
}

src/terminator/intrinsics/ints.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,26 @@ pub fn bitreverse<'tcx>(
657657
Type::I8 => conv_i8!(bitreverse_u8(val)),
658658
Type::U16 => bitreverse_u16(val),
659659
Type::I16 => conv_i16!(bitreverse_u16(conv_u16!(val))),
660+
Type::U128 => call!(
661+
CallSite::builtin(
662+
"bitreverse_u128".into(),
663+
FnSig::new(&[Type::U128], Type::U128,),
664+
true
665+
),
666+
[val]
667+
),
668+
Type::I128 => crate::casts::int_to_int(
669+
Type::U128,
670+
&Type::I128,
671+
call!(
672+
CallSite::builtin(
673+
"bitreverse_u128".into(),
674+
FnSig::new(&[Type::U128], Type::U128,),
675+
true
676+
),
677+
[crate::casts::int_to_int(Type::I128, &Type::U128, val)]
678+
),
679+
),
660680
_ => todo!("can't yet bitreverse {val_tpe:?}"),
661681
},
662682
ctx,

test/arthm/num_test.rs

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,4 +69,34 @@ fn main() {
6969
for b in 0..u16::MAX {
7070
test_eq!(bitreverse_u16(b), core::intrinsics::bitreverse(b));
7171
}
72+
#[cfg(not(debug_assertions))]
73+
fn bitreverse_u128(mut n: u128) -> u128 {
74+
n = (n >> 1) & 0x55555555555555555555555555555555u128
75+
| (n & 0x55555555555555555555555555555555u128) << 1;
76+
n = (n >> 2) & 0x33333333333333333333333333333333u128
77+
| (n & 0x33333333333333333333333333333333u128) << 2;
78+
n = (n >> 4) & 0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0Fu128
79+
| (n & 0x0F0F0F0F0F0F0F0F0F0F0F0F0F0F0F0Fu128) << 4;
80+
n = (n >> 8) & 0x00FF00FF00FF00FF00FF00FF00FF00FFu128
81+
| (n & 0x00FF00FF00FF00FF00FF00FF00FF00FFu128) << 8;
82+
n = (n >> 16) & 0x0000FFFF0000FFFF0000FFFF0000FFFFu128
83+
| (n & 0x0000FFFF0000FFFF0000FFFF0000FFFFu128) << 16;
84+
n = (n >> 32) & 0x00000000FFFFFFFF00000000FFFFFFFFu128
85+
| (n & 0x00000000FFFFFFFF00000000FFFFFFFFu128) << 32;
86+
n = (n >> 64) | (n << 64);
87+
n
88+
}
89+
#[cfg(not(debug_assertions))]
90+
for b in 0..u16::MAX {
91+
let b = b as u128 + b as u128 * (u64::MAX as u128);
92+
assert_eq!(bitreverse_u128(b), core::intrinsics::bitreverse(b));
93+
}
94+
#[cfg(not(debug_assertions))]
95+
for b in 0..u16::MAX {
96+
let b = b as i128 + b as i128 * (u64::MAX as i128);
97+
assert_eq!(
98+
bitreverse_u128(b as u128) as i128,
99+
core::intrinsics::bitreverse(b)
100+
);
101+
}
72102
}

0 commit comments

Comments
 (0)