authorgravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2023-10-17 02:52:57+03:30
committergravatar for alichraghi@proton.meAli Chraghi <alichraghi@proton.me> 2023-10-17 13:02:30+03:30
log6d8a979265fd37d689541bd7df4014d065d00b81
treebb4f9e8ee9dec8c34f0ec2d0e4935cd003c1931a
parent2d762a76a4e2d3d9e96e038406de31fa44661ad1

spirv: memcpy


2 files changed, 51 insertions(+), 14 deletions(-)

src/codegen/spirv.zig+42-1
...@@ -2007,6 +2007,7 @@ const DeclGen = struct {...@@ -2007,6 +2007,7 @@ const DeclGen = struct {
2007 .array_to_slice => try self.airArrayToSlice(inst),2007 .array_to_slice => try self.airArrayToSlice(inst),
2008 .slice => try self.airSlice(inst),2008 .slice => try self.airSlice(inst),
2009 .aggregate_init => try self.airAggregateInit(inst),2009 .aggregate_init => try self.airAggregateInit(inst),
2010 .memcpy => return self.airMemcpy(inst),
20102011
2011 .slice_ptr => try self.airSliceField(inst, 0),2012 .slice_ptr => try self.airSliceField(inst, 0),
2012 .slice_len => try self.airSliceField(inst, 1),2013 .slice_len => try self.airSliceField(inst, 1),
...@@ -2016,7 +2017,7 @@ const DeclGen = struct {...@@ -2016,7 +2017,7 @@ const DeclGen = struct {
2016 .ptr_elem_val => try self.airPtrElemVal(inst),2017 .ptr_elem_val => try self.airPtrElemVal(inst),
2017 .array_elem_val => try self.airArrayElemVal(inst),2018 .array_elem_val => try self.airArrayElemVal(inst),
20182019
2019 .set_union_tag => return try self.airSetUnionTag(inst),2020 .set_union_tag => return self.airSetUnionTag(inst),
2020 .get_union_tag => try self.airGetUnionTag(inst),2021 .get_union_tag => try self.airGetUnionTag(inst),
2021 .union_init => try self.airUnionInit(inst),2022 .union_init => try self.airUnionInit(inst),
20222023
...@@ -3150,6 +3151,46 @@ const DeclGen = struct {...@@ -3150,6 +3151,46 @@ const DeclGen = struct {
3150 }3151 }
3151 }3152 }
31523153
3154 fn sliceOrArrayLen(self: *DeclGen, operand_id: IdRef, ty: Type) !IdRef {
3155 const mod = self.module;
3156 switch (ty.ptrSize(mod)) {
3157 .Slice => return self.extractField(Type.usize, operand_id, 1),
3158 .One => {
3159 const array_ty = ty.childType(mod);
3160 const elem_ty = array_ty.childType(mod);
3161 const abi_size = elem_ty.abiSize(mod);
3162 const usize_ty_ref = try self.resolveType(Type.usize, .direct);
3163 return self.spv.constInt(usize_ty_ref, array_ty.arrayLenIncludingSentinel(mod) * abi_size);
3164 },
3165 .Many, .C => unreachable,
3166 }
3167 }
3168
3169 fn sliceOrArrayPtr(self: *DeclGen, operand_id: IdRef, ty: Type) !IdRef {
3170 const mod = self.module;
3171 if (ty.isSlice(mod)) {
3172 const ptr_ty = ty.slicePtrFieldType(mod);
3173 return self.extractField(ptr_ty, operand_id, 0);
3174 }
3175 return operand_id;
3176 }
3177
3178 fn airMemcpy(self: *DeclGen, inst: Air.Inst.Index) !void {
3179 const bin_op = self.air.instructions.items(.data)[inst].bin_op;
3180 const dest_slice = try self.resolve(bin_op.lhs);
3181 const src_slice = try self.resolve(bin_op.rhs);
3182 const dest_ty = self.typeOf(bin_op.lhs);
3183 const src_ty = self.typeOf(bin_op.rhs);
3184 const dest_ptr = try self.sliceOrArrayPtr(dest_slice, dest_ty);
3185 const src_ptr = try self.sliceOrArrayPtr(src_slice, src_ty);
3186 const len = try self.sliceOrArrayLen(dest_slice, dest_ty);
3187 try self.func.body.emit(self.spv.gpa, .OpCopyMemorySized, .{
3188 .target = dest_ptr,
3189 .source = src_ptr,
3190 .size = len,
3191 });
3192 }
3193
3153 fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef {3194 fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef {
3154 if (self.liveness.isUnused(inst)) return null;3195 if (self.liveness.isUnused(inst)) return null;
3155 const ty_op = self.air.instructions.items(.data)[inst].ty_op;3196 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}