Skip to content

Commit 274e830

Browse files
committed
Add write_bytes and ctlz intrinsics
1 parent 59420af commit 274e830

File tree

6 files changed

+93
-13
lines changed

6 files changed

+93
-13
lines changed

crates/hir-ty/src/consteval/tests.rs

+12
Original file line numberDiff line numberDiff line change
@@ -1724,6 +1724,18 @@ fn function_pointer() {
17241724
"#,
17251725
5,
17261726
);
1727+
check_number(
1728+
r#"
1729+
fn add2(x: u8) -> u8 {
1730+
x + 2
1731+
}
1732+
const GOAL: u8 = {
1733+
let plus2 = add2 as fn(u8) -> u8;
1734+
plus2(3)
1735+
};
1736+
"#,
1737+
5,
1738+
);
17271739
check_number(
17281740
r#"
17291741
//- minicore: coerce_unsized, index, slice

crates/hir-ty/src/consteval/tests/intrinsics.rs

+32
Original file line numberDiff line numberDiff line change
@@ -510,6 +510,24 @@ fn copy_nonoverlapping() {
510510
);
511511
}
512512

513+
#[test]
514+
fn write_bytes() {
515+
check_number(
516+
r#"
517+
extern "rust-intrinsic" {
518+
fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
519+
}
520+
521+
const GOAL: i32 = unsafe {
522+
let mut x = 2;
523+
write_bytes(&mut x, 5, 1);
524+
x
525+
};
526+
"#,
527+
0x05050505,
528+
);
529+
}
530+
513531
#[test]
514532
fn copy() {
515533
check_number(
@@ -545,6 +563,20 @@ fn ctpop() {
545563
);
546564
}
547565

566+
#[test]
567+
fn ctlz() {
568+
check_number(
569+
r#"
570+
extern "rust-intrinsic" {
571+
pub fn ctlz<T: Copy>(x: T) -> T;
572+
}
573+
574+
const GOAL: u8 = ctlz(0b0001_1100_u8);
575+
"#,
576+
3,
577+
);
578+
}
579+
548580
#[test]
549581
fn cttz() {
550582
check_number(

crates/hir-ty/src/mir/eval.rs

+12-10
Original file line numberDiff line numberDiff line change
@@ -1627,24 +1627,26 @@ impl Evaluator<'_> {
16271627
.ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory read".to_string()))
16281628
}
16291629

1630-
fn write_memory(&mut self, addr: Address, r: &[u8]) -> Result<()> {
1631-
if r.is_empty() {
1632-
return Ok(());
1633-
}
1630+
fn write_memory_using_ref(&mut self, addr: Address, size: usize) -> Result<&mut [u8]> {
16341631
let (mem, pos) = match addr {
16351632
Stack(it) => (&mut self.stack, it),
16361633
Heap(it) => (&mut self.heap, it),
16371634
Invalid(it) => {
16381635
return Err(MirEvalError::UndefinedBehavior(format!(
1639-
"write invalid memory address {it} with content {r:?}"
1636+
"write invalid memory address {it} with size {size}"
16401637
)));
16411638
}
16421639
};
1643-
mem.get_mut(pos..pos + r.len())
1644-
.ok_or_else(|| {
1645-
MirEvalError::UndefinedBehavior("out of bound memory write".to_string())
1646-
})?
1647-
.copy_from_slice(r);
1640+
Ok(mem.get_mut(pos..pos + size).ok_or_else(|| {
1641+
MirEvalError::UndefinedBehavior("out of bound memory write".to_string())
1642+
})?)
1643+
}
1644+
1645+
fn write_memory(&mut self, addr: Address, r: &[u8]) -> Result<()> {
1646+
if r.is_empty() {
1647+
return Ok(());
1648+
}
1649+
self.write_memory_using_ref(addr, r.len())?.copy_from_slice(r);
16481650
Ok(())
16491651
}
16501652

crates/hir-ty/src/mir/eval/shim.rs

+30-2
Original file line numberDiff line numberDiff line change
@@ -800,15 +800,25 @@ impl Evaluator<'_> {
800800
}
801801
"ctpop" => {
802802
let [arg] = args else {
803-
return Err(MirEvalError::TypeError("likely arg is not provided"));
803+
return Err(MirEvalError::TypeError("ctpop arg is not provided"));
804804
};
805805
let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).count_ones();
806806
destination
807807
.write_from_bytes(self, &(result as u128).to_le_bytes()[0..destination.size])
808808
}
809+
"ctlz" | "ctlz_nonzero" => {
810+
let [arg] = args else {
811+
return Err(MirEvalError::TypeError("cttz arg is not provided"));
812+
};
813+
let result =
814+
u128::from_le_bytes(pad16(arg.get(self)?, false)).leading_zeros() as usize;
815+
let result = result - (128 - arg.interval.size * 8);
816+
destination
817+
.write_from_bytes(self, &(result as u128).to_le_bytes()[0..destination.size])
818+
}
809819
"cttz" | "cttz_nonzero" => {
810820
let [arg] = args else {
811-
return Err(MirEvalError::TypeError("likely arg is not provided"));
821+
return Err(MirEvalError::TypeError("cttz arg is not provided"));
812822
};
813823
let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).trailing_zeros();
814824
destination
@@ -932,6 +942,24 @@ impl Evaluator<'_> {
932942
let addr = Address::from_bytes(arg.interval.get(self)?)?;
933943
destination.write_from_interval(self, Interval { addr, size: destination.size })
934944
}
945+
"write_bytes" => {
946+
let [dst, val, count] = args else {
947+
return Err(MirEvalError::TypeError("write_bytes args are not provided"));
948+
};
949+
let count = from_bytes!(usize, count.get(self)?);
950+
let val = from_bytes!(u8, val.get(self)?);
951+
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
952+
else {
953+
return Err(MirEvalError::TypeError(
954+
"write_bytes generic arg is not provided",
955+
));
956+
};
957+
let dst = Address::from_bytes(dst.get(self)?)?;
958+
let size = self.size_of_sized(ty, locals, "copy_nonoverlapping ptr type")?;
959+
let size = count * size;
960+
self.write_memory_using_ref(dst, size)?.fill(val);
961+
Ok(())
962+
}
935963
_ => not_supported!("unknown intrinsic {name}"),
936964
}
937965
}

crates/hir-ty/src/mir/eval/shim/simd.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ impl Evaluator<'_> {
4444
}
4545
};
4646
match try_const_usize(self.db, len) {
47-
Some(_) => not_supported!("array like simd type"),
47+
Some(len) => {
48+
let Some(ty) = subst.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
49+
return Err(MirEvalError::TypeError("simd type with no ty param"));
50+
};
51+
Ok((len as usize, ty.clone()))
52+
}
4853
None => Err(MirEvalError::TypeError("simd type with unevaluatable len param")),
4954
}
5055
}

crates/hir-ty/src/mir/lower.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1880,6 +1880,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
18801880

18811881
fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result<CastKind> {
18821882
Ok(match (source_ty.kind(Interner), target_ty.kind(Interner)) {
1883+
(TyKind::FnDef(..), TyKind::Function(_)) => CastKind::Pointer(PointerCast::ReifyFnPointer),
18831884
(TyKind::Scalar(s), TyKind::Scalar(t)) => match (s, t) {
18841885
(chalk_ir::Scalar::Float(_), chalk_ir::Scalar::Float(_)) => CastKind::FloatToFloat,
18851886
(chalk_ir::Scalar::Float(_), _) => CastKind::FloatToInt,

0 commit comments

Comments
 (0)