| author | |
| committer | |
| log | 792bbfa301436fc0ce31bc4072b4765ba1408a55 |
| tree | 4e249d92a5ab600e4ba67893e10ce392b7e506cb |
| parent | 5378fdffdcc60a5273021bc9cfc5be917e87c992 |
Previously it was not multiplying by the element ABI size. Now, it uses
ptr_add instructions which do math based on the element type.4 files changed, 58 insertions(+), 27 deletions(-)
lib/std/os.zig+1-1| ... | @@ -5548,7 +5548,7 @@ pub fn toPosixPath(file_path: []const u8) ![MAX_PATH_BYTES - 1:0]u8 { | ... | @@ -5548,7 +5548,7 @@ pub fn toPosixPath(file_path: []const u8) ![MAX_PATH_BYTES - 1:0]u8 { |
| 5548 | var path_with_null: [MAX_PATH_BYTES - 1:0]u8 = undefined; | 5548 | var path_with_null: [MAX_PATH_BYTES - 1:0]u8 = undefined; |
| 5549 | // >= rather than > to make room for the null byte | 5549 | // >= rather than > to make room for the null byte |
| 5550 | if (file_path.len >= MAX_PATH_BYTES) return error.NameTooLong; | 5550 | if (file_path.len >= MAX_PATH_BYTES) return error.NameTooLong; |
| 5551 | mem.copy(u8, &path_with_null, file_path); | 5551 | @memcpy(path_with_null[0..file_path.len], file_path); |
| 5552 | path_with_null[file_path.len] = 0; | 5552 | path_with_null[file_path.len] = 0; |
| 5553 | return path_with_null; | 5553 | return path_with_null; |
| 5554 | } | 5554 | } |
src/Air.zig+2| ... | @@ -138,12 +138,14 @@ pub const Inst = struct { | ... | @@ -138,12 +138,14 @@ pub const Inst = struct { |
| 138 | /// The offset is in element type units, not bytes. | 138 | /// The offset is in element type units, not bytes. |
| 139 | /// Wrapping is undefined behavior. | 139 | /// Wrapping is undefined behavior. |
| 140 | /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs. | 140 | /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs. |
| 141 | /// The pointer may be a slice. | ||
| 141 | /// Uses the `ty_pl` field. Payload is `Bin`. | 142 | /// Uses the `ty_pl` field. Payload is `Bin`. |
| 142 | ptr_add, | 143 | ptr_add, |
| 143 | /// Subtract an offset from a pointer, returning a new pointer. | 144 | /// Subtract an offset from a pointer, returning a new pointer. |
| 144 | /// The offset is in element type units, not bytes. | 145 | /// The offset is in element type units, not bytes. |
| 145 | /// Wrapping is undefined behavior. | 146 | /// Wrapping is undefined behavior. |
| 146 | /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs. | 147 | /// The lhs is the pointer, rhs is the offset. Result type is the same as lhs. |
| 148 | /// The pointer may be a slice. | ||
| 147 | /// Uses the `ty_pl` field. Payload is `Bin`. | 149 | /// Uses the `ty_pl` field. Payload is `Bin`. |
| 148 | ptr_sub, | 150 | ptr_sub, |
| 149 | /// Given two operands which can be floats, integers, or vectors, returns the | 151 | /// Given two operands which can be floats, integers, or vectors, returns the |
src/Sema.zig+21-6| ... | @@ -21950,12 +21950,19 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -21950,12 +21950,19 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 21950 | new_src_ptr = try upgradeToArrayPtr(sema, block, src_ptr, len); | 21950 | new_src_ptr = try upgradeToArrayPtr(sema, block, src_ptr, len); |
| 21951 | } | 21951 | } |
| 21952 | 21952 | ||
| 21953 | if (dest_len != .none) { | ||
| 21954 | // Change the src from slice to a many pointer, to avoid multiple ptr | ||
| 21955 | // slice extractions in AIR instructions. | ||
| 21956 | const new_src_ptr_ty = sema.typeOf(new_src_ptr); | ||
| 21957 | if (new_src_ptr_ty.isSlice()) { | ||
| 21958 | new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty); | ||
| 21959 | } | ||
| 21960 | } | ||
| 21961 | |||
| 21953 | try sema.requireRuntimeBlock(block, src, runtime_src); | 21962 | try sema.requireRuntimeBlock(block, src, runtime_src); |
| 21954 | 21963 | ||
| 21955 | // Aliasing safety check. | 21964 | // Aliasing safety check. |
| 21956 | if (block.wantSafety()) { | 21965 | if (block.wantSafety()) { |
| 21957 | const dest_int = try block.addUnOp(.ptrtoint, new_dest_ptr); | ||
| 21958 | const src_int = try block.addUnOp(.ptrtoint, new_src_ptr); | ||
| 21959 | const len = if (len_val) |v| | 21966 | const len = if (len_val) |v| |
| 21960 | try sema.addConstant(Type.usize, v) | 21967 | try sema.addConstant(Type.usize, v) |
| 21961 | else if (dest_len != .none) | 21968 | else if (dest_len != .none) |
| ... | @@ -21963,12 +21970,20 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -21963,12 +21970,20 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 21963 | else | 21970 | else |
| 21964 | src_len; | 21971 | src_len; |
| 21965 | 21972 | ||
| 21973 | // Extract raw pointer from dest slice. The AIR instructions could support them, but | ||
| 21974 | // it would cause redundant machine code instructions. | ||
| 21975 | const new_dest_ptr_ty = sema.typeOf(new_dest_ptr); | ||
| 21976 | const raw_dest_ptr = if (new_dest_ptr_ty.isSlice()) | ||
| 21977 | try sema.analyzeSlicePtr(block, dest_src, new_dest_ptr, new_dest_ptr_ty) | ||
| 21978 | else | ||
| 21979 | new_dest_ptr; | ||
| 21980 | |||
| 21966 | // ok1: dest >= src + len | 21981 | // ok1: dest >= src + len |
| 21967 | // ok2: src >= dest + len | 21982 | // ok2: src >= dest + len |
| 21968 | const src_plus_len = try block.addBinOp(.add, src_int, len); | 21983 | const src_plus_len = try sema.analyzePtrArithmetic(block, src, new_src_ptr, len, .ptr_add, src_src, src); |
| 21969 | const dest_plus_len = try block.addBinOp(.add, dest_int, len); | 21984 | const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src); |
| 21970 | const ok1 = try block.addBinOp(.cmp_gte, dest_int, src_plus_len); | 21985 | const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len); |
| 21971 | const ok2 = try block.addBinOp(.cmp_gte, src_int, dest_plus_len); | 21986 | const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len); |
| 21972 | const ok = try block.addBinOp(.bit_or, ok1, ok2); | 21987 | const ok = try block.addBinOp(.bit_or, ok1, ok2); |
| 21973 | try sema.addSafetyCheck(block, ok, .memcpy_alias); | 21988 | try sema.addSafetyCheck(block, ok, .memcpy_alias); |
| 21974 | } | 21989 | } |
src/codegen/llvm.zig+34-20| ... | @@ -7293,39 +7293,53 @@ pub const FuncGen = struct { | ... | @@ -7293,39 +7293,53 @@ pub const FuncGen = struct { |
| 7293 | fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7293 | fn airPtrAdd(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7294 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 7294 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 7295 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 7295 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 7296 | const base_ptr = try self.resolveInst(bin_op.lhs); | 7296 | const ptr = try self.resolveInst(bin_op.lhs); |
| 7297 | const offset = try self.resolveInst(bin_op.rhs); | 7297 | const offset = try self.resolveInst(bin_op.rhs); |
| 7298 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 7298 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 7299 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType()); | 7299 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType()); |
| 7300 | if (ptr_ty.ptrSize() == .One) { | 7300 | switch (ptr_ty.ptrSize()) { |
| 7301 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. | 7301 | .One => { |
| 7302 | const indices: [2]*llvm.Value = .{ | 7302 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. |
| 7303 | self.context.intType(32).constNull(), offset, | 7303 | const indices: [2]*llvm.Value = .{ self.context.intType(32).constNull(), offset }; |
| 7304 | }; | 7304 | return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); |
| 7305 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); | 7305 | }, |
| 7306 | } else { | 7306 | .C, .Many => { |
| 7307 | const indices: [1]*llvm.Value = .{offset}; | 7307 | const indices: [1]*llvm.Value = .{offset}; |
| 7308 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); | 7308 | return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); |
| 7309 | }, | ||
| 7310 | .Slice => { | ||
| 7311 | const base = self.builder.buildExtractValue(ptr, 0, ""); | ||
| 7312 | const indices: [1]*llvm.Value = .{offset}; | ||
| 7313 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, ""); | ||
| 7314 | }, | ||
| 7309 | } | 7315 | } |
| 7310 | } | 7316 | } |
| 7311 | 7317 | ||
| 7312 | fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { | 7318 | fn airPtrSub(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value { |
| 7313 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; | 7319 | const ty_pl = self.air.instructions.items(.data)[inst].ty_pl; |
| 7314 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; | 7320 | const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data; |
| 7315 | const base_ptr = try self.resolveInst(bin_op.lhs); | 7321 | const ptr = try self.resolveInst(bin_op.lhs); |
| 7316 | const offset = try self.resolveInst(bin_op.rhs); | 7322 | const offset = try self.resolveInst(bin_op.rhs); |
| 7317 | const negative_offset = self.builder.buildNeg(offset, ""); | 7323 | const negative_offset = self.builder.buildNeg(offset, ""); |
| 7318 | const ptr_ty = self.air.typeOf(bin_op.lhs); | 7324 | const ptr_ty = self.air.typeOf(bin_op.lhs); |
| 7319 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType()); | 7325 | const llvm_elem_ty = try self.dg.lowerPtrElemTy(ptr_ty.childType()); |
| 7320 | if (ptr_ty.ptrSize() == .One) { | 7326 | switch (ptr_ty.ptrSize()) { |
| 7321 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. | 7327 | .One => { |
| 7322 | const indices: [2]*llvm.Value = .{ | 7328 | // It's a pointer to an array, so according to LLVM we need an extra GEP index. |
| 7323 | self.context.intType(32).constNull(), negative_offset, | 7329 | const indices: [2]*llvm.Value = .{ |
| 7324 | }; | 7330 | self.context.intType(32).constNull(), negative_offset, |
| 7325 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); | 7331 | }; |
| 7326 | } else { | 7332 | return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); |
| 7327 | const indices: [1]*llvm.Value = .{negative_offset}; | 7333 | }, |
| 7328 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, ""); | 7334 | .C, .Many => { |
| 7335 | const indices: [1]*llvm.Value = .{negative_offset}; | ||
| 7336 | return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, ""); | ||
| 7337 | }, | ||
| 7338 | .Slice => { | ||
| 7339 | const base = self.builder.buildExtractValue(ptr, 0, ""); | ||
| 7340 | const indices: [1]*llvm.Value = .{negative_offset}; | ||
| 7341 | return self.builder.buildInBoundsGEP(llvm_elem_ty, base, &indices, indices.len, ""); | ||
| 7342 | }, | ||
| 7329 | } | 7343 | } |
| 7330 | } | 7344 | } |
| 7331 | 7345 |