Auto merge of #15268 - HKalbasi:mir, r=HKalbasi

Add write_bytes and ctlz intrinsics
This commit is contained in:
bors 2023-07-12 23:19:30 +00:00
commit d16d5fcf68
6 changed files with 93 additions and 13 deletions

View File

@ -1725,6 +1725,18 @@ fn function_pointer() {
"#,
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(
r#"
//- minicore: coerce_unsized, index, slice

View File

@ -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]
fn copy() {
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]
fn cttz() {
check_number(

View File

@ -1627,24 +1627,26 @@ impl Evaluator<'_> {
.ok_or_else(|| MirEvalError::UndefinedBehavior("out of bound memory read".to_string()))
}
fn write_memory(&mut self, addr: Address, r: &[u8]) -> Result<()> {
if r.is_empty() {
return Ok(());
}
fn write_memory_using_ref(&mut self, addr: Address, size: usize) -> Result<&mut [u8]> {
let (mem, pos) = match addr {
Stack(it) => (&mut self.stack, it),
Heap(it) => (&mut self.heap, it),
Invalid(it) => {
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_or_else(|| {
MirEvalError::UndefinedBehavior("out of bound memory write".to_string())
})?
.copy_from_slice(r);
Ok(mem.get_mut(pos..pos + size).ok_or_else(|| {
MirEvalError::UndefinedBehavior("out of bound memory write".to_string())
})?)
}
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(())
}

View File

@ -800,15 +800,25 @@ impl Evaluator<'_> {
}
"ctpop" => {
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();
destination
.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" => {
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();
destination
@ -932,6 +942,24 @@ impl Evaluator<'_> {
let addr = Address::from_bytes(arg.interval.get(self)?)?;
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}"),
}
}

View File

@ -44,7 +44,12 @@ impl Evaluator<'_> {
}
};
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")),
}
}

View File

@ -1880,6 +1880,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
fn cast_kind(source_ty: &Ty, target_ty: &Ty) -> Result<CastKind> {
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) {
(chalk_ir::Scalar::Float(_), chalk_ir::Scalar::Float(_)) => CastKind::FloatToFloat,
(chalk_ir::Scalar::Float(_), _) => CastKind::FloatToInt,