From 83a7303bbf92fcada2e61f2906f84ccf53e50ff0 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Sun, 23 Apr 2023 14:52:12 -0700 Subject: [PATCH] Sema: implement comptime `@memset` --- src/Sema.zig | 37 ++++++++++++++++--- test/behavior/basic.zig | 18 +-------- .../incorrect_type_to_memset_memcpy.zig | 4 +- .../@tagName on corrupted enum value.zig | 2 +- .../@tagName on corrupted union value.zig | 2 +- .../safety/switch on corrupted enum value.zig | 2 +- 6 files changed, 38 insertions(+), 27 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 5e16b9f3e5..9b54d649a0 100644 --- a/src/Sema.zig +++ b/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, diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 19ef38717a..ea2bf7847f 100644 --- a/test/behavior/basic.zig +++ b/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); } } diff --git a/test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig b/test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig index d3a6b7cc4b..37d0b8d323 100644 --- a/test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig +++ b/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 diff --git a/test/cases/safety/@tagName on corrupted enum value.zig b/test/cases/safety/@tagName on corrupted enum value.zig index 344b75effe..43af9fbda6 100644 --- a/test/cases/safety/@tagName on corrupted enum value.zig +++ b/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; diff --git a/test/cases/safety/@tagName on corrupted union value.zig b/test/cases/safety/@tagName on corrupted union value.zig index f7ffb07871..a72755abdc 100644 --- a/test/cases/safety/@tagName on corrupted union value.zig +++ b/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; diff --git a/test/cases/safety/switch on corrupted enum value.zig b/test/cases/safety/switch on corrupted enum value.zig index 2240fe0c8e..687be0b598 100644 --- a/test/cases/safety/switch on corrupted enum value.zig +++ b/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(), }