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...@@ -21959,17 +21959,44 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
21959 const dest_ptr_ty = sema.typeOf(dest_ptr);21959 const dest_ptr_ty = sema.typeOf(dest_ptr);
21960 try checkSliceOrArrayType(sema, block, dest_src, dest_ptr_ty);21960 try checkSliceOrArrayType(sema, block, dest_src, dest_ptr_ty);
2196121961
21962 const elem_ty = dest_ptr_ty.elemType2();21962 const dest_elem_ty = dest_ptr_ty.elemType2();
21963 const elem = try sema.coerce(block, elem_ty, uncoerced_elem, value_src);21963 const target = sema.mod.getTarget();
2196421964
21965 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: {21965 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: {
21966 if (!ptr_val.isComptimeMutablePtr()) break :rs dest_src;21966 if (!ptr_val.isComptimeMutablePtr()) break :rs dest_src;
21967 if (try sema.resolveMaybeUndefVal(elem)) |elem_val| {21967 if (try sema.resolveMaybeUndefVal(uncoerced_elem)) |_| {
21968 _ = elem_val;21968 const len_air_ref = try sema.fieldVal(block, src, dest_ptr, "len", dest_src);
21969 return sema.fail(block, src, "TODO: @memset at comptime", .{});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;
21970 } else break :rs value_src;21995 } else break :rs value_src;
21971 } else dest_src;21996 } else dest_src;
2197221997
21998 const elem = try sema.coerce(block, dest_elem_ty, uncoerced_elem, value_src);
21999
21973 try sema.requireRuntimeBlock(block, src, runtime_src);22000 try sema.requireRuntimeBlock(block, src, runtime_src);
21974 _ = try block.addInst(.{22001 _ = try block.addInst(.{
21975 .tag = if (block.wantSafety()) .memset_safe else .memset,22002 .tag = if (block.wantSafety()) .memset_safe else .memset,
test/behavior/basic.zig+1-17
...@@ -359,8 +359,7 @@ test "@memset on array pointers" {...@@ -359,8 +359,7 @@ test "@memset on array pointers" {
359 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;359 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
360360
361 try testMemsetArray();361 try testMemsetArray();
362 // TODO this doesn't pass yet362 try comptime testMemsetArray();
363 // try comptime testMemsetArray();
364}363}
365364
366fn testMemsetArray() !void {365fn testMemsetArray() !void {
...@@ -371,15 +370,7 @@ fn testMemsetArray() !void {...@@ -371,15 +370,7 @@ fn testMemsetArray() !void {
371 try expect(foo[0] == 'A');370 try expect(foo[0] == 'A');
372 try expect(foo[11] == 'A');371 try expect(foo[11] == 'A');
373 try expect(foo[19] == 'A');372 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);
381 }373 }
382
383 {374 {
384 // memset array to non-undefined, ABI size > 1375 // memset array to non-undefined, ABI size > 1
385 var foo: [20]u32 = undefined;376 var foo: [20]u32 = undefined;
...@@ -387,13 +378,6 @@ fn testMemsetArray() !void {...@@ -387,13 +378,6 @@ fn testMemsetArray() !void {
387 try expect(foo[0] == 1234);378 try expect(foo[0] == 1234);
388 try expect(foo[11] == 1234);379 try expect(foo[11] == 1234);
389 try expect(foo[19] == 1234);380 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);
397 }381 }
398}382}
399383
test/cases/compile_errors/incorrect_type_to_memset_memcpy.zig+2-2
...@@ -2,12 +2,12 @@ pub export fn entry() void {...@@ -2,12 +2,12 @@ pub export fn entry() void {
2 var buf: [5]u8 = .{ 1, 2, 3, 4, 5 };2 var buf: [5]u8 = .{ 1, 2, 3, 4, 5 };
3 var slice: []u8 = &buf;3 var slice: []u8 = &buf;
4 const a: u32 = 1234;4 const a: u32 = 1234;
5 @memcpy(slice, @ptrCast([*]const u8, &a), 4);5 @memcpy(slice, @ptrCast([*]const u8, &a));
6}6}
7pub export fn entry1() void {7pub export fn entry1() void {
8 var buf: [5]u8 = .{ 1, 2, 3, 4, 5 };8 var buf: [5]u8 = .{ 1, 2, 3, 4, 5 };
9 var ptr: *u8 = &buf[0];9 var ptr: *u8 = &buf[0];
10 @memcpy(ptr, 0, 4);10 @memcpy(ptr, 0);
11}11}
1212
13// error13// error
test/cases/safety/@tagName on corrupted enum value.zig +1-1
...@@ -15,7 +15,7 @@ const E = enum(u32) {...@@ -15,7 +15,7 @@ const E = enum(u32) {
1515
16pub fn main() !void {16pub fn main() !void {
17 var e: E = undefined;17 var e: E = undefined;
18 @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));18 @memset(@ptrCast([*]u8, &e)[0..@sizeOf(E)], 0x55);
19 var n = @tagName(e);19 var n = @tagName(e);
20 _ = n;20 _ = n;
21 return error.TestFailed;21 return error.TestFailed;
test/cases/safety/@tagName on corrupted union value.zig +1-1
...@@ -15,7 +15,7 @@ const U = union(enum(u32)) {...@@ -15,7 +15,7 @@ const U = union(enum(u32)) {
1515
16pub fn main() !void {16pub fn main() !void {
17 var u: U = undefined;17 var u: U = undefined;
18 @memset(@ptrCast([*]u8, &u), 0x55, @sizeOf(U));18 @memset(@ptrCast([*]u8, &u)[0..@sizeOf(U)], 0x55);
19 var t: @typeInfo(U).Union.tag_type.? = u;19 var t: @typeInfo(U).Union.tag_type.? = u;
20 var n = @tagName(t);20 var n = @tagName(t);
21 _ = n;21 _ = n;
test/cases/safety/switch on corrupted enum value.zig +1-1
...@@ -15,7 +15,7 @@ const E = enum(u32) {...@@ -15,7 +15,7 @@ const E = enum(u32) {
1515
16pub fn main() !void {16pub fn main() !void {
17 var e: E = undefined;17 var e: E = undefined;
18 @memset(@ptrCast([*]u8, &e), 0x55, @sizeOf(E));18 @memset(@ptrCast([*]u8, &e)[0..@sizeOf(E)], 0x55);
19 switch (e) {19 switch (e) {
20 .X, .Y => @breakpoint(),20 .X, .Y => @breakpoint(),
21 }21 }