mirror of
https://github.com/rust-lang/rust-analyzer.git
synced 2025-09-28 04:44:57 +00:00
Add write_bytes and ctlz intrinsics
This commit is contained in:
parent
59420afa46
commit
274e8301c1
6 changed files with 93 additions and 13 deletions
|
@ -1724,6 +1724,18 @@ fn function_pointer() {
|
||||||
"#,
|
"#,
|
||||||
5,
|
5,
|
||||||
);
|
);
|
||||||
|
check_number(
|
||||||
|
r#"
|
||||||
|
fn add2(x: u8) -> u8 {
|
||||||
|
x + 2
|
||||||
|
}
|
||||||
|
const GOAL: u8 = {
|
||||||
|
let plus2 = add2 as fn(u8) -> u8;
|
||||||
|
plus2(3)
|
||||||
|
};
|
||||||
|
"#,
|
||||||
|
5,
|
||||||
|
);
|
||||||
check_number(
|
check_number(
|
||||||
r#"
|
r#"
|
||||||
//- minicore: coerce_unsized, index, slice
|
//- minicore: coerce_unsized, index, slice
|
||||||
|
|
|
@ -510,6 +510,24 @@ fn copy_nonoverlapping() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn write_bytes() {
|
||||||
|
check_number(
|
||||||
|
r#"
|
||||||
|
extern "rust-intrinsic" {
|
||||||
|
fn write_bytes<T>(dst: *mut T, val: u8, count: usize);
|
||||||
|
}
|
||||||
|
|
||||||
|
const GOAL: i32 = unsafe {
|
||||||
|
let mut x = 2;
|
||||||
|
write_bytes(&mut x, 5, 1);
|
||||||
|
x
|
||||||
|
};
|
||||||
|
"#,
|
||||||
|
0x05050505,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn copy() {
|
fn copy() {
|
||||||
check_number(
|
check_number(
|
||||||
|
@ -545,6 +563,20 @@ fn ctpop() {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn ctlz() {
|
||||||
|
check_number(
|
||||||
|
r#"
|
||||||
|
extern "rust-intrinsic" {
|
||||||
|
pub fn ctlz<T: Copy>(x: T) -> T;
|
||||||
|
}
|
||||||
|
|
||||||
|
const GOAL: u8 = ctlz(0b0001_1100_u8);
|
||||||
|
"#,
|
||||||
|
3,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn cttz() {
|
fn cttz() {
|
||||||
check_number(
|
check_number(
|
||||||
|
|
|
@ -1627,24 +1627,26 @@ impl Evaluator<'_> {
|
||||||
.ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory read".to_string()))
|
.ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory read".to_string()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_memory(&mut self, addr: Address, r: &[u8]) -> Result<()> {
|
fn write_memory_using_ref(&mut self, addr: Address, size: usize) -> Result<&mut [u8]> {
|
||||||
if r.is_empty() {
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
let (mem, pos) = match addr {
|
let (mem, pos) = match addr {
|
||||||
Stack(it) => (&mut self.stack, it),
|
Stack(it) => (&mut self.stack, it),
|
||||||
Heap(it) => (&mut self.heap, it),
|
Heap(it) => (&mut self.heap, it),
|
||||||
Invalid(it) => {
|
Invalid(it) => {
|
||||||
return Err(MirEvalError::UndefinedBehavior(format!(
|
return Err(MirEvalError::UndefinedBehavior(format!(
|
||||||
"write invalid memory address {it} with content {r:?}"
|
"write invalid memory address {it} with size {size}"
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
mem.get_mut(pos..pos + r.len())
|
Ok(mem.get_mut(pos..pos + size).ok_or_else(|| {
|
||||||
.ok_or_else(|| {
|
MirEvalError::UndefinedBehavior("out of bound memory write".to_string())
|
||||||
MirEvalError::UndefinedBehavior("out of bound memory write".to_string())
|
})?)
|
||||||
})?
|
}
|
||||||
.copy_from_slice(r);
|
|
||||||
|
fn write_memory(&mut self, addr: Address, r: &[u8]) -> Result<()> {
|
||||||
|
if r.is_empty() {
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
self.write_memory_using_ref(addr, r.len())?.copy_from_slice(r);
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -800,15 +800,25 @@ impl Evaluator<'_> {
|
||||||
}
|
}
|
||||||
"ctpop" => {
|
"ctpop" => {
|
||||||
let [arg] = args else {
|
let [arg] = args else {
|
||||||
return Err(MirEvalError::TypeError("likely arg is not provided"));
|
return Err(MirEvalError::TypeError("ctpop arg is not provided"));
|
||||||
};
|
};
|
||||||
let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).count_ones();
|
let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).count_ones();
|
||||||
destination
|
destination
|
||||||
.write_from_bytes(self, &(result as u128).to_le_bytes()[0..destination.size])
|
.write_from_bytes(self, &(result as u128).to_le_bytes()[0..destination.size])
|
||||||
}
|
}
|
||||||
|
"ctlz" | "ctlz_nonzero" => {
|
||||||
|
let [arg] = args else {
|
||||||
|
return Err(MirEvalError::TypeError("cttz arg is not provided"));
|
||||||
|
};
|
||||||
|
let result =
|
||||||
|
u128::from_le_bytes(pad16(arg.get(self)?, false)).leading_zeros() as usize;
|
||||||
|
let result = result - (128 - arg.interval.size * 8);
|
||||||
|
destination
|
||||||
|
.write_from_bytes(self, &(result as u128).to_le_bytes()[0..destination.size])
|
||||||
|
}
|
||||||
"cttz" | "cttz_nonzero" => {
|
"cttz" | "cttz_nonzero" => {
|
||||||
let [arg] = args else {
|
let [arg] = args else {
|
||||||
return Err(MirEvalError::TypeError("likely arg is not provided"));
|
return Err(MirEvalError::TypeError("cttz arg is not provided"));
|
||||||
};
|
};
|
||||||
let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).trailing_zeros();
|
let result = u128::from_le_bytes(pad16(arg.get(self)?, false)).trailing_zeros();
|
||||||
destination
|
destination
|
||||||
|
@ -932,6 +942,24 @@ impl Evaluator<'_> {
|
||||||
let addr = Address::from_bytes(arg.interval.get(self)?)?;
|
let addr = Address::from_bytes(arg.interval.get(self)?)?;
|
||||||
destination.write_from_interval(self, Interval { addr, size: destination.size })
|
destination.write_from_interval(self, Interval { addr, size: destination.size })
|
||||||
}
|
}
|
||||||
|
"write_bytes" => {
|
||||||
|
let [dst, val, count] = args else {
|
||||||
|
return Err(MirEvalError::TypeError("write_bytes args are not provided"));
|
||||||
|
};
|
||||||
|
let count = from_bytes!(usize, count.get(self)?);
|
||||||
|
let val = from_bytes!(u8, val.get(self)?);
|
||||||
|
let Some(ty) = generic_args.as_slice(Interner).get(0).and_then(|it| it.ty(Interner))
|
||||||
|
else {
|
||||||
|
return Err(MirEvalError::TypeError(
|
||||||
|
"write_bytes generic arg is not provided",
|
||||||
|
));
|
||||||
|
};
|
||||||
|
let dst = Address::from_bytes(dst.get(self)?)?;
|
||||||
|
let size = self.size_of_sized(ty, locals, "copy_nonoverlapping ptr type")?;
|
||||||
|
let size = count * size;
|
||||||
|
self.write_memory_using_ref(dst, size)?.fill(val);
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
_ => not_supported!("unknown intrinsic {name}"),
|
_ => not_supported!("unknown intrinsic {name}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,12 @@ impl Evaluator<'_> {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
match try_const_usize(self.db, len) {
|
match try_const_usize(self.db, len) {
|
||||||
Some(_) => not_supported!("array like simd type"),
|
Some(len) => {
|
||||||
|
let Some(ty) = subst.as_slice(Interner).get(0).and_then(|it| it.ty(Interner)) else {
|
||||||
|
return Err(MirEvalError::TypeError("simd type with no ty param"));
|
||||||
|
};
|
||||||
|
Ok((len as usize, ty.clone()))
|
||||||
|
}
|
||||||
None => Err(MirEvalError::TypeError("simd type with unevaluatable len param")),
|
None => Err(MirEvalError::TypeError("simd type with unevaluatable len param")),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1880,6 +1880,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
|
||||||
|
|
||||||
fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result<CastKind> {
|
fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result<CastKind> {
|
||||||
Ok(match (source_ty.kind(Interner), target_ty.kind(Interner)) {
|
Ok(match (source_ty.kind(Interner), target_ty.kind(Interner)) {
|
||||||
|
(TyKind::FnDef(..), TyKind::Function(_)) => CastKind::Pointer(PointerCast::ReifyFnPointer),
|
||||||
(TyKind::Scalar(s), TyKind::Scalar(t)) => match (s, t) {
|
(TyKind::Scalar(s), TyKind::Scalar(t)) => match (s, t) {
|
||||||
(chalk_ir::Scalar::Float(_), chalk_ir::Scalar::Float(_)) => CastKind::FloatToFloat,
|
(chalk_ir::Scalar::Float(_), chalk_ir::Scalar::Float(_)) => CastKind::FloatToFloat,
|
||||||
(chalk_ir::Scalar::Float(_), _) => CastKind::FloatToInt,
|
(chalk_ir::Scalar::Float(_), _) => CastKind::FloatToInt,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue