diff options
| author | Robin Voetter <robin@voetter.nl> | 2023-10-18 15:38:30 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2023-10-18 15:38:30 +0200 |
| commit | 24b065a6a87da68bdefe228bb7e1d148e69edbd8 (patch) | |
| tree | 7eb026648853ffb393402e7f3d5ba91b8a9aef45 | |
| parent | aeadcb3918f7e6bc7abb08e70ffe3b3c25fb9c22 (diff) | |
| parent | 6d8a979265fd37d689541bd7df4014d065d00b81 (diff) | |
| download | zig-24b065a6a87da68bdefe228bb7e1d148e69edbd8.tar.gz zig-24b065a6a87da68bdefe228bb7e1d148e69edbd8.zip | |
Merge pull request #17561 from alichraghi/spirv-0
spirv: memcpy
| -rw-r--r-- | src/Sema.zig | 12 | ||||
| -rw-r--r-- | src/codegen/spirv.zig | 43 | ||||
| -rw-r--r-- | test/behavior/memcpy.zig | 22 |
3 files changed, 57 insertions, 20 deletions
diff --git a/src/Sema.zig b/src/Sema.zig index f084020f95..2f861a87e6 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -8441,7 +8441,7 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand); const zero_val = Air.internedToRef((try mod.intValue(Type.err_int, 0)).toIntern()); const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val); - const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero); + const ok = try block.addBinOp(.bool_and, is_lt_len, is_non_zero); try sema.addSafetyCheck(block, src, ok, .invalid_error_code); } return block.addInst(.{ @@ -21914,7 +21914,7 @@ fn zirErrorCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData } else { // Error must be in destination set or zero. const has_value = try block.addTyOp(.error_set_has_value, dest_ty, err_code); - const ok = try block.addBinOp(.bit_or, has_value, is_zero); + const ok = try block.addBinOp(.bool_or, has_value, is_zero); try sema.addSafetyCheck(block, src, ok, .invalid_error_code); } } else { @@ -22279,7 +22279,7 @@ fn ptrCastFull( const ok = if (src_info.flags.size == .Slice and dest_info.flags.size == .Slice) ok: { const len = try sema.analyzeSliceLen(block, operand_src, ptr); const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); - break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero); + break :ok try block.addBinOp(.bool_or, len_zero, is_non_zero); } else is_non_zero; try sema.addSafetyCheck(block, src, ok, .cast_to_null); } @@ -22296,7 +22296,7 @@ fn ptrCastFull( const ok = if (src_info.flags.size == .Slice and dest_info.flags.size == .Slice) ok: { const len = try sema.analyzeSliceLen(block, operand_src, ptr); const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); - break :ok try block.addBinOp(.bit_or, len_zero, is_aligned); + break :ok try block.addBinOp(.bool_or, len_zero, is_aligned); } else is_aligned; try sema.addSafetyCheck(block, src, ok, .incorrect_alignment); } @@ -24644,7 +24644,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src); const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len); const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len); - const ok = try block.addBinOp(.bit_or, ok1, ok2); + const ok = try block.addBinOp(.bool_or, ok1, ok2); try sema.addSafetyCheck(block, src, ok, .memcpy_alias); } @@ -30996,7 +30996,7 @@ fn coerceCompatiblePtrs( const ok = if (inst_ty.isSlice(mod)) ok: { const len = try sema.analyzeSliceLen(block, inst_src, inst); const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize); - break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero); + break :ok try block.addBinOp(.bool_or, len_zero, is_non_zero); } else is_non_zero; try sema.addSafetyCheck(block, inst_src, ok, .cast_to_null); } diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 2c9018463d..7ee281c466 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -2012,6 +2012,7 @@ const DeclGen = struct { .array_to_slice => try self.airArrayToSlice(inst), .slice => try self.airSlice(inst), .aggregate_init => try self.airAggregateInit(inst), + .memcpy => return self.airMemcpy(inst), .slice_ptr => try self.airSliceField(inst, 0), .slice_len => try self.airSliceField(inst, 1), @@ -2021,7 +2022,7 @@ const DeclGen = struct { .ptr_elem_val => try self.airPtrElemVal(inst), .array_elem_val => try self.airArrayElemVal(inst), - .set_union_tag => return try self.airSetUnionTag(inst), + .set_union_tag => return self.airSetUnionTag(inst), .get_union_tag => try self.airGetUnionTag(inst), .union_init => try self.airUnionInit(inst), @@ -3159,6 +3160,46 @@ const DeclGen = struct { } } + fn sliceOrArrayLen(self: *DeclGen, operand_id: IdRef, ty: Type) !IdRef { + const mod = self.module; + switch (ty.ptrSize(mod)) { + .Slice => return self.extractField(Type.usize, operand_id, 1), + .One => { + const array_ty = ty.childType(mod); + const elem_ty = array_ty.childType(mod); + const abi_size = elem_ty.abiSize(mod); + const usize_ty_ref = try self.resolveType(Type.usize, .direct); + return self.spv.constInt(usize_ty_ref, array_ty.arrayLenIncludingSentinel(mod) * abi_size); + }, + .Many, .C => unreachable, + } + } + + fn sliceOrArrayPtr(self: *DeclGen, operand_id: IdRef, ty: Type) !IdRef { + const mod = self.module; + if (ty.isSlice(mod)) { + const ptr_ty = ty.slicePtrFieldType(mod); + return self.extractField(ptr_ty, operand_id, 0); + } + return operand_id; + } + + fn airMemcpy(self: *DeclGen, inst: Air.Inst.Index) !void { + const bin_op = self.air.instructions.items(.data)[inst].bin_op; + const dest_slice = try self.resolve(bin_op.lhs); + const src_slice = try self.resolve(bin_op.rhs); + const dest_ty = self.typeOf(bin_op.lhs); + const src_ty = self.typeOf(bin_op.rhs); + const dest_ptr = try self.sliceOrArrayPtr(dest_slice, dest_ty); + const src_ptr = try self.sliceOrArrayPtr(src_slice, src_ty); + const len = try self.sliceOrArrayLen(dest_slice, dest_ty); + try self.func.body.emit(self.spv.gpa, .OpCopyMemorySized, .{ + .target = dest_ptr, + .source = src_ptr, + .size = len, + }); + } + fn airSliceField(self: *DeclGen, inst: Air.Inst.Index, field: u32) !?IdRef { if (self.liveness.isUnused(inst)) return null; const ty_op = self.air.instructions.items(.data)[inst].ty_op; diff --git a/test/behavior/memcpy.zig b/test/behavior/memcpy.zig index f1776dfe57..8d9880ccb0 100644 --- a/test/behavior/memcpy.zig +++ b/test/behavior/memcpy.zig @@ -28,7 +28,6 @@ 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; - if (builtin.zig_backend == .stage2_spirv64) return error.SkipZigTest; try testMemcpyBothSinglePtrArrayOneIsNullTerminated(); try comptime testMemcpyBothSinglePtrArrayOneIsNullTerminated(); @@ -49,7 +48,6 @@ test "@memcpy dest many pointer" { 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_spirv64) return error.SkipZigTest; try testMemcpyDestManyPtr(); try comptime testMemcpyDestManyPtr(); @@ -68,16 +66,14 @@ fn testMemcpyDestManyPtr() !void { } comptime { - if (builtin.zig_backend != .stage2_spirv64) { - const S = struct { - buffer: [8]u8 = undefined, - fn set(self: *@This(), items: []const u8) void { - @memcpy(self.buffer[0..items.len], items); - } - }; + const S = struct { + buffer: [8]u8 = undefined, + fn set(self: *@This(), items: []const u8) void { + @memcpy(self.buffer[0..items.len], items); + } + }; - var s = S{}; - s.set("hello"); - if (!std.mem.eql(u8, s.buffer[0..5], "hello")) @compileError("bad"); - } + var s = S{}; + s.set("hello"); + if (!std.mem.eql(u8, s.buffer[0..5], "hello")) @compileError("bad"); } |
