From 00b690540e561391d17c65e45f818db6be8fecec Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 26 Apr 2023 12:49:32 -0700 Subject: llvm backend: fix lowering of memset The bitcast of ABI size 1 elements was problematic for some types. --- test/behavior.zig | 1 + test/behavior/basic.zig | 90 --------------------------------- test/behavior/memset.zig | 128 +++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 129 insertions(+), 90 deletions(-) create mode 100644 test/behavior/memset.zig (limited to 'test') diff --git a/test/behavior.zig b/test/behavior.zig index b6fe8d120f..c75e7bc788 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -177,6 +177,7 @@ test { _ = @import("behavior/math.zig"); _ = @import("behavior/maximum_minimum.zig"); _ = @import("behavior/member_func.zig"); + _ = @import("behavior/memset.zig"); _ = @import("behavior/merge_error_sets.zig"); _ = @import("behavior/muladd.zig"); _ = @import("behavior/namespace_depends_on_compile_var.zig"); diff --git a/test/behavior/basic.zig b/test/behavior/basic.zig index 06b1fdda64..437b1b1373 100644 --- a/test/behavior/basic.zig +++ b/test/behavior/basic.zig @@ -353,96 +353,6 @@ fn f2(x: bool) []const u8 { return (if (x) &fA else &fB)(); } -test "@memset on array pointers" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) { - // TODO: implement memset when element ABI size > 1 - return error.SkipZigTest; - } - - try testMemsetArray(); - try comptime testMemsetArray(); -} - -fn testMemsetArray() !void { - { - // memset array to non-undefined, ABI size == 1 - var foo: [20]u8 = undefined; - @memset(&foo, 'A'); - try expect(foo[0] == 'A'); - try expect(foo[11] == 'A'); - try expect(foo[19] == 'A'); - } - { - // memset array to non-undefined, ABI size > 1 - var foo: [20]u32 = undefined; - @memset(&foo, 1234); - try expect(foo[0] == 1234); - try expect(foo[11] == 1234); - try expect(foo[19] == 1234); - } -} - -test "@memset on slices" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_wasm) { - // TODO: implement memset when element ABI size > 1 - // TODO: implement memset on slices - return error.SkipZigTest; - } - - try testMemsetSlice(); - try comptime testMemsetSlice(); -} - -fn testMemsetSlice() !void { - { - // memset slice to non-undefined, ABI size == 1 - var array: [20]u8 = undefined; - var len = array.len; - var slice = array[0..len]; - @memset(slice, 'A'); - try expect(slice[0] == 'A'); - try expect(slice[11] == 'A'); - try expect(slice[19] == 'A'); - } - { - // memset slice to non-undefined, ABI size > 1 - var array: [20]u32 = undefined; - var len = array.len; - var slice = array[0..len]; - @memset(slice, 1234); - try expect(slice[0] == 1234); - try expect(slice[11] == 1234); - try expect(slice[19] == 1234); - } -} - -test "memcpy and memset intrinsics" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - - try testMemcpyMemset(); - try comptime testMemcpyMemset(); -} - -fn testMemcpyMemset() !void { - var foo: [20]u8 = undefined; - var bar: [20]u8 = undefined; - - @memset(&foo, 'A'); - @memcpy(&bar, &foo); - - try expect(bar[0] == 'A'); - try expect(bar[11] == 'A'); - try expect(bar[19] == 'A'); -} - test "variable is allowed to be a pointer to an opaque type" { var x: i32 = 1234; _ = hereIsAnOpaqueType(@ptrCast(*OpaqueA, &x)); diff --git a/test/behavior/memset.zig b/test/behavior/memset.zig new file mode 100644 index 0000000000..69add499f9 --- /dev/null +++ b/test/behavior/memset.zig @@ -0,0 +1,128 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const expect = std.testing.expect; + +test "@memset on array pointers" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) { + // TODO: implement memset when element ABI size > 1 + return error.SkipZigTest; + } + + try testMemsetArray(); + try comptime testMemsetArray(); +} + +fn testMemsetArray() !void { + { + // memset array to non-undefined, ABI size == 1 + var foo: [20]u8 = undefined; + @memset(&foo, 'A'); + try expect(foo[0] == 'A'); + try expect(foo[11] == 'A'); + try expect(foo[19] == 'A'); + } + { + // memset array to non-undefined, ABI size > 1 + var foo: [20]u32 = undefined; + @memset(&foo, 1234); + try expect(foo[0] == 1234); + try expect(foo[11] == 1234); + try expect(foo[19] == 1234); + } +} + +test "@memset on slices" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) { + // TODO: implement memset when element ABI size > 1 + // TODO: implement memset on slices + return error.SkipZigTest; + } + + try testMemsetSlice(); + try comptime testMemsetSlice(); +} + +fn testMemsetSlice() !void { + { + // memset slice to non-undefined, ABI size == 1 + var array: [20]u8 = undefined; + var len = array.len; + var slice = array[0..len]; + @memset(slice, 'A'); + try expect(slice[0] == 'A'); + try expect(slice[11] == 'A'); + try expect(slice[19] == 'A'); + } + { + // memset slice to non-undefined, ABI size > 1 + var array: [20]u32 = undefined; + var len = array.len; + var slice = array[0..len]; + @memset(slice, 1234); + try expect(slice[0] == 1234); + try expect(slice[11] == 1234); + try expect(slice[19] == 1234); + } +} + +test "memset with bool element" { + var buf: [5]bool = undefined; + @memset(&buf, true); + try expect(buf[2]); + try expect(buf[4]); +} + +test "memset with 1-byte struct element" { + const S = struct { x: bool }; + var buf: [5]S = undefined; + @memset(&buf, .{ .x = true }); + try expect(buf[2].x); + try expect(buf[4].x); +} + +test "memset with 1-byte array element" { + const A = [1]bool; + var buf: [5]A = undefined; + @memset(&buf, .{true}); + try expect(buf[2][0]); + try expect(buf[4][0]); +} + +test "memset with large array element" { + const A = [128]u64; + var buf: [5]A = undefined; + var runtime_known_element = [_]u64{0} ** 128; + @memset(&buf, runtime_known_element); + for (buf[0]) |elem| try expect(elem == 0); + for (buf[1]) |elem| try expect(elem == 0); + for (buf[2]) |elem| try expect(elem == 0); + for (buf[3]) |elem| try expect(elem == 0); + for (buf[4]) |elem| try expect(elem == 0); +} + +test "memcpy and memset intrinsics" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + + try testMemcpyMemset(); + try comptime testMemcpyMemset(); +} + +fn testMemcpyMemset() !void { + var foo: [20]u8 = undefined; + var bar: [20]u8 = undefined; + + @memset(&foo, 'A'); + @memcpy(&bar, &foo); + + try expect(bar[0] == 'A'); + try expect(bar[11] == 'A'); + try expect(bar[19] == 'A'); +} -- cgit v1.2.3 From 9295355985202c267b4326b5a6e2ad5158b48e5d Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 26 Apr 2023 13:41:02 -0700 Subject: LLVM backend: optimize memset with comptime-known element When the element is comptime-known, we can check if it has a repeated byte representation. In this case, `@memset` can be lowered with the LLVM intrinsic rather than with a loop. --- src/Sema.zig | 3 +++ src/codegen/llvm.zig | 47 ++++++++++++++++++++++++++++++++--------------- src/value.zig | 38 +++++++++++++++++++++++++++++++++++--- test/behavior/memset.zig | 14 +++++++++++++- 4 files changed, 83 insertions(+), 19 deletions(-) (limited to 'test') diff --git a/src/Sema.zig b/src/Sema.zig index 8b47f1877b..e05308b6c0 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -26953,9 +26953,11 @@ fn storePtrVal( defer sema.gpa.free(buffer); reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, sema.mod, buffer) catch |err| switch (err) { error.ReinterpretDeclRef => unreachable, + error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already }; operand_val.writeToMemory(operand_ty, sema.mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) { error.ReinterpretDeclRef => unreachable, + error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already }; const arena = mut_kit.beginArena(sema.mod); @@ -27905,6 +27907,7 @@ fn bitCastVal( defer sema.gpa.free(buffer); val.writeToMemory(old_ty, sema.mod, buffer) catch |err| switch (err) { error.ReinterpretDeclRef => return null, + error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already }; return try Value.readFromMemory(new_ty, sema.mod, buffer[buffer_offset..], sema.arena); } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index a7a1d8f56f..d697a41988 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -8424,28 +8424,45 @@ pub const FuncGen = struct { const dest_slice = try self.resolveInst(bin_op.lhs); const ptr_ty = self.air.typeOf(bin_op.lhs); const elem_ty = self.air.typeOf(bin_op.rhs); - const target = self.dg.module.getTarget(); - const val_is_undef = if (self.air.value(bin_op.rhs)) |val| val.isUndefDeep() else false; + const module = self.dg.module; + const target = module.getTarget(); const dest_ptr_align = ptr_ty.ptrAlignment(target); const u8_llvm_ty = self.context.intType(8); const dest_ptr = self.sliceOrArrayPtr(dest_slice, ptr_ty); const is_volatile = ptr_ty.isVolatilePtr(); - if (val_is_undef) { - // Even if safety is disabled, we still emit a memset to undefined since it conveys - // extra information to LLVM. However, safety makes the difference between using - // 0xaa or actual undefined for the fill byte. - const fill_byte = if (safety) - u8_llvm_ty.constInt(0xaa, .False) - else - u8_llvm_ty.getUndef(); - const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); - _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); + if (self.air.value(bin_op.rhs)) |elem_val| { + if (elem_val.isUndefDeep()) { + // Even if safety is disabled, we still emit a memset to undefined since it conveys + // extra information to LLVM. However, safety makes the difference between using + // 0xaa or actual undefined for the fill byte. + const fill_byte = if (safety) + u8_llvm_ty.constInt(0xaa, .False) + else + u8_llvm_ty.getUndef(); + const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); + _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); - if (safety and self.dg.module.comp.bin_file.options.valgrind) { - self.valgrindMarkUndef(dest_ptr, len); + if (safety and module.comp.bin_file.options.valgrind) { + self.valgrindMarkUndef(dest_ptr, len); + } + return null; + } + + // Test if the element value is compile-time known to be a + // repeating byte pattern, for example, `@as(u64, 0)` has a + // repeating byte pattern of 0 bytes. In such case, the memset + // intrinsic can be used. + var value_buffer: Value.Payload.U64 = undefined; + if (try elem_val.hasRepeatedByteRepr(elem_ty, module, &value_buffer)) |byte_val| { + const fill_byte = try self.resolveValue(.{ + .ty = Type.u8, + .val = byte_val, + }); + const len = self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); + _ = self.builder.buildMemSet(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile); + return null; } - return null; } const value = try self.resolveInst(bin_op.rhs); diff --git a/src/value.zig b/src/value.zig index 05e9d24ee2..2b9636f5e9 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1278,7 +1278,10 @@ pub const Value = extern union { /// /// Asserts that buffer.len >= ty.abiSize(). The buffer is allowed to extend past /// the end of the value in memory. - pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{ReinterpretDeclRef}!void { + pub fn writeToMemory(val: Value, ty: Type, mod: *Module, buffer: []u8) error{ + ReinterpretDeclRef, + IllDefinedMemoryLayout, + }!void { const target = mod.getTarget(); const endian = target.cpu.arch.endian(); if (val.isUndef()) { @@ -1345,7 +1348,7 @@ pub const Value = extern union { return writeToPackedMemory(val, ty, mod, buffer[0..byte_count], 0); }, .Struct => switch (ty.containerLayout()) { - .Auto => unreachable, // Sema is supposed to have emitted a compile error already + .Auto => return error.IllDefinedMemoryLayout, .Extern => { const fields = ty.structFields().values(); const field_vals = val.castTag(.aggregate).?.data; @@ -1366,7 +1369,7 @@ pub const Value = extern union { std.mem.writeInt(Int, buffer[0..@sizeOf(Int)], @intCast(Int, int), endian); }, .Union => switch (ty.containerLayout()) { - .Auto => unreachable, + .Auto => return error.IllDefinedMemoryLayout, .Extern => @panic("TODO implement writeToMemory for extern unions"), .Packed => { const byte_count = (@intCast(usize, ty.bitSize(target)) + 7) / 8; @@ -5381,6 +5384,35 @@ pub const Value = extern union { } } + /// If the value is represented in-memory as a series of bytes that all + /// have the same value, return that byte value, otherwise null. + pub fn hasRepeatedByteRepr(val: Value, ty: Type, mod: *Module, value_buffer: *Payload.U64) !?Value { + const target = mod.getTarget(); + const abi_size = ty.abiSize(target); + assert(abi_size >= 1); + const byte_buffer = try mod.gpa.alloc(u8, abi_size); + defer mod.gpa.free(byte_buffer); + + writeToMemory(val, ty, mod, byte_buffer) catch |err| switch (err) { + error.ReinterpretDeclRef => return null, + // TODO: The writeToMemory function was originally created for the purpose + // of comptime pointer casting. However, it is now additionally being used + // for checking the actual memory layout that will be generated by machine + // code late in compilation. So, this error handling is too aggressive and + // causes some false negatives, causing less-than-ideal code generation. + error.IllDefinedMemoryLayout => return null, + }; + const first_byte = byte_buffer[0]; + for (byte_buffer[1..]) |byte| { + if (byte != first_byte) return null; + } + value_buffer.* = .{ + .base = .{ .tag = .int_u64 }, + .data = first_byte, + }; + return initPayload(&value_buffer.base); + } + /// This type is not copyable since it may contain pointers to its inner data. pub const Payload = struct { tag: Tag, diff --git a/test/behavior/memset.zig b/test/behavior/memset.zig index 69add499f9..374fd4b6f5 100644 --- a/test/behavior/memset.zig +++ b/test/behavior/memset.zig @@ -94,7 +94,7 @@ test "memset with 1-byte array element" { try expect(buf[4][0]); } -test "memset with large array element" { +test "memset with large array element, runtime known" { const A = [128]u64; var buf: [5]A = undefined; var runtime_known_element = [_]u64{0} ** 128; @@ -106,6 +106,18 @@ test "memset with large array element" { for (buf[4]) |elem| try expect(elem == 0); } +test "memset with large array element, comptime known" { + const A = [128]u64; + var buf: [5]A = undefined; + const comptime_known_element = [_]u64{0} ** 128; + @memset(&buf, comptime_known_element); + for (buf[0]) |elem| try expect(elem == 0); + for (buf[1]) |elem| try expect(elem == 0); + for (buf[2]) |elem| try expect(elem == 0); + for (buf[3]) |elem| try expect(elem == 0); + for (buf[4]) |elem| try expect(elem == 0); +} + test "memcpy and memset intrinsics" { if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; -- cgit v1.2.3 From a67dec1c9f86b5c74c91cd4fd3e7fe06c8440586 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 26 Apr 2023 18:11:57 -0700 Subject: disable not yet passing new behavior tests from this branch --- test/behavior/memset.zig | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) (limited to 'test') diff --git a/test/behavior/memset.zig b/test/behavior/memset.zig index 374fd4b6f5..67f7d7344d 100644 --- a/test/behavior/memset.zig +++ b/test/behavior/memset.zig @@ -72,6 +72,11 @@ fn testMemsetSlice() !void { } test "memset with bool element" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + var buf: [5]bool = undefined; @memset(&buf, true); try expect(buf[2]); @@ -79,6 +84,11 @@ test "memset with bool element" { } test "memset with 1-byte struct element" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + const S = struct { x: bool }; var buf: [5]S = undefined; @memset(&buf, .{ .x = true }); @@ -87,6 +97,11 @@ test "memset with 1-byte struct element" { } test "memset with 1-byte array element" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + const A = [1]bool; var buf: [5]A = undefined; @memset(&buf, .{true}); @@ -95,6 +110,11 @@ test "memset with 1-byte array element" { } test "memset with large array element, runtime known" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + const A = [128]u64; var buf: [5]A = undefined; var runtime_known_element = [_]u64{0} ** 128; @@ -107,6 +127,11 @@ test "memset with large array element, runtime known" { } test "memset with large array element, comptime known" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + const A = [128]u64; var buf: [5]A = undefined; const comptime_known_element = [_]u64{0} ** 128; -- cgit v1.2.3 From 73d3fb9883c1d89fd1460a18f186a1737613bfbc Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Thu, 27 Apr 2023 14:01:16 -0700 Subject: C backend: fix ptr comparison of array ptrs when one is null-terminated --- src/codegen/c.zig | 2 +- test/behavior.zig | 1 + test/behavior/memcpy.zig | 44 ++++++++++++++++++++++++++++++++++++++++++++ test/behavior/memset.zig | 21 --------------------- 4 files changed, 46 insertions(+), 22 deletions(-) create mode 100644 test/behavior/memcpy.zig (limited to 'test') diff --git a/src/codegen/c.zig b/src/codegen/c.zig index 27b04cee8e..a97d7c0b70 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -3858,7 +3858,7 @@ fn airCmpOp( try reap(f, inst, &.{ data.lhs, data.rhs }); const rhs_ty = f.air.typeOf(data.rhs); - const need_cast = lhs_ty.isSinglePointer() != rhs_ty.isSinglePointer(); + const need_cast = lhs_ty.isSinglePointer() or rhs_ty.isSinglePointer(); const writer = f.object.writer(); const local = try f.allocLocal(inst, inst_ty); const v = try Vectorize.start(f, inst, writer, lhs_ty); diff --git a/test/behavior.zig b/test/behavior.zig index c75e7bc788..70293bf45d 100644 --- a/test/behavior.zig +++ b/test/behavior.zig @@ -177,6 +177,7 @@ test { _ = @import("behavior/math.zig"); _ = @import("behavior/maximum_minimum.zig"); _ = @import("behavior/member_func.zig"); + _ = @import("behavior/memcpy.zig"); _ = @import("behavior/memset.zig"); _ = @import("behavior/merge_error_sets.zig"); _ = @import("behavior/muladd.zig"); diff --git a/test/behavior/memcpy.zig b/test/behavior/memcpy.zig new file mode 100644 index 0000000000..1d99a7163b --- /dev/null +++ b/test/behavior/memcpy.zig @@ -0,0 +1,44 @@ +const std = @import("std"); +const builtin = @import("builtin"); +const expect = std.testing.expect; + +test "memcpy and memset intrinsics" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO + + try testMemcpyMemset(); + try comptime testMemcpyMemset(); +} + +fn testMemcpyMemset() !void { + var foo: [20]u8 = undefined; + var bar: [20]u8 = undefined; + + @memset(&foo, 'A'); + @memcpy(&bar, &foo); + + try expect(bar[0] == 'A'); + try expect(bar[11] == 'A'); + try expect(bar[19] == 'A'); +} + +test "@memcpy with both operands single-ptr-to-array, one is null-terminated" { + if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; + + try testMemcpyBothSinglePtrArrayOneIsNullTerminated(); + try comptime testMemcpyBothSinglePtrArrayOneIsNullTerminated(); +} + +fn testMemcpyBothSinglePtrArrayOneIsNullTerminated() !void { + var buf: [100]u8 = undefined; + const suffix = "hello"; + @memcpy(buf[buf.len - suffix.len ..], suffix); + try expect(buf[95] == 'h'); + try expect(buf[96] == 'e'); + try expect(buf[97] == 'l'); + try expect(buf[98] == 'l'); + try expect(buf[99] == 'o'); +} diff --git a/test/behavior/memset.zig b/test/behavior/memset.zig index 67f7d7344d..89e01a0e56 100644 --- a/test/behavior/memset.zig +++ b/test/behavior/memset.zig @@ -142,24 +142,3 @@ test "memset with large array element, comptime known" { for (buf[3]) |elem| try expect(elem == 0); for (buf[4]) |elem| try expect(elem == 0); } - -test "memcpy and memset intrinsics" { - if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; - if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO - - try testMemcpyMemset(); - try comptime testMemcpyMemset(); -} - -fn testMemcpyMemset() !void { - var foo: [20]u8 = undefined; - var bar: [20]u8 = undefined; - - @memset(&foo, 'A'); - @memcpy(&bar, &foo); - - try expect(bar[0] == 'A'); - try expect(bar[11] == 'A'); - try expect(bar[19] == 'A'); -} -- cgit v1.2.3 From 85ffb8f18f10506d03ac7b0a68288c855b828a2e Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Fri, 28 Apr 2023 13:24:10 -0700 Subject: disable 2 failing behavior tests with x86 backend --- test/behavior/memset.zig | 2 ++ 1 file changed, 2 insertions(+) (limited to 'test') diff --git a/test/behavior/memset.zig b/test/behavior/memset.zig index 89e01a0e56..2cc390a3c9 100644 --- a/test/behavior/memset.zig +++ b/test/behavior/memset.zig @@ -114,6 +114,7 @@ test "memset with large array element, runtime known" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const A = [128]u64; var buf: [5]A = undefined; @@ -131,6 +132,7 @@ test "memset with large array element, comptime known" { if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; if (builtin.zig_backend == .stage2_wasm) return error.SkipZigTest; + if (builtin.zig_backend == .stage2_x86_64) return error.SkipZigTest; const A = [128]u64; var buf: [5]A = undefined; -- cgit v1.2.3