Auto merge of #15268 - HKalbasi:mir, r=HKalbasi
Add write_bytes and ctlz intrinsics
This commit is contained in:
commit
d16d5fcf68
@ -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
|
||||
|
@ -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(
|
||||
|
@ -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(())
|
||||
}
|
||||
|
||||
|
@ -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}"),
|
||||
}
|
||||
}
|
||||
|
@ -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")),
|
||||
}
|
||||
}
|
||||
|
@ -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,
|
||||
|
Loading…
x
Reference in New Issue
Block a user