Commit 83a7303bbf

Andrew Kelley <andrew@ziglang.org>
2023-04-23 23:52:12
Sema: implement comptime `@memset`
1 parent 0f65cc9
src/Sema.zig
@@ -21959,17 +21959,44 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
     const dest_ptr_ty = sema.typeOf(dest_ptr);
     try checkSliceOrArrayType(sema, block, dest_src, dest_ptr_ty);
 
-    const elem_ty = dest_ptr_ty.elemType2();
-    const elem = try sema.coerce(block, elem_ty, uncoerced_elem, value_src);
+    const dest_elem_ty = dest_ptr_ty.elemType2();
+    const target = sema.mod.getTarget();
 
     const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: {
         if (!ptr_val.isComptimeMutablePtr()) break :rs dest_src;
-        if (try sema.resolveMaybeUndefVal(elem)) |elem_val| {
-            _ = elem_val;
-            return sema.fail(block, src, "TODO: @memset at comptime", .{});
+        if (try sema.resolveMaybeUndefVal(uncoerced_elem)) |_| {
+            const len_air_ref = try sema.fieldVal(block, src, dest_ptr, "len", dest_src);
+            const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse
+                break :rs dest_src;
+            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 elem_ptr = try sema.elemPtr(
+                    block,
+                    src,
+                    dest_ptr,
+                    elem_index,
+                    src,
+                    true, // init
+                    false, // oob_safety
+                );
+                try sema.storePtr2(
+                    block,
+                    src,
+                    elem_ptr,
+                    dest_src,
+                    uncoerced_elem,
+                    value_src,
+                    .store,
+                );
+            }
+            return;
         } else break :rs value_src;
     } else dest_src;
 
+    const elem = try sema.coerce(block, dest_elem_ty, uncoerced_elem, value_src);
+
     try sema.requireRuntimeBlock(block, src, runtime_src);
     _ = try block.addInst(.{
         .tag = if (block.wantSafety()) .memset_safe else .memset,
test/behavior/basic.zig
@@ -359,8 +359,7 @@ test "@memset on array pointers" {
     if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
 
     try testMemsetArray();
-    // TODO this doesn't pass yet
-    // try comptime testMemsetArray();
+    try comptime testMemsetArray();
 }
 
 fn testMemsetArray() !void {
@@ -371,15 +370,7 @@ fn testMemsetArray() !void {
         try expect(foo[0] == 'A');
         try expect(foo[11] == 'A');
         try expect(foo[19] == 'A');
-
-        // memset array to undefined, ABI size == 1
-        @setRuntimeSafety(true);
-        @memset(&foo, undefined);
-        try expect(foo[0] == 0xaa);
-        try expect(foo[11] == 0xaa);
-        try expect(foo[19] == 0xaa);
     }
-
     {
         // memset array to non-undefined, ABI size > 1
         var foo: [20]u32 = undefined;
@@ -387,13 +378,6 @@ fn testMemsetArray() !void {
         try expect(foo[0] == 1234);
         try expect(foo[11] == 1234);
         try expect(foo[19] == 1234);
-
-        // memset array to undefined, ABI size > 1
-        @setRuntimeSafety(true);
-        @memset(&foo, undefined);
-        try expect(foo[0] == 0xaaaaaaaa);
-        try expect(foo[11] == 0xaaaaaaaa);
-        try expect(foo[19] == 0xaaaaaaaa);
     }
 }
 
test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig
@@ -2,12 +2,12 @@ pub export fn entry() void {
     var buf: [5]u8 = .{ 1, 2, 3, 4, 5 };
     var slice: []u8 = &buf;
     const a: u32 = 1234;
-    @memcpy(slice, @ptrCast([*]const u8, &a), 4);
+    @memcpy(slice, @ptrCast([*]const u8, &a));
 }
 pub export fn entry1() void {
     var buf: [5]u8 = .{ 1, 2, 3, 4, 5 };
     var ptr: *u8 = &buf[0];
-    @memcpy(ptr, 0, 4);
+    @memcpy(ptr, 0);
 }
 
 // error
test/cases/safety/@tagName on corrupted enum value.zig
@@ -15,7 +15,7 @@ const E = enum(u32) {
 
 pub fn main() !void {
     var e: E = undefined;
-    @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
+    @memset(@ptrCast([*]u8, &e)[0..@sizeOf(E)], 0x55);
     var n = @tagName(e);
     _ = n;
     return error.TestFailed;
test/cases/safety/@tagName on corrupted union value.zig
@@ -15,7 +15,7 @@ const U = union(enum(u32)) {
 
 pub fn main() !void {
     var u: U = undefined;
-    @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
+    @memset(@ptrCast([*]u8, &u)[0..@sizeOf(U)], 0x55);
     var t: @typeInfo(U).Union.tag_type.? = u;
     var n = @tagName(t);
     _ = n;
test/cases/safety/switch on corrupted enum value.zig
@@ -15,7 +15,7 @@ const E = enum(u32) {
 
 pub fn main() !void {
     var e: E = undefined;
-    @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
+    @memset(@ptrCast([*]u8, &e)[0..@sizeOf(E)], 0x55);
     switch (e) {
         .X, .Y => @breakpoint(),
     }