authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-23 14:52:12-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-25 11:23:41-07:00
log83a7303bbf92fcada2e61f2906f84ccf53e50ff0
treee3930f9b1a3ee2c4f835055ab221197696ecb5c3
parent0f65cc9275cde61fe20f28e4f059c8af4c63b051

Sema: implement comptime `@memset`


6 files changed, 38 insertions(+), 27 deletions(-)

src/Sema.zig+32-5
......@@ -21959,17 +21959,44 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2195921959 const dest_ptr_ty = sema.typeOf(dest_ptr);
2196021960 try checkSliceOrArrayType(sema, block, dest_src, dest_ptr_ty);
2196121961
21962 const elem_ty = dest_ptr_ty.elemType2();
21963 const elem = try sema.coerce(block, elem_ty, uncoerced_elem, value_src);
21962 const dest_elem_ty = dest_ptr_ty.elemType2();
21963 const target = sema.mod.getTarget();
2196421964
2196521965 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: {
2196621966 if (!ptr_val.isComptimeMutablePtr()) break :rs dest_src;
21967 if (try sema.resolveMaybeUndefVal(elem)) |elem_val| {
21968 _ = elem_val;
21969 return sema.fail(block, src, "TODO: @memset at comptime", .{});
21967 if (try sema.resolveMaybeUndefVal(uncoerced_elem)) |_| {
21968 const len_air_ref = try sema.fieldVal(block, src, dest_ptr, "len", dest_src);
21969 const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse
21970 break :rs dest_src;
21971 const len_u64 = (try len_val.getUnsignedIntAdvanced(target, sema)).?;
21972 const len = try sema.usizeCast(block, dest_src, len_u64);
21973 for (0..len) |i| {
21974 const elem_index = try sema.addIntUnsigned(Type.usize, i);
21975 const elem_ptr = try sema.elemPtr(
21976 block,
21977 src,
21978 dest_ptr,
21979 elem_index,
21980 src,
21981 true, // init
21982 false, // oob_safety
21983 );
21984 try sema.storePtr2(
21985 block,
21986 src,
21987 elem_ptr,
21988 dest_src,
21989 uncoerced_elem,
21990 value_src,
21991 .store,
21992 );
21993 }
21994 return;
2197021995 } else break :rs value_src;
2197121996 } else dest_src;
2197221997
21998 const elem = try sema.coerce(block, dest_elem_ty, uncoerced_elem, value_src);
21999
2197322000 try sema.requireRuntimeBlock(block, src, runtime_src);
2197422001 _ = try block.addInst(.{
2197522002 .tag = if (block.wantSafety()) .memset_safe else .memset,
test/behavior/basic.zig+1-17
......@@ -359,8 +359,7 @@ test "@memset on array pointers" {
359359 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
360360
361361 try testMemsetArray();
362 // TODO this doesn't pass yet
363 // try comptime testMemsetArray();
362 try comptime testMemsetArray();
364363}
365364
366365fn testMemsetArray() !void {
......@@ -371,15 +370,7 @@ fn testMemsetArray() !void {
371370 try expect(foo[0] == 'A');
372371 try expect(foo[11] == 'A');
373372 try expect(foo[19] == 'A');
374
375 // memset array to undefined, ABI size == 1
376 @setRuntimeSafety(true);
377 @memset(&foo, undefined);
378 try expect(foo[0] == 0xaa);
379 try expect(foo[11] == 0xaa);
380 try expect(foo[19] == 0xaa);
381373 }
382
383374 {
384375 // memset array to non-undefined, ABI size > 1
385376 var foo: [20]u32 = undefined;
......@@ -387,13 +378,6 @@ fn testMemsetArray() !void {
387378 try expect(foo[0] == 1234);
388379 try expect(foo[11] == 1234);
389380 try expect(foo[19] == 1234);
390
391 // memset array to undefined, ABI size > 1
392 @setRuntimeSafety(true);
393 @memset(&foo, undefined);
394 try expect(foo[0] == 0xaaaaaaaa);
395 try expect(foo[11] == 0xaaaaaaaa);
396 try expect(foo[19] == 0xaaaaaaaa);
397381 }
398382}
399383
test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig+2-2
......@@ -2,12 +2,12 @@ pub export fn entry() void {
22 var buf: [5]u8 = .{ 1, 2, 3, 4, 5 };
33 var slice: []u8 = &buf;
44 const a: u32 = 1234;
5 @memcpy(slice, @ptrCast([*]const u8, &a), 4);
5 @memcpy(slice, @ptrCast([*]const u8, &a));
66}
77pub export fn entry1() void {
88 var buf: [5]u8 = .{ 1, 2, 3, 4, 5 };
99 var ptr: *u8 = &buf[0];
10 @memcpy(ptr, 0, 4);
10 @memcpy(ptr, 0);
1111}
1212
1313// error
test/cases/safety/@tagName on corrupted enum value.zig +1-1
......@@ -15,7 +15,7 @@ const E = enum(u32) {
1515
1616pub fn main() !void {
1717 var e: E = undefined;
18 @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
18 @memset(@ptrCast([*]u8, &e)[0..@sizeOf(E)], 0x55);
1919 var n = @tagName(e);
2020 _ = n;
2121 return error.TestFailed;
test/cases/safety/@tagName on corrupted union value.zig +1-1
......@@ -15,7 +15,7 @@ const U = union(enum(u32)) {
1515
1616pub fn main() !void {
1717 var u: U = undefined;
18 @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));
18 @memset(@ptrCast([*]u8, &u)[0..@sizeOf(U)], 0x55);
1919 var t: @typeInfo(U).Union.tag_type.? = u;
2020 var n = @tagName(t);
2121 _ = n;
test/cases/safety/switch on corrupted enum value.zig +1-1
......@@ -15,7 +15,7 @@ const E = enum(u32) {
1515
1616pub fn main() !void {
1717 var e: E = undefined;
18 @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));
18 @memset(@ptrCast([*]u8, &e)[0..@sizeOf(E)], 0x55);
1919 switch (e) {
2020 .X, .Y => @breakpoint(),
2121 }