authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-13 21:44:40-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-04-25 11:23:40-07:00
loga5c910adb610ae530db99f10aa77aaed3e85e830
tree5c3f72dbac50fc9f09608be3d7ea328c629c00a0
parent8d88dcdc61c61e3410138f4402482131f5074a80

change semantics of `@memcpy` and `@memset`

Now they use slices or array pointers with any element type instead of requiring byte pointers. This is a breaking enhancement to the language. The safety check for overlapping pointers will be implemented in a future commit. closes #14040

33 files changed, 221 insertions(+), 280 deletions(-)

doc/langref.html.in+19-31
...@@ -8681,40 +8681,28 @@ test "integer cast panic" {...@@ -8681,40 +8681,28 @@ test "integer cast panic" {
8681 {#header_close#}8681 {#header_close#}
86828682
8683 {#header_open|@memcpy#}8683 {#header_open|@memcpy#}
8684 <pre>{#syntax#}@memcpy(noalias dest: [*]u8, noalias source: [*]const u8, byte_count: usize) void{#endsyntax#}</pre>8684 <pre>{#syntax#}@memcpy(noalias dest, noalias source) void{#endsyntax#}</pre>
8685 <p>8685 <p>This function copies bytes from one region of memory to another.</p>
8686 This function copies bytes from one region of memory to another. {#syntax#}dest{#endsyntax#} and8686 <p>{#syntax#}dest{#endsyntax#} must be a mutable slice, or a mutable pointer to an array.
8687 {#syntax#}source{#endsyntax#} are both pointers and must not overlap.8687 It may have any alignment, and it may have any element type.</p>
8688 </p>8688 <p>{#syntax#}source{#endsyntax#} must be an array, pointer, or a slice
8689 <p>8689 with the same element type as {#syntax#}dest{#endsyntax#}. It may have
8690 This function is a low level intrinsic with no safety mechanisms. Most code8690 any alignment. Only {#syntax#}const{#endsyntax#} access is required. It
8691 should not use this function, instead using something like this:8691 is sliced from 0 to the same length as
8692 </p>8692 {#syntax#}dest{#endsyntax#}, triggering the same set of safety checks and
8693 <pre>{#syntax#}for (dest, source[0..byte_count]) |*d, s| d.* = s;{#endsyntax#}</pre>8693 possible compile errors as
8694 <p>8694 {#syntax#}source[0..dest.len]{#endsyntax#}.</p>
8695 The optimizer is intelligent enough to turn the above snippet into a memcpy.8695 <p>It is illegal for {#syntax#}dest{#endsyntax#} and
8696 </p>8696 {#syntax#}source[0..dest.len]{#endsyntax#} to overlap. If safety
8697 <p>There is also a standard library function for this:</p>8697 checks are enabled, there will be a runtime check for such overlapping.</p>
8698 <pre>{#syntax#}const mem = @import("std").mem;
8699mem.copy(u8, dest[0..byte_count], source[0..byte_count]);{#endsyntax#}</pre>
8700 {#header_close#}8698 {#header_close#}
87018699
8702 {#header_open|@memset#}8700 {#header_open|@memset#}
8703 <pre>{#syntax#}@memset(dest: [*]u8, c: u8, byte_count: usize) void{#endsyntax#}</pre>8701 <pre>{#syntax#}@memset(dest, elem) void{#endsyntax#}</pre>
8704 <p>8702 <p>This function sets all the elements of a memory region to {#syntax#}elem{#endsyntax#}.</p>
8705 This function sets a region of memory to {#syntax#}c{#endsyntax#}. {#syntax#}dest{#endsyntax#} is a pointer.8703 <p>{#syntax#}dest{#endsyntax#} must be a mutable slice or a mutable pointer to an array.
8706 </p>8704 It may have any alignment, and it may have any element type.</p>
8707 <p>8705 <p>{#syntax#}elem{#endsyntax#} is coerced to the element type of {#syntax#}dest{#endsyntax#}.</p>
8708 This function is a low level intrinsic with no safety mechanisms. Most
8709 code should not use this function, instead using something like this:
8710 </p>
8711 <pre>{#syntax#}for (dest[0..byte_count]) |*b| b.* = c;{#endsyntax#}</pre>
8712 <p>
8713 The optimizer is intelligent enough to turn the above snippet into a memset.
8714 </p>
8715 <p>There is also a standard library function for this:</p>
8716 <pre>{#syntax#}const mem = @import("std").mem;
8717mem.set(u8, dest, c);{#endsyntax#}</pre>
8718 {#header_close#}8706 {#header_close#}
87198707
8720 {#header_open|@min#}8708 {#header_open|@min#}
lib/compiler_rt/atomics.zig+6-6
...@@ -121,22 +121,22 @@ fn __atomic_load(size: u32, src: [*]u8, dest: [*]u8, model: i32) callconv(.C) vo...@@ -121,22 +121,22 @@ fn __atomic_load(size: u32, src: [*]u8, dest: [*]u8, model: i32) callconv(.C) vo
121 _ = model;121 _ = model;
122 var sl = spinlocks.get(@ptrToInt(src));122 var sl = spinlocks.get(@ptrToInt(src));
123 defer sl.release();123 defer sl.release();
124 @memcpy(dest, src, size);124 @memcpy(dest[0..size], src);
125}125}
126126
127fn __atomic_store(size: u32, dest: [*]u8, src: [*]u8, model: i32) callconv(.C) void {127fn __atomic_store(size: u32, dest: [*]u8, src: [*]u8, model: i32) callconv(.C) void {
128 _ = model;128 _ = model;
129 var sl = spinlocks.get(@ptrToInt(dest));129 var sl = spinlocks.get(@ptrToInt(dest));
130 defer sl.release();130 defer sl.release();
131 @memcpy(dest, src, size);131 @memcpy(dest[0..size], src);
132}132}
133133
134fn __atomic_exchange(size: u32, ptr: [*]u8, val: [*]u8, old: [*]u8, model: i32) callconv(.C) void {134fn __atomic_exchange(size: u32, ptr: [*]u8, val: [*]u8, old: [*]u8, model: i32) callconv(.C) void {
135 _ = model;135 _ = model;
136 var sl = spinlocks.get(@ptrToInt(ptr));136 var sl = spinlocks.get(@ptrToInt(ptr));
137 defer sl.release();137 defer sl.release();
138 @memcpy(old, ptr, size);138 @memcpy(old[0..size], ptr);
139 @memcpy(ptr, val, size);139 @memcpy(ptr[0..size], val);
140}140}
141141
142fn __atomic_compare_exchange(142fn __atomic_compare_exchange(
...@@ -155,10 +155,10 @@ fn __atomic_compare_exchange(...@@ -155,10 +155,10 @@ fn __atomic_compare_exchange(
155 if (expected[i] != b) break;155 if (expected[i] != b) break;
156 } else {156 } else {
157 // The two objects, ptr and expected, are equal157 // The two objects, ptr and expected, are equal
158 @memcpy(ptr, desired, size);158 @memcpy(ptr[0..size], desired);
159 return 1;159 return 1;
160 }160 }
161 @memcpy(expected, ptr, size);161 @memcpy(expected[0..size], ptr);
162 return 0;162 return 0;
163}163}
164164
lib/compiler_rt/emutls.zig+2-2
...@@ -139,10 +139,10 @@ const ObjectArray = struct {...@@ -139,10 +139,10 @@ const ObjectArray = struct {
139139
140 if (control.default_value) |value| {140 if (control.default_value) |value| {
141 // default value: copy the content to newly allocated object.141 // default value: copy the content to newly allocated object.
142 @memcpy(data, @ptrCast([*]const u8, value), size);142 @memcpy(data[0..size], @ptrCast([*]const u8, value));
143 } else {143 } else {
144 // no default: return zeroed memory.144 // no default: return zeroed memory.
145 @memset(data, 0, size);145 @memset(data[0..size], 0);
146 }146 }
147147
148 self.slots[index] = @ptrCast(*anyopaque, data);148 self.slots[index] = @ptrCast(*anyopaque, data);
lib/std/array_hash_map.zig+2-2
...@@ -1893,7 +1893,7 @@ const IndexHeader = struct {...@@ -1893,7 +1893,7 @@ const IndexHeader = struct {
1893 const index_size = hash_map.capacityIndexSize(new_bit_index);1893 const index_size = hash_map.capacityIndexSize(new_bit_index);
1894 const nbytes = @sizeOf(IndexHeader) + index_size * len;1894 const nbytes = @sizeOf(IndexHeader) + index_size * len;
1895 const bytes = try allocator.alignedAlloc(u8, @alignOf(IndexHeader), nbytes);1895 const bytes = try allocator.alignedAlloc(u8, @alignOf(IndexHeader), nbytes);
1896 @memset(bytes.ptr + @sizeOf(IndexHeader), 0xff, bytes.len - @sizeOf(IndexHeader));1896 @memset(bytes[@sizeOf(IndexHeader)..], 0xff);
1897 const result = @ptrCast(*IndexHeader, bytes.ptr);1897 const result = @ptrCast(*IndexHeader, bytes.ptr);
1898 result.* = .{1898 result.* = .{
1899 .bit_index = new_bit_index,1899 .bit_index = new_bit_index,
...@@ -1914,7 +1914,7 @@ const IndexHeader = struct {...@@ -1914,7 +1914,7 @@ const IndexHeader = struct {
1914 const index_size = hash_map.capacityIndexSize(header.bit_index);1914 const index_size = hash_map.capacityIndexSize(header.bit_index);
1915 const ptr = @ptrCast([*]align(@alignOf(IndexHeader)) u8, header);1915 const ptr = @ptrCast([*]align(@alignOf(IndexHeader)) u8, header);
1916 const nbytes = @sizeOf(IndexHeader) + header.length() * index_size;1916 const nbytes = @sizeOf(IndexHeader) + header.length() * index_size;
1917 @memset(ptr + @sizeOf(IndexHeader), 0xff, nbytes - @sizeOf(IndexHeader));1917 @memset(ptr[@sizeOf(IndexHeader)..nbytes], 0xff);
1918 }1918 }
19191919
1920 // Verify that the header has sufficient alignment to produce aligned arrays.1920 // Verify that the header has sufficient alignment to produce aligned arrays.
lib/std/array_list.zig+4-12
...@@ -121,7 +121,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -121,7 +121,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
121121
122 const new_memory = try allocator.alignedAlloc(T, alignment, self.items.len);122 const new_memory = try allocator.alignedAlloc(T, alignment, self.items.len);
123 mem.copy(T, new_memory, self.items);123 mem.copy(T, new_memory, self.items);
124 @memset(@ptrCast([*]u8, self.items.ptr), undefined, self.items.len * @sizeOf(T));124 @memset(self.items, undefined);
125 self.clearAndFree();125 self.clearAndFree();
126 return new_memory;126 return new_memory;
127 }127 }
...@@ -281,11 +281,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {...@@ -281,11 +281,7 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
281 const new_len = old_len + items.len;281 const new_len = old_len + items.len;
282 assert(new_len <= self.capacity);282 assert(new_len <= self.capacity);
283 self.items.len = new_len;283 self.items.len = new_len;
284 @memcpy(284 @memcpy(self.items[old_len..][0..items.len], items);
285 @ptrCast([*]align(@alignOf(T)) u8, self.items.ptr + old_len),
286 @ptrCast([*]const u8, items.ptr),
287 items.len * @sizeOf(T),
288 );
289 }285 }
290286
291 pub const Writer = if (T != u8)287 pub const Writer = if (T != u8)
...@@ -601,7 +597,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -601,7 +597,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
601597
602 const new_memory = try allocator.alignedAlloc(T, alignment, self.items.len);598 const new_memory = try allocator.alignedAlloc(T, alignment, self.items.len);
603 mem.copy(T, new_memory, self.items);599 mem.copy(T, new_memory, self.items);
604 @memset(@ptrCast([*]u8, self.items.ptr), undefined, self.items.len * @sizeOf(T));600 @memset(self.items, undefined);
605 self.clearAndFree(allocator);601 self.clearAndFree(allocator);
606 return new_memory;602 return new_memory;
607 }603 }
...@@ -740,11 +736,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ...@@ -740,11 +736,7 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
740 const new_len = old_len + items.len;736 const new_len = old_len + items.len;
741 assert(new_len <= self.capacity);737 assert(new_len <= self.capacity);
742 self.items.len = new_len;738 self.items.len = new_len;
743 @memcpy(739 @memcpy(self.items[old_len..][0..items.len], items);
744 @ptrCast([*]align(@alignOf(T)) u8, self.items.ptr + old_len),
745 @ptrCast([*]const u8, items.ptr),
746 items.len * @sizeOf(T),
747 );
748 }740 }
749741
750 pub const WriterContext = struct {742 pub const WriterContext = struct {
lib/std/c/darwin.zig+1-1
...@@ -3670,7 +3670,7 @@ pub const MachTask = extern struct {...@@ -3670,7 +3670,7 @@ pub const MachTask = extern struct {
3670 else => |err| return unexpectedKernError(err),3670 else => |err| return unexpectedKernError(err),
3671 }3671 }
36723672
3673 @memcpy(out_buf[0..].ptr, @intToPtr([*]const u8, vm_memory), curr_bytes_read);3673 @memcpy(out_buf[0..curr_bytes_read], @intToPtr([*]const u8, vm_memory));
3674 _ = vm_deallocate(mach_task_self(), vm_memory, curr_bytes_read);3674 _ = vm_deallocate(mach_task_self(), vm_memory, curr_bytes_read);
36753675
3676 out_buf = out_buf[curr_bytes_read..];3676 out_buf = out_buf[curr_bytes_read..];
lib/std/crypto/aes_gcm.zig+1-1
...@@ -91,7 +91,7 @@ fn AesGcm(comptime Aes: anytype) type {...@@ -91,7 +91,7 @@ fn AesGcm(comptime Aes: anytype) type {
91 acc |= (computed_tag[p] ^ tag[p]);91 acc |= (computed_tag[p] ^ tag[p]);
92 }92 }
93 if (acc != 0) {93 if (acc != 0) {
94 @memset(m.ptr, undefined, m.len);94 @memset(m, undefined);
95 return error.AuthenticationFailed;95 return error.AuthenticationFailed;
96 }96 }
9797
lib/std/crypto/tls/Client.zig+1-1
...@@ -531,7 +531,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In...@@ -531,7 +531,7 @@ pub fn init(stream: anytype, ca_bundle: Certificate.Bundle, host: []const u8) In
531 const pub_key = subject.pubKey();531 const pub_key = subject.pubKey();
532 if (pub_key.len > main_cert_pub_key_buf.len)532 if (pub_key.len > main_cert_pub_key_buf.len)
533 return error.CertificatePublicKeyInvalid;533 return error.CertificatePublicKeyInvalid;
534 @memcpy(&main_cert_pub_key_buf, pub_key.ptr, pub_key.len);534 @memcpy(main_cert_pub_key_buf[0..pub_key.len], pub_key);
535 main_cert_pub_key_len = @intCast(@TypeOf(main_cert_pub_key_len), pub_key.len);535 main_cert_pub_key_len = @intCast(@TypeOf(main_cert_pub_key_len), pub_key.len);
536 } else {536 } else {
537 try prev_cert.verify(subject, now_sec);537 try prev_cert.verify(subject, now_sec);
lib/std/crypto/utils.zig+3-3
...@@ -135,11 +135,11 @@ pub fn timingSafeSub(comptime T: type, a: []const T, b: []const T, result: []T,...@@ -135,11 +135,11 @@ pub fn timingSafeSub(comptime T: type, a: []const T, b: []const T, result: []T,
135/// Sets a slice to zeroes.135/// Sets a slice to zeroes.
136/// Prevents the store from being optimized out.136/// Prevents the store from being optimized out.
137pub fn secureZero(comptime T: type, s: []T) void {137pub fn secureZero(comptime T: type, s: []T) void {
138 // NOTE: We do not use a volatile slice cast here since LLVM cannot138 // TODO: implement `@memset` for non-byte-sized element type in the llvm backend
139 // see that it can be replaced by a memset.139 //@memset(@as([]volatile T, s), 0);
140 const ptr = @ptrCast([*]volatile u8, s.ptr);140 const ptr = @ptrCast([*]volatile u8, s.ptr);
141 const length = s.len * @sizeOf(T);141 const length = s.len * @sizeOf(T);
142 @memset(ptr, 0, length);142 @memset(ptr[0..length], 0);
143}143}
144144
145test "crypto.utils.timingSafeEql" {145test "crypto.utils.timingSafeEql" {
lib/std/fifo.zig+4-4
...@@ -104,7 +104,7 @@ pub fn LinearFifo(...@@ -104,7 +104,7 @@ pub fn LinearFifo(
104 }104 }
105 { // set unused area to undefined105 { // set unused area to undefined
106 const unused = mem.sliceAsBytes(self.buf[self.count..]);106 const unused = mem.sliceAsBytes(self.buf[self.count..]);
107 @memset(unused.ptr, undefined, unused.len);107 @memset(unused, undefined);
108 }108 }
109 }109 }
110110
...@@ -182,12 +182,12 @@ pub fn LinearFifo(...@@ -182,12 +182,12 @@ pub fn LinearFifo(
182 const slice = self.readableSliceMut(0);182 const slice = self.readableSliceMut(0);
183 if (slice.len >= count) {183 if (slice.len >= count) {
184 const unused = mem.sliceAsBytes(slice[0..count]);184 const unused = mem.sliceAsBytes(slice[0..count]);
185 @memset(unused.ptr, undefined, unused.len);185 @memset(unused, undefined);
186 } else {186 } else {
187 const unused = mem.sliceAsBytes(slice[0..]);187 const unused = mem.sliceAsBytes(slice[0..]);
188 @memset(unused.ptr, undefined, unused.len);188 @memset(unused, undefined);
189 const unused2 = mem.sliceAsBytes(self.readableSliceMut(slice.len)[0 .. count - slice.len]);189 const unused2 = mem.sliceAsBytes(self.readableSliceMut(slice.len)[0 .. count - slice.len]);
190 @memset(unused2.ptr, undefined, unused2.len);190 @memset(unused2, undefined);
191 }191 }
192 }192 }
193 if (autoalign and self.count == count) {193 if (autoalign and self.count == count) {
lib/std/hash/murmur.zig+4-9
...@@ -115,7 +115,7 @@ pub const Murmur2_64 = struct {...@@ -115,7 +115,7 @@ pub const Murmur2_64 = struct {
115 const offset = len - rest;115 const offset = len - rest;
116 if (rest > 0) {116 if (rest > 0) {
117 var k1: u64 = 0;117 var k1: u64 = 0;
118 @memcpy(@ptrCast([*]u8, &k1), @ptrCast([*]const u8, &str[@intCast(usize, offset)]), @intCast(usize, rest));118 @memcpy(@ptrCast([*]u8, &k1)[0..@intCast(usize, rest)], @ptrCast([*]const u8, &str[@intCast(usize, offset)]));
119 if (native_endian == .Big)119 if (native_endian == .Big)
120 k1 = @byteSwap(k1);120 k1 = @byteSwap(k1);
121 h1 ^= k1;121 h1 ^= k1;
...@@ -282,13 +282,8 @@ pub const Murmur3_32 = struct {...@@ -282,13 +282,8 @@ pub const Murmur3_32 = struct {
282282
283fn SMHasherTest(comptime hash_fn: anytype, comptime hashbits: u32) u32 {283fn SMHasherTest(comptime hash_fn: anytype, comptime hashbits: u32) u32 {
284 const hashbytes = hashbits / 8;284 const hashbytes = hashbits / 8;
285 var key: [256]u8 = undefined;285 var key: [256]u8 = [1]u8{0} ** 256;
286 var hashes: [hashbytes * 256]u8 = undefined;286 var hashes: [hashbytes * 256]u8 = [1]u8{0} ** (hashbytes * 256);
287 var final: [hashbytes]u8 = undefined;
288
289 @memset(@ptrCast([*]u8, &key[0]), 0, @sizeOf(@TypeOf(key)));
290 @memset(@ptrCast([*]u8, &hashes[0]), 0, @sizeOf(@TypeOf(hashes)));
291 @memset(@ptrCast([*]u8, &final[0]), 0, @sizeOf(@TypeOf(final)));
292287
293 var i: u32 = 0;288 var i: u32 = 0;
294 while (i < 256) : (i += 1) {289 while (i < 256) : (i += 1) {
...@@ -297,7 +292,7 @@ fn SMHasherTest(comptime hash_fn: anytype, comptime hashbits: u32) u32 {...@@ -297,7 +292,7 @@ fn SMHasherTest(comptime hash_fn: anytype, comptime hashbits: u32) u32 {
297 var h = hash_fn(key[0..i], 256 - i);292 var h = hash_fn(key[0..i], 256 - i);
298 if (native_endian == .Big)293 if (native_endian == .Big)
299 h = @byteSwap(h);294 h = @byteSwap(h);
300 @memcpy(@ptrCast([*]u8, &hashes[i * hashbytes]), @ptrCast([*]u8, &h), hashbytes);295 @memcpy(hashes[i * hashbytes..][0..hashbytes], @ptrCast([*]u8, &h));
301 }296 }
302297
303 return @truncate(u32, hash_fn(&hashes, 0));298 return @truncate(u32, hash_fn(&hashes, 0));
lib/std/hash_map.zig+1-1
...@@ -1449,7 +1449,7 @@ pub fn HashMapUnmanaged(...@@ -1449,7 +1449,7 @@ pub fn HashMapUnmanaged(
1449 }1449 }
14501450
1451 fn initMetadatas(self: *Self) void {1451 fn initMetadatas(self: *Self) void {
1452 @memset(@ptrCast([*]u8, self.metadata.?), 0, @sizeOf(Metadata) * self.capacity());1452 @memset(@ptrCast([*]u8, self.metadata.?)[0..@sizeOf(Metadata) * self.capacity()], 0);
1453 }1453 }
14541454
1455 // This counts the number of occupied slots (not counting tombstones), which is1455 // This counts the number of occupied slots (not counting tombstones), which is
lib/std/heap/general_purpose_allocator.zig+4-3
...@@ -759,7 +759,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -759,7 +759,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
759 const new_size_class = math.ceilPowerOfTwoAssert(usize, new_aligned_size);759 const new_size_class = math.ceilPowerOfTwoAssert(usize, new_aligned_size);
760 if (new_size_class <= size_class) {760 if (new_size_class <= size_class) {
761 if (old_mem.len > new_size) {761 if (old_mem.len > new_size) {
762 @memset(old_mem.ptr + new_size, undefined, old_mem.len - new_size);762 @memset(old_mem[new_size..], undefined);
763 }763 }
764 if (config.verbose_log) {764 if (config.verbose_log) {
765 log.info("small resize {d} bytes at {*} to {d}", .{765 log.info("small resize {d} bytes at {*} to {d}", .{
...@@ -911,7 +911,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -911,7 +911,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
911 self.empty_buckets = bucket;911 self.empty_buckets = bucket;
912 }912 }
913 } else {913 } else {
914 @memset(old_mem.ptr, undefined, old_mem.len);914 @memset(old_mem, undefined);
915 }915 }
916 if (config.safety) {916 if (config.safety) {
917 assert(self.small_allocations.remove(@ptrToInt(old_mem.ptr)));917 assert(self.small_allocations.remove(@ptrToInt(old_mem.ptr)));
...@@ -1011,7 +1011,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {...@@ -1011,7 +1011,7 @@ pub fn GeneralPurposeAllocator(comptime config: Config) type {
1011 };1011 };
1012 self.buckets[bucket_index] = ptr;1012 self.buckets[bucket_index] = ptr;
1013 // Set the used bits to all zeroes1013 // Set the used bits to all zeroes
1014 @memset(@as(*[1]u8, ptr.usedBits(0)), 0, usedBitsCount(size_class));1014 @memset(@as([*]u8, @as(*[1]u8, ptr.usedBits(0)))[0..usedBitsCount(size_class)], 0);
1015 return ptr;1015 return ptr;
1016 }1016 }
1017 };1017 };
...@@ -1412,3 +1412,4 @@ test "bug 9995 fix, large allocs count requested size not backing size" {...@@ -1412,3 +1412,4 @@ test "bug 9995 fix, large allocs count requested size not backing size" {
1412 buf = try allocator.realloc(buf, 2);1412 buf = try allocator.realloc(buf, 2);
1413 try std.testing.expect(gpa.total_requested_bytes == 2);1413 try std.testing.expect(gpa.total_requested_bytes == 2);
1414}1414}
1415
lib/std/math/big/int_test.zig+4-4
...@@ -2756,7 +2756,7 @@ test "big int conversion read twos complement with padding" {...@@ -2756,7 +2756,7 @@ test "big int conversion read twos complement with padding" {
27562756
2757 var buffer1 = try testing.allocator.alloc(u8, 16);2757 var buffer1 = try testing.allocator.alloc(u8, 16);
2758 defer testing.allocator.free(buffer1);2758 defer testing.allocator.free(buffer1);
2759 @memset(buffer1.ptr, 0xaa, buffer1.len);2759 @memset(buffer1, 0xaa);
27602760
2761 // writeTwosComplement:2761 // writeTwosComplement:
2762 // (1) should not write beyond buffer[0..abi_size]2762 // (1) should not write beyond buffer[0..abi_size]
...@@ -2773,7 +2773,7 @@ test "big int conversion read twos complement with padding" {...@@ -2773,7 +2773,7 @@ test "big int conversion read twos complement with padding" {
2773 a.toConst().writeTwosComplement(buffer1[0..16], .Big);2773 a.toConst().writeTwosComplement(buffer1[0..16], .Big);
2774 try testing.expect(std.mem.eql(u8, buffer1, &[_]u8{ 0x0, 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd }));2774 try testing.expect(std.mem.eql(u8, buffer1, &[_]u8{ 0x0, 0x0, 0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd }));
27752775
2776 @memset(buffer1.ptr, 0xaa, buffer1.len);2776 @memset(buffer1, 0xaa);
2777 try a.set(-0x01_02030405_06070809_0a0b0c0d);2777 try a.set(-0x01_02030405_06070809_0a0b0c0d);
2778 bit_count = 12 * 8 + 2;2778 bit_count = 12 * 8 + 2;
27792779
...@@ -2794,7 +2794,7 @@ test "big int write twos complement +/- zero" {...@@ -2794,7 +2794,7 @@ test "big int write twos complement +/- zero" {
27942794
2795 var buffer1 = try testing.allocator.alloc(u8, 16);2795 var buffer1 = try testing.allocator.alloc(u8, 16);
2796 defer testing.allocator.free(buffer1);2796 defer testing.allocator.free(buffer1);
2797 @memset(buffer1.ptr, 0xaa, buffer1.len);2797 @memset(buffer1, 0xaa);
27982798
2799 // Test zero2799 // Test zero
28002800
...@@ -2807,7 +2807,7 @@ test "big int write twos complement +/- zero" {...@@ -2807,7 +2807,7 @@ test "big int write twos complement +/- zero" {
2807 m.toConst().writeTwosComplement(buffer1[0..16], .Big);2807 m.toConst().writeTwosComplement(buffer1[0..16], .Big);
2808 try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 16))));2808 try testing.expect(std.mem.eql(u8, buffer1, &(([_]u8{0} ** 16))));
28092809
2810 @memset(buffer1.ptr, 0xaa, buffer1.len);2810 @memset(buffer1, 0xaa);
2811 m.positive = false;2811 m.positive = false;
28122812
2813 // Test negative zero2813 // Test negative zero
lib/std/mem/Allocator.zig+4-4
...@@ -215,7 +215,7 @@ pub fn allocAdvancedWithRetAddr(...@@ -215,7 +215,7 @@ pub fn allocAdvancedWithRetAddr(
215 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;215 const byte_count = math.mul(usize, @sizeOf(T), n) catch return Error.OutOfMemory;
216 const byte_ptr = self.rawAlloc(byte_count, log2a(a), return_address) orelse return Error.OutOfMemory;216 const byte_ptr = self.rawAlloc(byte_count, log2a(a), return_address) orelse return Error.OutOfMemory;
217 // TODO: https://github.com/ziglang/zig/issues/4298217 // TODO: https://github.com/ziglang/zig/issues/4298
218 @memset(byte_ptr, undefined, byte_count);218 @memset(byte_ptr[0..byte_count], undefined);
219 const byte_slice = byte_ptr[0..byte_count];219 const byte_slice = byte_ptr[0..byte_count];
220 return mem.bytesAsSlice(T, @alignCast(a, byte_slice));220 return mem.bytesAsSlice(T, @alignCast(a, byte_slice));
221}221}
...@@ -282,9 +282,9 @@ pub fn reallocAdvanced(...@@ -282,9 +282,9 @@ pub fn reallocAdvanced(
282282
283 const new_mem = self.rawAlloc(byte_count, log2a(Slice.alignment), return_address) orelse283 const new_mem = self.rawAlloc(byte_count, log2a(Slice.alignment), return_address) orelse
284 return error.OutOfMemory;284 return error.OutOfMemory;
285 @memcpy(new_mem, old_byte_slice.ptr, @min(byte_count, old_byte_slice.len));285 @memcpy(new_mem[0..@min(byte_count, old_byte_slice.len)], old_byte_slice);
286 // TODO https://github.com/ziglang/zig/issues/4298286 // TODO https://github.com/ziglang/zig/issues/4298
287 @memset(old_byte_slice.ptr, undefined, old_byte_slice.len);287 @memset(old_byte_slice, undefined);
288 self.rawFree(old_byte_slice, log2a(Slice.alignment), return_address);288 self.rawFree(old_byte_slice, log2a(Slice.alignment), return_address);
289289
290 return mem.bytesAsSlice(T, @alignCast(Slice.alignment, new_mem[0..byte_count]));290 return mem.bytesAsSlice(T, @alignCast(Slice.alignment, new_mem[0..byte_count]));
...@@ -299,7 +299,7 @@ pub fn free(self: Allocator, memory: anytype) void {...@@ -299,7 +299,7 @@ pub fn free(self: Allocator, memory: anytype) void {
299 if (bytes_len == 0) return;299 if (bytes_len == 0) return;
300 const non_const_ptr = @constCast(bytes.ptr);300 const non_const_ptr = @constCast(bytes.ptr);
301 // TODO: https://github.com/ziglang/zig/issues/4298301 // TODO: https://github.com/ziglang/zig/issues/4298
302 @memset(non_const_ptr, undefined, bytes_len);302 @memset(non_const_ptr[0..bytes_len], undefined);
303 self.rawFree(non_const_ptr[0..bytes_len], log2a(Slice.alignment), @returnAddress());303 self.rawFree(non_const_ptr[0..bytes_len], log2a(Slice.alignment), @returnAddress());
304}304}
305305
lib/std/multi_array_list.zig+1-2
...@@ -360,11 +360,10 @@ pub fn MultiArrayList(comptime T: type) type {...@@ -360,11 +360,10 @@ pub fn MultiArrayList(comptime T: type) type {
360 if (@sizeOf(field_info.type) != 0) {360 if (@sizeOf(field_info.type) != 0) {
361 const field = @intToEnum(Field, i);361 const field = @intToEnum(Field, i);
362 const dest_slice = self_slice.items(field)[new_len..];362 const dest_slice = self_slice.items(field)[new_len..];
363 const byte_count = dest_slice.len * @sizeOf(field_info.type);
364 // We use memset here for more efficient codegen in safety-checked,363 // We use memset here for more efficient codegen in safety-checked,
365 // valgrind-enabled builds. Otherwise the valgrind client request364 // valgrind-enabled builds. Otherwise the valgrind client request
366 // will be repeated for every element.365 // will be repeated for every element.
367 @memset(@ptrCast([*]u8, dest_slice.ptr), undefined, byte_count);366 @memset(dest_slice, undefined);
368 }367 }
369 }368 }
370 self.len = new_len;369 self.len = new_len;
lib/std/net.zig+3-3
...@@ -1020,7 +1020,7 @@ fn linuxLookupName(...@@ -1020,7 +1020,7 @@ fn linuxLookupName(
1020 for (addrs.items, 0..) |*addr, i| {1020 for (addrs.items, 0..) |*addr, i| {
1021 var key: i32 = 0;1021 var key: i32 = 0;
1022 var sa6: os.sockaddr.in6 = undefined;1022 var sa6: os.sockaddr.in6 = undefined;
1023 @memset(@ptrCast([*]u8, &sa6), 0, @sizeOf(os.sockaddr.in6));1023 @memset(@ptrCast([*]u8, &sa6)[0..@sizeOf(os.sockaddr.in6)], 0);
1024 var da6 = os.sockaddr.in6{1024 var da6 = os.sockaddr.in6{
1025 .family = os.AF.INET6,1025 .family = os.AF.INET6,
1026 .scope_id = addr.addr.in6.sa.scope_id,1026 .scope_id = addr.addr.in6.sa.scope_id,
...@@ -1029,7 +1029,7 @@ fn linuxLookupName(...@@ -1029,7 +1029,7 @@ fn linuxLookupName(
1029 .addr = [1]u8{0} ** 16,1029 .addr = [1]u8{0} ** 16,
1030 };1030 };
1031 var sa4: os.sockaddr.in = undefined;1031 var sa4: os.sockaddr.in = undefined;
1032 @memset(@ptrCast([*]u8, &sa4), 0, @sizeOf(os.sockaddr.in));1032 @memset(@ptrCast([*]u8, &sa4)[0..@sizeOf(os.sockaddr.in)], 0);
1033 var da4 = os.sockaddr.in{1033 var da4 = os.sockaddr.in{
1034 .family = os.AF.INET,1034 .family = os.AF.INET,
1035 .port = 65535,1035 .port = 65535,
...@@ -1577,7 +1577,7 @@ fn resMSendRc(...@@ -1577,7 +1577,7 @@ fn resMSendRc(
15771577
1578 // Get local address and open/bind a socket1578 // Get local address and open/bind a socket
1579 var sa: Address = undefined;1579 var sa: Address = undefined;
1580 @memset(@ptrCast([*]u8, &sa), 0, @sizeOf(Address));1580 @memset(@ptrCast([*]u8, &sa)[0..@sizeOf(Address)], 0);
1581 sa.any.family = family;1581 sa.any.family = family;
1582 try os.bind(fd, &sa.any, sl);1582 try os.bind(fd, &sa.any, sl);
15831583
lib/std/os.zig+4-4
...@@ -5217,7 +5217,7 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {...@@ -5217,7 +5217,7 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
5217 .macos, .ios, .watchos, .tvos => {5217 .macos, .ios, .watchos, .tvos => {
5218 // On macOS, we can use F.GETPATH fcntl command to query the OS for5218 // On macOS, we can use F.GETPATH fcntl command to query the OS for
5219 // the path to the file descriptor.5219 // the path to the file descriptor.
5220 @memset(out_buffer, 0, MAX_PATH_BYTES);5220 @memset(out_buffer[0..MAX_PATH_BYTES], 0);
5221 switch (errno(system.fcntl(fd, F.GETPATH, out_buffer))) {5221 switch (errno(system.fcntl(fd, F.GETPATH, out_buffer))) {
5222 .SUCCESS => {},5222 .SUCCESS => {},
5223 .BADF => return error.FileNotFound,5223 .BADF => return error.FileNotFound,
...@@ -5308,7 +5308,7 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {...@@ -5308,7 +5308,7 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
5308 if (comptime builtin.os.version_range.semver.max.order(.{ .major = 6, .minor = 0 }) == .lt) {5308 if (comptime builtin.os.version_range.semver.max.order(.{ .major = 6, .minor = 0 }) == .lt) {
5309 @compileError("querying for canonical path of a handle is unsupported on this host");5309 @compileError("querying for canonical path of a handle is unsupported on this host");
5310 }5310 }
5311 @memset(out_buffer, 0, MAX_PATH_BYTES);5311 @memset(out_buffer[0..MAX_PATH_BYTES], 0);
5312 switch (errno(system.fcntl(fd, F.GETPATH, out_buffer))) {5312 switch (errno(system.fcntl(fd, F.GETPATH, out_buffer))) {
5313 .SUCCESS => {},5313 .SUCCESS => {},
5314 .BADF => return error.FileNotFound,5314 .BADF => return error.FileNotFound,
...@@ -5322,7 +5322,7 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {...@@ -5322,7 +5322,7 @@ pub fn getFdPath(fd: fd_t, out_buffer: *[MAX_PATH_BYTES]u8) RealPathError![]u8 {
5322 if (comptime builtin.os.version_range.semver.max.order(.{ .major = 10, .minor = 0 }) == .lt) {5322 if (comptime builtin.os.version_range.semver.max.order(.{ .major = 10, .minor = 0 }) == .lt) {
5323 @compileError("querying for canonical path of a handle is unsupported on this host");5323 @compileError("querying for canonical path of a handle is unsupported on this host");
5324 }5324 }
5325 @memset(out_buffer, 0, MAX_PATH_BYTES);5325 @memset(out_buffer[0..MAX_PATH_BYTES], 0);
5326 switch (errno(system.fcntl(fd, F.GETPATH, out_buffer))) {5326 switch (errno(system.fcntl(fd, F.GETPATH, out_buffer))) {
5327 .SUCCESS => {},5327 .SUCCESS => {},
5328 .ACCES => return error.AccessDenied,5328 .ACCES => return error.AccessDenied,
...@@ -5720,7 +5720,7 @@ pub fn res_mkquery(...@@ -5720,7 +5720,7 @@ pub fn res_mkquery(
57205720
5721 // Construct query template - ID will be filled later5721 // Construct query template - ID will be filled later
5722 var q: [280]u8 = undefined;5722 var q: [280]u8 = undefined;
5723 @memset(&q, 0, n);5723 @memset(q[0..n], 0);
5724 q[2] = @as(u8, op) * 8 + 1;5724 q[2] = @as(u8, op) * 8 + 1;
5725 q[5] = 1;5725 q[5] = 1;
5726 mem.copy(u8, q[13..], name);5726 mem.copy(u8, q[13..], name);
lib/std/os/linux.zig+3-3
...@@ -1184,7 +1184,7 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact...@@ -1184,7 +1184,7 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact
1184 .mask = undefined,1184 .mask = undefined,
1185 .restorer = @ptrCast(k_sigaction_funcs.restorer, restorer_fn),1185 .restorer = @ptrCast(k_sigaction_funcs.restorer, restorer_fn),
1186 };1186 };
1187 @memcpy(@ptrCast([*]u8, &ksa.mask), @ptrCast([*]const u8, &new.mask), mask_size);1187 @memcpy(@ptrCast([*]u8, &ksa.mask)[0..mask_size], @ptrCast([*]const u8, &new.mask));
1188 }1188 }
11891189
1190 const ksa_arg = if (act != null) @ptrToInt(&ksa) else 0;1190 const ksa_arg = if (act != null) @ptrToInt(&ksa) else 0;
...@@ -1200,7 +1200,7 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact...@@ -1200,7 +1200,7 @@ pub fn sigaction(sig: u6, noalias act: ?*const Sigaction, noalias oact: ?*Sigact
1200 if (oact) |old| {1200 if (oact) |old| {
1201 old.handler.handler = oldksa.handler;1201 old.handler.handler = oldksa.handler;
1202 old.flags = @truncate(c_uint, oldksa.flags);1202 old.flags = @truncate(c_uint, oldksa.flags);
1203 @memcpy(@ptrCast([*]u8, &old.mask), @ptrCast([*]const u8, &oldksa.mask), mask_size);1203 @memcpy(@ptrCast([*]u8, &old.mask)[0..mask_size], @ptrCast([*]const u8, &oldksa.mask));
1204 }1204 }
12051205
1206 return 0;1206 return 0;
...@@ -1515,7 +1515,7 @@ pub fn sched_yield() usize {...@@ -1515,7 +1515,7 @@ pub fn sched_yield() usize {
1515pub fn sched_getaffinity(pid: pid_t, size: usize, set: *cpu_set_t) usize {1515pub fn sched_getaffinity(pid: pid_t, size: usize, set: *cpu_set_t) usize {
1516 const rc = syscall3(.sched_getaffinity, @bitCast(usize, @as(isize, pid)), size, @ptrToInt(set));1516 const rc = syscall3(.sched_getaffinity, @bitCast(usize, @as(isize, pid)), size, @ptrToInt(set));
1517 if (@bitCast(isize, rc) < 0) return rc;1517 if (@bitCast(isize, rc) < 0) return rc;
1518 if (rc < size) @memset(@ptrCast([*]u8, set) + rc, 0, size - rc);1518 if (rc < size) @memset(@ptrCast([*]u8, set)[rc..size], 0);
1519 return 0;1519 return 0;
1520}1520}
15211521
lib/std/os/windows.zig+3-3
...@@ -755,9 +755,9 @@ pub fn CreateSymbolicLink(...@@ -755,9 +755,9 @@ pub fn CreateSymbolicLink(
755 };755 };
756756
757 std.mem.copy(u8, buffer[0..], std.mem.asBytes(&symlink_data));757 std.mem.copy(u8, buffer[0..], std.mem.asBytes(&symlink_data));
758 @memcpy(buffer[@sizeOf(SYMLINK_DATA)..], @ptrCast([*]const u8, target_path), target_path.len * 2);758 @memcpy(buffer[@sizeOf(SYMLINK_DATA)..][0..target_path.len * 2], @ptrCast([*]const u8, target_path));
759 const paths_start = @sizeOf(SYMLINK_DATA) + target_path.len * 2;759 const paths_start = @sizeOf(SYMLINK_DATA) + target_path.len * 2;
760 @memcpy(buffer[paths_start..].ptr, @ptrCast([*]const u8, target_path), target_path.len * 2);760 @memcpy(buffer[paths_start..][0..target_path.len * 2], @ptrCast([*]const u8, target_path));
761 _ = try DeviceIoControl(symlink_handle, FSCTL_SET_REPARSE_POINT, buffer[0..buf_len], null);761 _ = try DeviceIoControl(symlink_handle, FSCTL_SET_REPARSE_POINT, buffer[0..buf_len], null);
762}762}
763763
...@@ -1179,7 +1179,7 @@ pub fn GetFinalPathNameByHandle(...@@ -1179,7 +1179,7 @@ pub fn GetFinalPathNameByHandle(
1179 var input_struct = @ptrCast(*MOUNTMGR_MOUNT_POINT, &input_buf[0]);1179 var input_struct = @ptrCast(*MOUNTMGR_MOUNT_POINT, &input_buf[0]);
1180 input_struct.DeviceNameOffset = @sizeOf(MOUNTMGR_MOUNT_POINT);1180 input_struct.DeviceNameOffset = @sizeOf(MOUNTMGR_MOUNT_POINT);
1181 input_struct.DeviceNameLength = @intCast(USHORT, volume_name_u16.len * 2);1181 input_struct.DeviceNameLength = @intCast(USHORT, volume_name_u16.len * 2);
1182 @memcpy(input_buf[@sizeOf(MOUNTMGR_MOUNT_POINT)..], @ptrCast([*]const u8, volume_name_u16.ptr), volume_name_u16.len * 2);1182 @memcpy(input_buf[@sizeOf(MOUNTMGR_MOUNT_POINT)..][0..volume_name_u16.len * 2], @ptrCast([*]const u8, volume_name_u16.ptr));
11831183
1184 DeviceIoControl(mgmt_handle, IOCTL_MOUNTMGR_QUERY_POINTS, &input_buf, &output_buf) catch |err| switch (err) {1184 DeviceIoControl(mgmt_handle, IOCTL_MOUNTMGR_QUERY_POINTS, &input_buf, &output_buf) catch |err| switch (err) {
1185 error.AccessDenied => unreachable,1185 error.AccessDenied => unreachable,
lib/std/zig/c_builtins.zig+2-2
...@@ -152,7 +152,7 @@ pub inline fn __builtin___memset_chk(...@@ -152,7 +152,7 @@ pub inline fn __builtin___memset_chk(
152152
153pub inline fn __builtin_memset(dst: ?*anyopaque, val: c_int, len: usize) ?*anyopaque {153pub inline fn __builtin_memset(dst: ?*anyopaque, val: c_int, len: usize) ?*anyopaque {
154 const dst_cast = @ptrCast([*c]u8, dst);154 const dst_cast = @ptrCast([*c]u8, dst);
155 @memset(dst_cast, @bitCast(u8, @truncate(i8, val)), len);155 @memset(dst_cast[0..len], @bitCast(u8, @truncate(i8, val)));
156 return dst;156 return dst;
157}157}
158158
...@@ -174,7 +174,7 @@ pub inline fn __builtin_memcpy(...@@ -174,7 +174,7 @@ pub inline fn __builtin_memcpy(
174 const dst_cast = @ptrCast([*c]u8, dst);174 const dst_cast = @ptrCast([*c]u8, dst);
175 const src_cast = @ptrCast([*c]const u8, src);175 const src_cast = @ptrCast([*c]const u8, src);
176176
177 @memcpy(dst_cast, src_cast, len);177 @memcpy(dst_cast[0..len], src_cast);
178 return dst;178 return dst;
179}179}
180180
src/Air.zig+11-8
...@@ -632,17 +632,20 @@ pub const Inst = struct {...@@ -632,17 +632,20 @@ pub const Inst = struct {
632 /// Uses the `pl_op` field with `pred` as operand, and payload `Bin`.632 /// Uses the `pl_op` field with `pred` as operand, and payload `Bin`.
633 select,633 select,
634634
635 /// Given dest ptr, value, and len, set all elements at dest to value.635 /// Given dest pointer and value, set all elements at dest to value.
636 /// Dest pointer is either a slice or a pointer to array.
637 /// The element type may be any type, and the slice may have any alignment.
636 /// Result type is always void.638 /// Result type is always void.
637 /// Uses the `pl_op` field. Operand is the dest ptr. Payload is `Bin`. `lhs` is the639 /// Uses the `bin_op` field. LHS is the dest slice. RHS is the element value.
638 /// value, `rhs` is the length.
639 /// The element type may be any type, not just u8.
640 memset,640 memset,
641 /// Given dest ptr, src ptr, and len, copy len elements from src to dest.641 /// Given dest pointer and source pointer, copy elements from source to dest.
642 /// Dest pointer is either a slice or a pointer to array.
643 /// The dest element type may be any type.
644 /// Source pointer must have same element type as dest element type.
645 /// Dest slice may have any alignment; source pointer may have any alignment.
646 /// The two memory regions must not overlap.
642 /// Result type is always void.647 /// Result type is always void.
643 /// Uses the `pl_op` field. Operand is the dest ptr. Payload is `Bin`. `lhs` is the648 /// Uses the `bin_op` field. LHS is the dest slice. RHS is the source pointer.
644 /// src ptr, `rhs` is the length.
645 /// The element type may be any type, not just u8.
646 memcpy,649 memcpy,
647650
648 /// Uses the `ty_pl` field with payload `Cmpxchg`.651 /// Uses the `ty_pl` field with payload `Cmpxchg`.
src/AstGen.zig+6-8
...@@ -8453,18 +8453,16 @@ fn builtinCall(...@@ -8453,18 +8453,16 @@ fn builtinCall(
8453 return rvalue(gz, ri, result, node);8453 return rvalue(gz, ri, result, node);
8454 },8454 },
8455 .memcpy => {8455 .memcpy => {
8456 _ = try gz.addPlNode(.memcpy, node, Zir.Inst.Memcpy{8456 _ = try gz.addPlNode(.memcpy, node, Zir.Inst.Bin{
8457 .dest = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .manyptr_u8_type } }, params[0]),8457 .lhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
8458 .source = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .manyptr_const_u8_type } }, params[1]),8458 .rhs = try expr(gz, scope, .{ .rl = .ref }, params[1]),
8459 .byte_count = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, params[2]),
8460 });8459 });
8461 return rvalue(gz, ri, .void_value, node);8460 return rvalue(gz, ri, .void_value, node);
8462 },8461 },
8463 .memset => {8462 .memset => {
8464 _ = try gz.addPlNode(.memset, node, Zir.Inst.Memset{8463 _ = try gz.addPlNode(.memset, node, Zir.Inst.Bin{
8465 .dest = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .manyptr_u8_type } }, params[0]),8464 .lhs = try expr(gz, scope, .{ .rl = .none }, params[0]),
8466 .byte = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .u8_type } }, params[1]),8465 .rhs = try expr(gz, scope, .{ .rl = .none }, params[1]),
8467 .byte_count = try expr(gz, scope, .{ .rl = .{ .coerced_ty = .usize_type } }, params[2]),
8468 });8466 });
8469 return rvalue(gz, ri, .void_value, node);8467 return rvalue(gz, ri, .void_value, node);
8470 },8468 },
src/BuiltinFn.zig+2-2
...@@ -615,14 +615,14 @@ pub const list = list: {...@@ -615,14 +615,14 @@ pub const list = list: {
615 "@memcpy",615 "@memcpy",
616 .{616 .{
617 .tag = .memcpy,617 .tag = .memcpy,
618 .param_count = 3,618 .param_count = 2,
619 },619 },
620 },620 },
621 .{621 .{
622 "@memset",622 "@memset",
623 .{623 .{
624 .tag = .memset,624 .tag = .memset,
625 .param_count = 3,625 .param_count = 2,
626 },626 },
627 },627 },
628 .{628 .{
src/Liveness.zig+4-17
...@@ -304,6 +304,8 @@ pub fn categorizeOperand(...@@ -304,6 +304,8 @@ pub fn categorizeOperand(
304 .atomic_store_release,304 .atomic_store_release,
305 .atomic_store_seq_cst,305 .atomic_store_seq_cst,
306 .set_union_tag,306 .set_union_tag,
307 .memset,
308 .memcpy,
307 => {309 => {
308 const o = air_datas[inst].bin_op;310 const o = air_datas[inst].bin_op;
309 if (o.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write);311 if (o.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write);
...@@ -597,16 +599,6 @@ pub fn categorizeOperand(...@@ -597,16 +599,6 @@ pub fn categorizeOperand(
597 if (extra.operand == operand_ref) return matchOperandSmallIndex(l, inst, 1, .write);599 if (extra.operand == operand_ref) return matchOperandSmallIndex(l, inst, 1, .write);
598 return .write;600 return .write;
599 },601 },
600 .memset,
601 .memcpy,
602 => {
603 const pl_op = air_datas[inst].pl_op;
604 const extra = air.extraData(Air.Bin, pl_op.payload).data;
605 if (pl_op.operand == operand_ref) return matchOperandSmallIndex(l, inst, 0, .write);
606 if (extra.lhs == operand_ref) return matchOperandSmallIndex(l, inst, 1, .write);
607 if (extra.rhs == operand_ref) return matchOperandSmallIndex(l, inst, 2, .write);
608 return .write;
609 },
610602
611 .br => {603 .br => {
612 const br = air_datas[inst].br;604 const br = air_datas[inst].br;
...@@ -987,6 +979,8 @@ fn analyzeInst(...@@ -987,6 +979,8 @@ fn analyzeInst(
987 .set_union_tag,979 .set_union_tag,
988 .min,980 .min,
989 .max,981 .max,
982 .memset,
983 .memcpy,
990 => {984 => {
991 const o = inst_datas[inst].bin_op;985 const o = inst_datas[inst].bin_op;
992 return analyzeOperands(a, pass, data, inst, .{ o.lhs, o.rhs, .none });986 return analyzeOperands(a, pass, data, inst, .{ o.lhs, o.rhs, .none });
...@@ -1234,13 +1228,6 @@ fn analyzeInst(...@@ -1234,13 +1228,6 @@ fn analyzeInst(
1234 const extra = a.air.extraData(Air.AtomicRmw, pl_op.payload).data;1228 const extra = a.air.extraData(Air.AtomicRmw, pl_op.payload).data;
1235 return analyzeOperands(a, pass, data, inst, .{ pl_op.operand, extra.operand, .none });1229 return analyzeOperands(a, pass, data, inst, .{ pl_op.operand, extra.operand, .none });
1236 },1230 },
1237 .memset,
1238 .memcpy,
1239 => {
1240 const pl_op = inst_datas[inst].pl_op;
1241 const extra = a.air.extraData(Air.Bin, pl_op.payload).data;
1242 return analyzeOperands(a, pass, data, inst, .{ pl_op.operand, extra.lhs, extra.rhs });
1243 },
12441231
1245 .br => return analyzeInstBr(a, pass, data, inst),1232 .br => return analyzeInstBr(a, pass, data, inst),
12461233
src/Sema.zig+57-56
...@@ -9861,8 +9861,11 @@ fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -9861,8 +9861,11 @@ fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
9861 const extra = sema.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data;9861 const extra = sema.code.extraData(Zir.Inst.SliceStart, inst_data.payload_index).data;
9862 const array_ptr = try sema.resolveInst(extra.lhs);9862 const array_ptr = try sema.resolveInst(extra.lhs);
9863 const start = try sema.resolveInst(extra.start);9863 const start = try sema.resolveInst(extra.start);
9864 const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node };
9865 const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
9866 const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
98649867
9865 return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded);9868 return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded, ptr_src, start_src, end_src);
9866}9869}
98679870
9868fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9871fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -9875,8 +9878,11 @@ fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -9875,8 +9878,11 @@ fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
9875 const array_ptr = try sema.resolveInst(extra.lhs);9878 const array_ptr = try sema.resolveInst(extra.lhs);
9876 const start = try sema.resolveInst(extra.start);9879 const start = try sema.resolveInst(extra.start);
9877 const end = try sema.resolveInst(extra.end);9880 const end = try sema.resolveInst(extra.end);
9881 const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node };
9882 const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
9883 const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
98789884
9879 return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded);9885 return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded, ptr_src, start_src, end_src);
9880}9886}
98819887
9882fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {9888fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -9891,8 +9897,11 @@ fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -9891,8 +9897,11 @@ fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
9891 const start = try sema.resolveInst(extra.start);9897 const start = try sema.resolveInst(extra.start);
9892 const end = try sema.resolveInst(extra.end);9898 const end = try sema.resolveInst(extra.end);
9893 const sentinel = try sema.resolveInst(extra.sentinel);9899 const sentinel = try sema.resolveInst(extra.sentinel);
9900 const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node };
9901 const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
9902 const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
98949903
9895 return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src);9904 return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src, ptr_src, start_src, end_src);
9896}9905}
98979906
9898fn zirSwitchCapture(9907fn zirSwitchCapture(
...@@ -20393,6 +20402,22 @@ fn checkPtrType(...@@ -20393,6 +20402,22 @@ fn checkPtrType(
20393 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(sema.mod)});20402 return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(sema.mod)});
20394}20403}
2039520404
20405fn checkSliceOrArrayType(
20406 sema: *Sema,
20407 block: *Block,
20408 ty_src: LazySrcLoc,
20409 ty: Type,
20410) CompileError!void {
20411 if (ty.zigTypeTag() == .Pointer) {
20412 switch (ty.ptrSize()) {
20413 .Slice => return,
20414 .One => if (ty.childType().zigTypeTag() == .Array) return,
20415 else => {},
20416 }
20417 }
20418 return sema.fail(block, ty_src, "expected slice or array pointer; found '{}'", .{ty.fmt(sema.mod)});
20419}
20420
20396fn checkVectorElemType(20421fn checkVectorElemType(
20397 sema: *Sema,20422 sema: *Sema,
20398 block: *Block,20423 block: *Block,
...@@ -21750,88 +21775,64 @@ fn analyzeMinMax(...@@ -21750,88 +21775,64 @@ fn analyzeMinMax(
2175021775
21751fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {21776fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
21752 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;21777 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
21753 const extra = sema.code.extraData(Zir.Inst.Memcpy, inst_data.payload_index).data;21778 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
21754 const src = inst_data.src();21779 const src = inst_data.src();
21755 const dest_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };21780 const dest_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
21756 const src_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };21781 const src_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
21757 const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };21782 const dest_ptr = try sema.resolveInst(extra.lhs);
21758 const uncasted_dest_ptr = try sema.resolveInst(extra.dest);21783 const src_ptr_ptr = try sema.resolveInst(extra.rhs);
2175921784 const dest_ptr_ty = sema.typeOf(dest_ptr);
21760 // TODO AstGen's coerced_ty cannot handle volatile here21785 try checkSliceOrArrayType(sema, block, dest_src, dest_ptr_ty);
21761 var dest_ptr_info = Type.initTag(.manyptr_u8).ptrInfo().data;21786
21762 dest_ptr_info.@"volatile" = sema.typeOf(uncasted_dest_ptr).isVolatilePtr();21787 const dest_len = try sema.fieldVal(block, dest_src, dest_ptr, "len", dest_src);
21763 const dest_ptr_ty = try Type.ptr(sema.arena, sema.mod, dest_ptr_info);21788 const src_ptr = try sema.analyzeSlice(block, src_src, src_ptr_ptr, .zero_usize, dest_len, .none, .unneeded, src_src, src_src, src_src);
21764 const dest_ptr = try sema.coerce(block, dest_ptr_ty, uncasted_dest_ptr, dest_src);
21765
21766 const uncasted_src_ptr = try sema.resolveInst(extra.source);
21767 var src_ptr_info = Type.initTag(.manyptr_const_u8).ptrInfo().data;
21768 src_ptr_info.@"volatile" = sema.typeOf(uncasted_src_ptr).isVolatilePtr();
21769 const src_ptr_ty = try Type.ptr(sema.arena, sema.mod, src_ptr_info);
21770 const src_ptr = try sema.coerce(block, src_ptr_ty, uncasted_src_ptr, src_src);
21771 const len = try sema.coerce(block, Type.usize, try sema.resolveInst(extra.byte_count), len_src);
2177221789
21773 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: {21790 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: {
21774 if (!dest_ptr_val.isComptimeMutablePtr()) break :rs dest_src;21791 if (!dest_ptr_val.isComptimeMutablePtr()) break :rs dest_src;
21775 if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |src_ptr_val| {21792 if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |src_ptr_val| {
21776 if (!src_ptr_val.isComptimeMutablePtr()) break :rs src_src;21793 if (!src_ptr_val.isComptimeMutablePtr()) break :rs src_src;
21777 if (try sema.resolveDefinedValue(block, len_src, len)) |len_val| {21794 return sema.fail(block, src, "TODO: @memcpy at comptime", .{});
21778 _ = len_val;
21779 return sema.fail(block, src, "TODO: Sema.zirMemcpy at comptime", .{});
21780 } else break :rs len_src;
21781 } else break :rs src_src;21795 } else break :rs src_src;
21782 } else dest_src;21796 } else dest_src;
2178321797
21784 try sema.requireRuntimeBlock(block, src, runtime_src);21798 try sema.requireRuntimeBlock(block, src, runtime_src);
21785 _ = try block.addInst(.{21799 _ = try block.addInst(.{
21786 .tag = .memcpy,21800 .tag = .memcpy,
21787 .data = .{ .pl_op = .{21801 .data = .{ .bin_op = .{
21788 .operand = dest_ptr,21802 .lhs = dest_ptr,
21789 .payload = try sema.addExtra(Air.Bin{21803 .rhs = src_ptr,
21790 .lhs = src_ptr,
21791 .rhs = len,
21792 }),
21793 } },21804 } },
21794 });21805 });
21795}21806}
2179621807
21797fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {21808fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
21798 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;21809 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
21799 const extra = sema.code.extraData(Zir.Inst.Memset, inst_data.payload_index).data;21810 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
21800 const src = inst_data.src();21811 const src = inst_data.src();
21801 const dest_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };21812 const dest_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
21802 const value_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };21813 const value_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
21803 const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };21814 const dest_ptr = try sema.resolveInst(extra.lhs);
21804 const uncasted_dest_ptr = try sema.resolveInst(extra.dest);21815 const uncoerced_elem = try sema.resolveInst(extra.rhs);
21816 const dest_ptr_ty = sema.typeOf(dest_ptr);
21817 try checkSliceOrArrayType(sema, block, dest_src, dest_ptr_ty);
2180521818
21806 // TODO AstGen's coerced_ty cannot handle volatile here21819 const elem_ty = dest_ptr_ty.elemType2();
21807 var ptr_info = Type.initTag(.manyptr_u8).ptrInfo().data;21820 const elem = try sema.coerce(block, elem_ty, uncoerced_elem, value_src);
21808 ptr_info.@"volatile" = sema.typeOf(uncasted_dest_ptr).isVolatilePtr();
21809 const dest_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
21810 const dest_ptr = try sema.coerce(block, dest_ptr_ty, uncasted_dest_ptr, dest_src);
21811
21812 const value = try sema.coerce(block, Type.u8, try sema.resolveInst(extra.byte), value_src);
21813 const len = try sema.coerce(block, Type.usize, try sema.resolveInst(extra.byte_count), len_src);
2181421821
21815 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: {21822 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: {
21816 if (!ptr_val.isComptimeMutablePtr()) break :rs dest_src;21823 if (!ptr_val.isComptimeMutablePtr()) break :rs dest_src;
21817 if (try sema.resolveDefinedValue(block, len_src, len)) |len_val| {21824 if (try sema.resolveMaybeUndefVal(elem)) |elem_val| {
21818 if (try sema.resolveMaybeUndefVal(value)) |val| {21825 _ = elem_val;
21819 _ = len_val;21826 return sema.fail(block, src, "TODO: @memset at comptime", .{});
21820 _ = val;21827 } else break :rs value_src;
21821 return sema.fail(block, src, "TODO: Sema.zirMemset at comptime", .{});
21822 } else break :rs value_src;
21823 } else break :rs len_src;
21824 } else dest_src;21828 } else dest_src;
2182521829
21826 try sema.requireRuntimeBlock(block, src, runtime_src);21830 try sema.requireRuntimeBlock(block, src, runtime_src);
21827 _ = try block.addInst(.{21831 _ = try block.addInst(.{
21828 .tag = .memset,21832 .tag = .memset,
21829 .data = .{ .pl_op = .{21833 .data = .{ .bin_op = .{
21830 .operand = dest_ptr,21834 .lhs = dest_ptr,
21831 .payload = try sema.addExtra(Air.Bin{21835 .rhs = elem,
21832 .lhs = value,
21833 .rhs = len,
21834 }),
21835 } },21836 } },
21836 });21837 });
21837}21838}
...@@ -28753,10 +28754,10 @@ fn analyzeSlice(...@@ -28753,10 +28754,10 @@ fn analyzeSlice(
28753 uncasted_end_opt: Air.Inst.Ref,28754 uncasted_end_opt: Air.Inst.Ref,
28754 sentinel_opt: Air.Inst.Ref,28755 sentinel_opt: Air.Inst.Ref,
28755 sentinel_src: LazySrcLoc,28756 sentinel_src: LazySrcLoc,
28757 ptr_src: LazySrcLoc,
28758 start_src: LazySrcLoc,
28759 end_src: LazySrcLoc,
28756) CompileError!Air.Inst.Ref {28760) CompileError!Air.Inst.Ref {
28757 const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = src.node_offset.x };
28758 const start_src: LazySrcLoc = .{ .node_offset_slice_start = src.node_offset.x };
28759 const end_src: LazySrcLoc = .{ .node_offset_slice_end = src.node_offset.x };
28760 // Slice expressions can operate on a variable whose type is an array. This requires28761 // Slice expressions can operate on a variable whose type is an array. This requires
28761 // the slice operand to be a pointer. In the case of a non-array, it will be a double pointer.28762 // the slice operand to be a pointer. In the case of a non-array, it will be a double pointer.
28762 const ptr_ptr_ty = sema.typeOf(ptr_ptr);28763 const ptr_ptr_ty = sema.typeOf(ptr_ptr);
src/Zir.zig+2-14
...@@ -922,10 +922,10 @@ pub const Inst = struct {...@@ -922,10 +922,10 @@ pub const Inst = struct {
922 /// Uses the `pl_node` union field with payload `FieldParentPtr`.922 /// Uses the `pl_node` union field with payload `FieldParentPtr`.
923 field_parent_ptr,923 field_parent_ptr,
924 /// Implements the `@memcpy` builtin.924 /// Implements the `@memcpy` builtin.
925 /// Uses the `pl_node` union field with payload `Memcpy`.925 /// Uses the `pl_node` union field with payload `Bin`.
926 memcpy,926 memcpy,
927 /// Implements the `@memset` builtin.927 /// Implements the `@memset` builtin.
928 /// Uses the `pl_node` union field with payload `Memset`.928 /// Uses the `pl_node` union field with payload `Bin`.
929 memset,929 memset,
930 /// Implements the `@min` builtin.930 /// Implements the `@min` builtin.
931 /// Uses the `pl_node` union field with payload `Bin`931 /// Uses the `pl_node` union field with payload `Bin`
...@@ -3501,18 +3501,6 @@ pub const Inst = struct {...@@ -3501,18 +3501,6 @@ pub const Inst = struct {
3501 field_ptr: Ref,3501 field_ptr: Ref,
3502 };3502 };
35033503
3504 pub const Memcpy = struct {
3505 dest: Ref,
3506 source: Ref,
3507 byte_count: Ref,
3508 };
3509
3510 pub const Memset = struct {
3511 dest: Ref,
3512 byte: Ref,
3513 byte_count: Ref,
3514 };
3515
3516 pub const Shuffle = struct {3504 pub const Shuffle = struct {
3517 elem_type: Ref,3505 elem_type: Ref,
3518 a: Ref,3506 a: Ref,
src/codegen/llvm.zig+54-17
...@@ -5776,6 +5776,36 @@ pub const FuncGen = struct {...@@ -5776,6 +5776,36 @@ pub const FuncGen = struct {
5776 return result;5776 return result;
5777 }5777 }
57785778
5779 fn sliceOrArrayPtr(fg: *FuncGen, ptr: *llvm.Value, ty: Type) *llvm.Value {
5780 switch (ty.ptrSize()) {
5781 .Slice => return fg.builder.buildExtractValue(ptr, 0, ""),
5782 .One => return ptr,
5783 .Many, .C => unreachable,
5784 }
5785 }
5786
5787 fn sliceOrArrayLenInBytes(fg: *FuncGen, ptr: *llvm.Value, ty: Type) *llvm.Value {
5788 const target = fg.dg.module.getTarget();
5789 const llvm_usize_ty = fg.context.intType(target.cpu.arch.ptrBitWidth());
5790 switch (ty.ptrSize()) {
5791 .Slice => {
5792 const len = fg.builder.buildExtractValue(ptr, 1, "");
5793 const elem_ty = ty.childType();
5794 const abi_size = elem_ty.abiSize(target);
5795 if (abi_size == 1) return len;
5796 const abi_size_llvm_val = llvm_usize_ty.constInt(abi_size, .False);
5797 return fg.builder.buildMul(len, abi_size_llvm_val, "");
5798 },
5799 .One => {
5800 const array_ty = ty.childType();
5801 const elem_ty = array_ty.childType();
5802 const abi_size = elem_ty.abiSize(target);
5803 return llvm_usize_ty.constInt(array_ty.arrayLen() * abi_size, .False);
5804 },
5805 .Many, .C => unreachable,
5806 }
5807 }
5808
5779 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value {5809 fn airSliceField(self: *FuncGen, inst: Air.Inst.Index, index: c_uint) !?*llvm.Value {
5780 const ty_op = self.air.instructions.items(.data)[inst].ty_op;5810 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
5781 const operand = try self.resolveInst(ty_op.operand);5811 const operand = try self.resolveInst(ty_op.operand);
...@@ -8374,18 +8404,24 @@ pub const FuncGen = struct {...@@ -8374,18 +8404,24 @@ pub const FuncGen = struct {
8374 }8404 }
83758405
8376 fn airMemset(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8406 fn airMemset(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8377 const pl_op = self.air.instructions.items(.data)[inst].pl_op;8407 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
8378 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;8408 const dest_slice = try self.resolveInst(bin_op.lhs);
8379 const dest_ptr = try self.resolveInst(pl_op.operand);8409 const ptr_ty = self.air.typeOf(bin_op.lhs);
8380 const ptr_ty = self.air.typeOf(pl_op.operand);8410 const value = try self.resolveInst(bin_op.rhs);
8381 const value = try self.resolveInst(extra.lhs);8411 const elem_ty = self.air.typeOf(bin_op.rhs);
8382 const val_is_undef = if (self.air.value(extra.lhs)) |val| val.isUndefDeep() else false;
8383 const len = try self.resolveInst(extra.rhs);
8384 const u8_llvm_ty = self.context.intType(8);
8385 const fill_char = if (val_is_undef) u8_llvm_ty.constInt(0xaa, .False) else value;
8386 const target = self.dg.module.getTarget();8412 const target = self.dg.module.getTarget();
8413 const val_is_undef = if (self.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false;
8414 const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
8415 const dest_ptr = self.sliceOrArrayPtr(dest_slice, ptr_ty);
8416 const u8_llvm_ty = self.context.intType(8);
8417 const fill_byte = if (val_is_undef) u8_llvm_ty.constInt(0xaa, .False) else b: {
8418 if (elem_ty.abiSize(target) != 1) {
8419 return self.dg.todo("implement @memset for non-byte-sized element type", .{});
8420 }
8421 break :b self.builder.buildBitCast(value, u8_llvm_ty, "");
8422 };
8387 const dest_ptr_align = ptr_ty.ptrAlignment(target);8423 const dest_ptr_align = ptr_ty.ptrAlignment(target);
8388 _ = self.builder.buildMemSet(dest_ptr, fill_char, len, dest_ptr_align, ptr_ty.isVolatilePtr());8424 _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, ptr_ty.isVolatilePtr());
83898425
8390 if (val_is_undef and self.dg.module.comp.bin_file.options.valgrind) {8426 if (val_is_undef and self.dg.module.comp.bin_file.options.valgrind) {
8391 self.valgrindMarkUndef(dest_ptr, len);8427 self.valgrindMarkUndef(dest_ptr, len);
...@@ -8394,13 +8430,14 @@ pub const FuncGen = struct {...@@ -8394,13 +8430,14 @@ pub const FuncGen = struct {
8394 }8430 }
83958431
8396 fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {8432 fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
8397 const pl_op = self.air.instructions.items(.data)[inst].pl_op;8433 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
8398 const extra = self.air.extraData(Air.Bin, pl_op.payload).data;8434 const dest_slice = try self.resolveInst(bin_op.lhs);
8399 const dest_ptr = try self.resolveInst(pl_op.operand);8435 const dest_ptr_ty = self.air.typeOf(bin_op.lhs);
8400 const dest_ptr_ty = self.air.typeOf(pl_op.operand);8436 const src_slice = try self.resolveInst(bin_op.rhs);
8401 const src_ptr = try self.resolveInst(extra.lhs);8437 const src_ptr_ty = self.air.typeOf(bin_op.rhs);
8402 const src_ptr_ty = self.air.typeOf(extra.lhs);8438 const src_ptr = self.sliceOrArrayPtr(src_slice, src_ptr_ty);
8403 const len = try self.resolveInst(extra.rhs);8439 const len = self.sliceOrArrayLenInBytes(dest_slice, dest_ptr_ty);
8440 const dest_ptr = self.sliceOrArrayPtr(dest_slice, dest_ptr_ty);
8404 const is_volatile = src_ptr_ty.isVolatilePtr() or dest_ptr_ty.isVolatilePtr();8441 const is_volatile = src_ptr_ty.isVolatilePtr() or dest_ptr_ty.isVolatilePtr();
8405 const target = self.dg.module.getTarget();8442 const target = self.dg.module.getTarget();
8406 _ = self.builder.buildMemCpy(8443 _ = self.builder.buildMemCpy(
src/print_air.zig+2-24
...@@ -169,6 +169,8 @@ const Writer = struct {...@@ -169,6 +169,8 @@ const Writer = struct {
169 .cmp_gte_optimized,169 .cmp_gte_optimized,
170 .cmp_gt_optimized,170 .cmp_gt_optimized,
171 .cmp_neq_optimized,171 .cmp_neq_optimized,
172 .memcpy,
173 .memset,
172 => try w.writeBinOp(s, inst),174 => try w.writeBinOp(s, inst),
173175
174 .is_null,176 .is_null,
...@@ -315,8 +317,6 @@ const Writer = struct {...@@ -315,8 +317,6 @@ const Writer = struct {
315 .atomic_store_release => try w.writeAtomicStore(s, inst, .Release),317 .atomic_store_release => try w.writeAtomicStore(s, inst, .Release),
316 .atomic_store_seq_cst => try w.writeAtomicStore(s, inst, .SeqCst),318 .atomic_store_seq_cst => try w.writeAtomicStore(s, inst, .SeqCst),
317 .atomic_rmw => try w.writeAtomicRmw(s, inst),319 .atomic_rmw => try w.writeAtomicRmw(s, inst),
318 .memcpy => try w.writeMemcpy(s, inst),
319 .memset => try w.writeMemset(s, inst),
320 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),320 .field_parent_ptr => try w.writeFieldParentPtr(s, inst),
321 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),321 .wasm_memory_size => try w.writeWasmMemorySize(s, inst),
322 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),322 .wasm_memory_grow => try w.writeWasmMemoryGrow(s, inst),
...@@ -591,17 +591,6 @@ const Writer = struct {...@@ -591,17 +591,6 @@ const Writer = struct {
591 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });591 try s.print(", {s}, {s}", .{ @tagName(extra.op()), @tagName(extra.ordering()) });
592 }592 }
593593
594 fn writeMemset(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
595 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
596 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
597
598 try w.writeOperand(s, inst, 0, pl_op.operand);
599 try s.writeAll(", ");
600 try w.writeOperand(s, inst, 1, extra.lhs);
601 try s.writeAll(", ");
602 try w.writeOperand(s, inst, 2, extra.rhs);
603 }
604
605 fn writeFieldParentPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {594 fn writeFieldParentPtr(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
606 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;595 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
607 const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;596 const extra = w.air.extraData(Air.FieldParentPtr, ty_pl.payload).data;
...@@ -610,17 +599,6 @@ const Writer = struct {...@@ -610,17 +599,6 @@ const Writer = struct {
610 try s.print(", {d}", .{extra.field_index});599 try s.print(", {d}", .{extra.field_index});
611 }600 }
612601
613 fn writeMemcpy(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
614 const pl_op = w.air.instructions.items(.data)[inst].pl_op;
615 const extra = w.air.extraData(Air.Bin, pl_op.payload).data;
616
617 try w.writeOperand(s, inst, 0, pl_op.operand);
618 try s.writeAll(", ");
619 try w.writeOperand(s, inst, 1, extra.lhs);
620 try s.writeAll(", ");
621 try w.writeOperand(s, inst, 2, extra.rhs);
622 }
623
624 fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {602 fn writeConstant(w: *Writer, s: anytype, inst: Air.Inst.Index) @TypeOf(s).Error!void {
625 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;603 const ty_pl = w.air.instructions.items(.data)[inst].ty_pl;
626 const val = w.air.values[ty_pl.payload];604 const val = w.air.values[ty_pl.payload];
src/print_zir.zig+2-28
...@@ -277,8 +277,6 @@ const Writer = struct {...@@ -277,8 +277,6 @@ const Writer = struct {
277 .atomic_load => try self.writeAtomicLoad(stream, inst),277 .atomic_load => try self.writeAtomicLoad(stream, inst),
278 .atomic_store => try self.writeAtomicStore(stream, inst),278 .atomic_store => try self.writeAtomicStore(stream, inst),
279 .atomic_rmw => try self.writeAtomicRmw(stream, inst),279 .atomic_rmw => try self.writeAtomicRmw(stream, inst),
280 .memcpy => try self.writeMemcpy(stream, inst),
281 .memset => try self.writeMemset(stream, inst),
282 .shuffle => try self.writeShuffle(stream, inst),280 .shuffle => try self.writeShuffle(stream, inst),
283 .mul_add => try self.writeMulAdd(stream, inst),281 .mul_add => try self.writeMulAdd(stream, inst),
284 .field_parent_ptr => try self.writeFieldParentPtr(stream, inst),282 .field_parent_ptr => try self.writeFieldParentPtr(stream, inst),
...@@ -346,6 +344,8 @@ const Writer = struct {...@@ -346,6 +344,8 @@ const Writer = struct {
346 .vector_type,344 .vector_type,
347 .max,345 .max,
348 .min,346 .min,
347 .memcpy,
348 .memset,
349 .elem_ptr_node,349 .elem_ptr_node,
350 .elem_val_node,350 .elem_val_node,
351 .elem_ptr,351 .elem_ptr,
...@@ -1000,32 +1000,6 @@ const Writer = struct {...@@ -1000,32 +1000,6 @@ const Writer = struct {
1000 try self.writeSrc(stream, inst_data.src());1000 try self.writeSrc(stream, inst_data.src());
1001 }1001 }
10021002
1003 fn writeMemcpy(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1004 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1005 const extra = self.code.extraData(Zir.Inst.Memcpy, inst_data.payload_index).data;
1006
1007 try self.writeInstRef(stream, extra.dest);
1008 try stream.writeAll(", ");
1009 try self.writeInstRef(stream, extra.source);
1010 try stream.writeAll(", ");
1011 try self.writeInstRef(stream, extra.byte_count);
1012 try stream.writeAll(") ");
1013 try self.writeSrc(stream, inst_data.src());
1014 }
1015
1016 fn writeMemset(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1017 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1018 const extra = self.code.extraData(Zir.Inst.Memset, inst_data.payload_index).data;
1019
1020 try self.writeInstRef(stream, extra.dest);
1021 try stream.writeAll(", ");
1022 try self.writeInstRef(stream, extra.byte);
1023 try stream.writeAll(", ");
1024 try self.writeInstRef(stream, extra.byte_count);
1025 try stream.writeAll(") ");
1026 try self.writeSrc(stream, inst_data.src());
1027 }
1028
1029 fn writeStructInitAnon(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {1003 fn writeStructInitAnon(self: *Writer, stream: anytype, inst: Zir.Inst.Index) !void {
1030 const inst_data = self.code.instructions.items(.data)[inst].pl_node;1004 const inst_data = self.code.instructions.items(.data)[inst].pl_node;
1031 const extra = self.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);1005 const extra = self.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);
test/behavior/basic.zig+2-2
...@@ -367,8 +367,8 @@ fn testMemcpyMemset() !void {...@@ -367,8 +367,8 @@ fn testMemcpyMemset() !void {
367 var foo: [20]u8 = undefined;367 var foo: [20]u8 = undefined;
368 var bar: [20]u8 = undefined;368 var bar: [20]u8 = undefined;
369369
370 @memset(&foo, 'A', foo.len);370 @memset(&foo, 'A');
371 @memcpy(&bar, &foo, bar.len);371 @memcpy(&bar, &foo);
372372
373 try expect(bar[0] == 'A');373 try expect(bar[0] == 'A');
374 try expect(bar[11] == 'A');374 try expect(bar[11] == 'A');
test/behavior/bugs/718.zig+1-1
...@@ -14,7 +14,7 @@ test "zero keys with @memset" {...@@ -14,7 +14,7 @@ test "zero keys with @memset" {
14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO14 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; // TODO
15 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO15 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
1616
17 @memset(@ptrCast([*]u8, &keys), 0, @sizeOf(@TypeOf(keys)));17 @memset(@ptrCast([*]u8, &keys)[0..@sizeOf(@TypeOf(keys))], 0);
18 try expect(!keys.up);18 try expect(!keys.up);
19 try expect(!keys.down);19 try expect(!keys.down);
20 try expect(!keys.left);20 try expect(!keys.left);
test/behavior/struct.zig+2-2
...@@ -91,7 +91,7 @@ test "structs" {...@@ -91,7 +91,7 @@ test "structs" {
91 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO91 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO
9292
93 var foo: StructFoo = undefined;93 var foo: StructFoo = undefined;
94 @memset(@ptrCast([*]u8, &foo), 0, @sizeOf(StructFoo));94 @memset(@ptrCast([*]u8, &foo)[0..@sizeOf(StructFoo)], 0);
95 foo.a += 1;95 foo.a += 1;
96 foo.b = foo.a == 1;96 foo.b = foo.a == 1;
97 try testFoo(foo);97 try testFoo(foo);
...@@ -498,7 +498,7 @@ test "packed struct fields are ordered from LSB to MSB" {...@@ -498,7 +498,7 @@ test "packed struct fields are ordered from LSB to MSB" {
498498
499 var all: u64 = 0x7765443322221111;499 var all: u64 = 0x7765443322221111;
500 var bytes: [8]u8 align(@alignOf(Bitfields)) = undefined;500 var bytes: [8]u8 align(@alignOf(Bitfields)) = undefined;
501 @memcpy(&bytes, @ptrCast([*]u8, &all), 8);501 @memcpy(bytes[0..8], @ptrCast([*]u8, &all));
502 var bitfields = @ptrCast(*Bitfields, &bytes).*;502 var bitfields = @ptrCast(*Bitfields, &bytes).*;
503503
504 try expect(bitfields.f1 == 0x1111);504 try expect(bitfields.f1 == 0x1111);