diff --git a/lib/std/os.zig b/lib/std/os.zig index a1fecd8501..5f4619613f 100644 --- a/lib/std/os.zig +++ b/lib/std/os.zig @@ -5548,7 +5548,7 @@ pub fn toPosixPath(file_path: []const u8) ![MAX_PATH_BYTES - 1:0]u8 { var path_with_null: [MAX_PATH_BYTES - 1:0]u8 = undefined; // >= rather than > to make room for the null byte if (file_path.len >= MAX_PATH_BYTES) return error.NameTooLong; - mem.copy(u8, &path_with_null, file_path); + @memcpy(path_with_null[0..file_path.len], file_path); path_with_null[file_path.len] = 0; return path_with_null; } diff --git a/src/Air.zig b/src/Air.zig index a2b8b9bc01..7ee36206f1 100644 --- a/src/Air.zig +++ b/src/Air.zig @@ -138,12 +138,14 @@ pub const Inst = struct { /// The offset is in element type units, not bytes. /// Wrapping is undefined behavior. /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs. + /// The pointer may be a slice. /// Uses the `ty_pl` field. Payload is `Bin`. ptr_add, /// Subtract an offset from a pointer, returning a new pointer. /// The offset is in element type units, not bytes. /// Wrapping is undefined behavior. /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs. + /// The pointer may be a slice. /// Uses the `ty_pl` field. Payload is `Bin`. ptr_sub, /// Given two operands which can be floats, integers, or vectors, returns the diff --git a/src/Sema.zig b/src/Sema.zig index 404bbd30a5..2c505561c9 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -21950,12 +21950,19 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void new_src_ptr = try upgradeToArrayPtr(sema, block, src_ptr, len); } + if (dest_len != .none) { + // Change the src from slice to a many pointer, to avoid multiple ptr + // slice extractions in AIR instructions. + const new_src_ptr_ty = sema.typeOf(new_src_ptr); + if (new_src_ptr_ty.isSlice()) { + new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty); + } + } + try sema.requireRuntimeBlock(block, src, runtime_src); // Aliasing safety check. if (block.wantSafety()) { - const dest_int = try block.addUnOp(.ptrtoint, new_dest_ptr); - const src_int = try block.addUnOp(.ptrtoint, new_src_ptr); const len = if (len_val) |v| try sema.addConstant(Type.usize, v) else if (dest_len != .none) @@ -21963,12 +21970,20 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void else src_len; + // Extract raw pointer from dest slice. The AIR instructions could support them, but + // it would cause redundant machine code instructions. + const new_dest_ptr_ty = sema.typeOf(new_dest_ptr); + const raw_dest_ptr = if (new_dest_ptr_ty.isSlice()) + try sema.analyzeSlicePtr(block, dest_src, new_dest_ptr, new_dest_ptr_ty) + else + new_dest_ptr; + // ok1: dest >= src + len // ok2: src >= dest + len - const src_plus_len = try block.addBinOp(.add, src_int, len); - const dest_plus_len = try block.addBinOp(.add, dest_int, len); - const ok1 = try block.addBinOp(.cmp_gte, dest_int, src_plus_len); - const ok2 = try block.addBinOp(.cmp_gte, src_int, dest_plus_len); + const src_plus_len = try sema.analyzePtrArithmetic(block, src, new_src_ptr, len, .ptr_add, src_src, src); + 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); try sema.addSafetyCheck(block, ok, .memcpy_alias); } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index ac105606e8..94f49e801d 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -7293,39 +7293,53 @@ pub const FuncGen = struct { fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; - const base_ptr = try self.resolveInst(bin_op.lhs); + const ptr = try self.resolveInst(bin_op.lhs); const offset = try self.resolveInst(bin_op.rhs); const ptr_ty = self.air.typeOf(bin_op.lhs); const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType()); - if (ptr_ty.ptrSize() == .One) { - // It's a pointer to an array, so according to LLVM we need an extra GEP index. - const indices: [2]*llvm.Value = .{ - self.context.intType(32).constNull(), offset, - }; - return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); - } else { - const indices: [1]*llvm.Value = .{offset}; - return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); + switch (ptr_ty.ptrSize()) { + .One => { + // It's a pointer to an array, so according to LLVM we need an extra GEP index. + const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), offset }; + return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); + }, + .C, .Many => { + const indices: [1]*llvm.Value = .{offset}; + return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); + }, + .Slice => { + const base = self.builder.buildExtractValue(ptr, 0, ""); + const indices: [1]*llvm.Value = .{offset}; + return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, ""); + }, } } fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; - const base_ptr = try self.resolveInst(bin_op.lhs); + const ptr = try self.resolveInst(bin_op.lhs); const offset = try self.resolveInst(bin_op.rhs); const negative_offset = self.builder.buildNeg(offset, ""); const ptr_ty = self.air.typeOf(bin_op.lhs); const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType()); - if (ptr_ty.ptrSize() == .One) { - // It's a pointer to an array, so according to LLVM we need an extra GEP index. - const indices: [2]*llvm.Value = .{ - self.context.intType(32).constNull(), negative_offset, - }; - return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); - } else { - const indices: [1]*llvm.Value = .{negative_offset}; - return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); + switch (ptr_ty.ptrSize()) { + .One => { + // It's a pointer to an array, so according to LLVM we need an extra GEP index. + const indices: [2]*llvm.Value = .{ + self.context.intType(32).constNull(), negative_offset, + }; + return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); + }, + .C, .Many => { + const indices: [1]*llvm.Value = .{negative_offset}; + return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); + }, + .Slice => { + const base = self.builder.buildExtractValue(ptr, 0, ""); + const indices: [1]*llvm.Value = .{negative_offset}; + return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, ""); + }, } }