about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/hir-ty/src/consteval/tests.rs12
-rw-r--r--crates/hir-ty/src/consteval/tests/intrinsics.rs32
-rw-r--r--crates/hir-ty/src/mir/eval.rs22
-rw-r--r--crates/hir-ty/src/mir/eval/shim.rs32
-rw-r--r--crates/hir-ty/src/mir/eval/shim/simd.rs7
-rw-r--r--crates/hir-ty/src/mir/lower.rs1
6 files changed, 93 insertions, 13 deletions
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 8e21272e14a..4ca1d8a2394 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -1726,6 +1726,18 @@ fn function_pointer() {
     );
     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
     fn add2(x: u8) -> u8 {
         x + 2
diff --git a/crates/hir-ty/src/consteval/tests/intrinsics.rs b/crates/hir-ty/src/consteval/tests/intrinsics.rs
index cb8f1b55575..30e87661abc 100644
--- a/crates/hir-ty/src/consteval/tests/intrinsics.rs
+++ b/crates/hir-ty/src/consteval/tests/intrinsics.rs
@@ -511,6 +511,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(
         r#"
@@ -546,6 +564,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(
         r#"
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index a1bab097951..47c93547683 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -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(())
     }
 
diff --git a/crates/hir-ty/src/mir/eval/shim.rs b/crates/hir-ty/src/mir/eval/shim.rs
index 3b8b7201223..cedc4538037 100644
--- a/crates/hir-ty/src/mir/eval/shim.rs
+++ b/crates/hir-ty/src/mir/eval/shim.rs
@@ -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}"),
         }
     }
diff --git a/crates/hir-ty/src/mir/eval/shim/simd.rs b/crates/hir-ty/src/mir/eval/shim/simd.rs
index bc9529d38f4..ec746310487 100644
--- a/crates/hir-ty/src/mir/eval/shim/simd.rs
+++ b/crates/hir-ty/src/mir/eval/shim/simd.rs
@@ -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")),
                 }
             }
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index d8fa8cf01a9..36108587904 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -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,