| author | |
| committer | |
| log | 24b065a6a87da68bdefe228bb7e1d148e69edbd8 |
| tree | 7eb026648853ffb393402e7f3d5ba91b8a9aef45 |
| parent | aeadcb3918f7e6bc7abb08e70ffe3b3c25fb9c22 |
| parent | 6d8a979265fd37d689541bd7df4014d065d00b81 |
| signature |
spirv: memcpy3 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 | } |
| 24650 | 24650 | ||
| ... | @@ -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), | ||
| 2015 | 2016 | ||
| 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), |
| 2023 | 2024 | ||
| 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), |
| 2027 | 2028 | ||
| ... | @@ -3159,6 +3160,46 @@ const DeclGen = struct { | ... | @@ -3159,6 +3160,46 @@ const DeclGen = struct { |
| 3159 | } | 3160 | } |
| 3160 | } | 3161 | } |
| 3161 | 3162 | ||
| 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; | ||
| 32 | 31 | ||
| 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; | ||
| 53 | 51 | ||
| 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 | } |
| 69 | 67 | ||
| 70 | comptime { | 68 | comptime { |
| 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 | }; | ||
| 78 | 75 | ||
| 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 | } |