Commit 482a0f648c

Andrew Kelley <andrew@ziglang.org>
2023-04-24 00:10:18
Sema: implement comptime `@memcpy`
1 parent 83a7303
Changed files (2)
src
test
behavior
src/Sema.zig
@@ -21828,6 +21828,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
     const src_ptr = try sema.resolveInst(extra.rhs);
     const dest_len = try indexablePtrLenOrNone(sema, block, dest_src, dest_ptr);
     const src_len = try indexablePtrLenOrNone(sema, block, src_src, src_ptr);
+    const target = sema.mod.getTarget();
 
     if (dest_len == .none and src_len == .none) {
         const msg = msg: {
@@ -21879,9 +21880,41 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
 
     const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: {
         if (!dest_ptr_val.isComptimeMutablePtr()) break :rs dest_src;
-        if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |src_ptr_val| {
-            _ = src_ptr_val;
-            return sema.fail(block, src, "TODO: @memcpy at comptime", .{});
+        if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| {
+            const len_u64 = (try len_val.?.getUnsignedIntAdvanced(target, sema)).?;
+            const len = try sema.usizeCast(block, dest_src, len_u64);
+            for (0..len) |i| {
+                const elem_index = try sema.addIntUnsigned(Type.usize, i);
+                const dest_elem_ptr = try sema.elemPtr(
+                    block,
+                    src,
+                    dest_ptr,
+                    elem_index,
+                    src,
+                    true, // init
+                    false, // oob_safety
+                );
+                const src_elem_ptr = try sema.elemPtr(
+                    block,
+                    src,
+                    src_ptr,
+                    elem_index,
+                    src,
+                    false, // init
+                    false, // oob_safety
+                );
+                const uncoerced_elem = try sema.analyzeLoad(block, src, src_elem_ptr, src_src);
+                try sema.storePtr2(
+                    block,
+                    src,
+                    dest_elem_ptr,
+                    dest_src,
+                    uncoerced_elem,
+                    src_src,
+                    .store,
+                );
+            }
+            return;
         } else break :rs src_src;
     } else dest_src;
 
@@ -21902,7 +21935,6 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
 
     const dest_elem_ty = dest_ty.elemType2();
     const src_elem_ty = src_ty.elemType2();
-    const target = sema.mod.getTarget();
     if (.ok != try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, true, target, dest_src, src_src)) {
         return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the element types have different ABI sizes", .{});
     }
test/behavior/basic.zig
@@ -387,8 +387,7 @@ test "memcpy and memset intrinsics" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
 
     try testMemcpyMemset();
-    // TODO add comptime test coverage
-    //comptime try testMemcpyMemset();
+    try comptime testMemcpyMemset();
 }
 
 fn testMemcpyMemset() !void {