authorgravatar for robin@voetter.nlRobin Voetter <robin@voetter.nl> 2023-10-18 15:38:30+02:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-10-18 15:38:30+02:00
log24b065a6a87da68bdefe228bb7e1d148e69edbd8
tree7eb026648853ffb393402e7f3d5ba91b8a9aef45
parentaeadcb3918f7e6bc7abb08e70ffe3b3c25fb9c22
parent6d8a979265fd37d689541bd7df4014d065d00b81
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17561 from alichraghi/spirv-0

spirv: memcpy

3 files changed, 57 insertions(+), 20 deletions(-)

src/Sema.zig+6-6
...@@ -8441,7 +8441,7 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD...@@ -8441,7 +8441,7 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
8441 const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand);8441 const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand);
8442 const zero_val = Air.internedToRef((try mod.intValue(Type.err_int, 0)).toIntern());8442 const zero_val = Air.internedToRef((try mod.intValue(Type.err_int, 0)).toIntern());
8443 const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val);8443 const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val);
8444 const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero);8444 const ok = try block.addBinOp(.bool_and, is_lt_len, is_non_zero);
8445 try sema.addSafetyCheck(block, src, ok, .invalid_error_code);8445 try sema.addSafetyCheck(block, src, ok, .invalid_error_code);
8446 }8446 }
8447 return block.addInst(.{8447 return block.addInst(.{
...@@ -21914,7 +21914,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData...@@ -21914,7 +21914,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
21914 } else {21914 } else {
21915 // Error must be in destination set or zero.21915 // Error must be in destination set or zero.
21916 const has_value = try block.addTyOp(.error_set_has_value, dest_ty, err_code);21916 const has_value = try block.addTyOp(.error_set_has_value, dest_ty, err_code);
21917 const ok = try block.addBinOp(.bit_or, has_value, is_zero);21917 const ok = try block.addBinOp(.bool_or, has_value, is_zero);
21918 try sema.addSafetyCheck(block, src, ok, .invalid_error_code);21918 try sema.addSafetyCheck(block, src, ok, .invalid_error_code);
21919 }21919 }
21920 } else {21920 } else {
...@@ -22279,7 +22279,7 @@ fn ptrCastFull(...@@ -22279,7 +22279,7 @@ fn ptrCastFull(
22279 const ok = if (src_info.flags.size == .Slice and dest_info.flags.size == .Slice) ok: {22279 const ok = if (src_info.flags.size == .Slice and dest_info.flags.size == .Slice) ok: {
22280 const len = try sema.analyzeSliceLen(block, operand_src, ptr);22280 const len = try sema.analyzeSliceLen(block, operand_src, ptr);
22281 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);22281 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
22282 break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);22282 break :ok try block.addBinOp(.bool_or, len_zero, is_non_zero);
22283 } else is_non_zero;22283 } else is_non_zero;
22284 try sema.addSafetyCheck(block, src, ok, .cast_to_null);22284 try sema.addSafetyCheck(block, src, ok, .cast_to_null);
22285 }22285 }
...@@ -22296,7 +22296,7 @@ fn ptrCastFull(...@@ -22296,7 +22296,7 @@ fn ptrCastFull(
22296 const ok = if (src_info.flags.size == .Slice and dest_info.flags.size == .Slice) ok: {22296 const ok = if (src_info.flags.size == .Slice and dest_info.flags.size == .Slice) ok: {
22297 const len = try sema.analyzeSliceLen(block, operand_src, ptr);22297 const len = try sema.analyzeSliceLen(block, operand_src, ptr);
22298 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);22298 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
22299 break :ok try block.addBinOp(.bit_or, len_zero, is_aligned);22299 break :ok try block.addBinOp(.bool_or, len_zero, is_aligned);
22300 } else is_aligned;22300 } else is_aligned;
22301 try sema.addSafetyCheck(block, src, ok, .incorrect_alignment);22301 try sema.addSafetyCheck(block, src, ok, .incorrect_alignment);
22302 }22302 }
...@@ -24644,7 +24644,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -24644,7 +24644,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
24644 const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src);24644 const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src);
24645 const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len);24645 const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len);
24646 const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len);24646 const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len);
24647 const ok = try block.addBinOp(.bit_or, ok1, ok2);24647 const ok = try block.addBinOp(.bool_or, ok1, ok2);
24648 try sema.addSafetyCheck(block, src, ok, .memcpy_alias);24648 try sema.addSafetyCheck(block, src, ok, .memcpy_alias);
24649 }24649 }
2465024650
...@@ -30996,7 +30996,7 @@ fn coerceCompatiblePtrs(...@@ -30996,7 +30996,7 @@ fn coerceCompatiblePtrs(
30996 const ok = if (inst_ty.isSlice(mod)) ok: {30996 const ok = if (inst_ty.isSlice(mod)) ok: {
30997 const len = try sema.analyzeSliceLen(block, inst_src, inst);30997 const len = try sema.analyzeSliceLen(block, inst_src, inst);
30998 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);30998 const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
30999 break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);30999 break :ok try block.addBinOp(.bool_or, len_zero, is_non_zero);
31000 } else is_non_zero;31000 } else is_non_zero;
31001 try sema.addSafetyCheck(block, inst_src, ok, .cast_to_null);31001 try sema.addSafetyCheck(block, inst_src, ok, .cast_to_null);
31002 }31002 }
src/codegen/spirv.zig+42-1
...@@ -2012,6 +2012,7 @@ const DeclGen = struct {...@@ -2012,6 +2012,7 @@ const DeclGen = struct {
2012 .array_to_slice => try self.airArrayToSlice(inst),2012 .array_to_slice => try self.airArrayToSlice(inst),
2013 .slice => try self.airSlice(inst),2013 .slice => try self.airSlice(inst),
2014 .aggregate_init => try self.airAggregateInit(inst),2014 .aggregate_init => try self.airAggregateInit(inst),
2015 .memcpy => return self.airMemcpy(inst),
20152016
2016 .slice_ptr => try self.airSliceField(inst, 0),2017 .slice_ptr => try self.airSliceField(inst, 0),
2017 .slice_len => try self.airSliceField(inst, 1),2018 .slice_len => try self.airSliceField(inst, 1),
...@@ -2021,7 +2022,7 @@ const DeclGen = struct {...@@ -2021,7 +2022,7 @@ const DeclGen = struct {
2021 .ptr_elem_val => try self.airPtrElemVal(inst),2022 .ptr_elem_val => try self.airPtrElemVal(inst),
2022 .array_elem_val => try self.airArrayElemVal(inst),2023 .array_elem_val => try self.airArrayElemVal(inst),
20232024
2024 .set_union_tag => return try self.airSetUnionTag(inst),2025 .set_union_tag => return self.airSetUnionTag(inst),
2025 .get_union_tag => try self.airGetUnionTag(inst),2026 .get_union_tag => try self.airGetUnionTag(inst),
2026 .union_init => try self.airUnionInit(inst),2027 .union_init => try self.airUnionInit(inst),
20272028
...@@ -3159,6 +3160,46 @@ const DeclGen = struct {...@@ -3159,6 +3160,46 @@ const DeclGen = struct {
3159 }3160 }
3160 }3161 }
31613162
3163 fn sliceOrArrayLen(self: *DeclGen, operand_id: IdRef, ty: Type) !IdRef {
3164 const mod = self.module;
3165 switch (ty.ptrSize(mod)) {
3166 .Slice => return self.extractField(Type.usize, operand_id, 1),
3167 .One => {
3168 const array_ty = ty.childType(mod);
3169 const elem_ty = array_ty.childType(mod);
3170 const abi_size = elem_ty.abiSize(mod);
3171 const usize_ty_ref = try self.resolveType(Type.usize, .direct);
3172 return self.spv.constInt(usize_ty_ref, array_ty.arrayLenIncludingSentinel(mod) * abi_size);
3173 },
3174 .Many, .C => unreachable,
3175 }
3176 }
3177
3178 fn sliceOrArrayPtr(self: *DeclGen, operand_id: IdRef, ty: Type) !IdRef {
3179 const mod = self.module;
3180 if (ty.isSlice(mod)) {
3181 const ptr_ty = ty.slicePtrFieldType(mod);
3182 return self.extractField(ptr_ty, operand_id, 0);
3183 }
3184 return operand_id;
3185 }
3186
3187 fn airMemcpy(self: *DeclGen, inst: Air.Inst.Index) !void {
3188 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3189 const dest_slice = try self.resolve(bin_op.lhs);
3190 const src_slice = try self.resolve(bin_op.rhs);
3191 const dest_ty = self.typeOf(bin_op.lhs);
3192 const src_ty = self.typeOf(bin_op.rhs);
3193 const dest_ptr = try self.sliceOrArrayPtr(dest_slice, dest_ty);
3194 const src_ptr = try self.sliceOrArrayPtr(src_slice, src_ty);
3195 const len = try self.sliceOrArrayLen(dest_slice, dest_ty);
3196 try self.func.body.emit(self.spv.gpa, .OpCopyMemorySized, .{
3197 .target = dest_ptr,
3198 .source = src_ptr,
3199 .size = len,
3200 });
3201 }
3202
3162 fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef {3203 fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef {
3163 if (self.liveness.isUnused(inst)) return null;3204 if (self.liveness.isUnused(inst)) return null;
3164 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3205 const ty_op = self.air.instructions.items(.data)[inst].ty_op;
test/behavior/memcpy.zig+9-13
...@@ -28,7 +28,6 @@ test "@memcpy with both operands single-ptr-to-array, one is null-terminated" {...@@ -28,7 +28,6 @@ test "@memcpy with both operands single-ptr-to-array, one is null-terminated" {
28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;28 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
29 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;29 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
30 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;30 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
31 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
3231
33 try testMemcpyBothSinglePtrArrayOneIsNullTerminated();32 try testMemcpyBothSinglePtrArrayOneIsNullTerminated();
34 try comptime testMemcpyBothSinglePtrArrayOneIsNullTerminated();33 try comptime testMemcpyBothSinglePtrArrayOneIsNullTerminated();
...@@ -49,7 +48,6 @@ test "@memcpy dest many pointer" {...@@ -49,7 +48,6 @@ test "@memcpy dest many pointer" {
49 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;48 if (builtin.zig_backend == .stage2_aarch64) return error.SkipZigTest;
50 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;49 if (builtin.zig_backend == .stage2_arm) return error.SkipZigTest;
51 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;50 if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest;
52 if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest;
5351
54 try testMemcpyDestManyPtr();52 try testMemcpyDestManyPtr();
55 try comptime testMemcpyDestManyPtr();53 try comptime testMemcpyDestManyPtr();
...@@ -68,16 +66,14 @@ fn testMemcpyDestManyPtr() !void {...@@ -68,16 +66,14 @@ fn testMemcpyDestManyPtr() !void {
68}66}
6967
70comptime {68comptime {
71 if (builtin.zig_backend != .stage2_spirv64) {69 const S = struct {
72 const S = struct {70 buffer: [8]u8 = undefined,
73 buffer: [8]u8 = undefined,71 fn set(self: *@This(), items: []const u8) void {
74 fn set(self: *@This(), items: []const u8) void {72 @memcpy(self.buffer[0..items.len], items);
75 @memcpy(self.buffer[0..items.len], items);73 }
76 }74 };
77 };
7875
79 var s = S{};76 var s = S{};
80 s.set("hello");77 s.set("hello");
81 if (!std.mem.eql(u8, s.buffer[0..5], "hello")) @compileError("bad");78 if (!std.mem.eql(u8, s.buffer[0..5], "hello")) @compileError("bad");
82 }
83}79}