From 3e30ba3f20dce2d406253de3fc0eb86934a3eaa7 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 7 Jun 2022 20:51:14 -0700 Subject: stage2: better codegen for byte-aligned packed struct fields * Sema: handle overaligned packed struct field pointers * LLVM: handle byte-aligned packed struct field pointers --- src/codegen/llvm.zig | 40 +++++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 11 deletions(-) (limited to 'src/codegen/llvm.zig') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index dcdf4888ea..188c2f6f11 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -8311,23 +8311,41 @@ pub const FuncGen = struct { field_index: u32, ) !?*const llvm.Value { if (self.liveness.isUnused(inst)) return null; + + const target = self.dg.object.target; const struct_ty = struct_ptr_ty.childType(); switch (struct_ty.zigTypeTag()) { .Struct => switch (struct_ty.containerLayout()) { .Packed => { - // From LLVM's perspective, a pointer to a packed struct and a pointer - // to a field of a packed struct are the same. The difference is in the - // Zig pointer type which provides information for how to mask and shift - // out the relevant bits when accessing the pointee. - // Here we perform a bitcast because we want to use the host_size - // as the llvm pointer element type. - const result_llvm_ty = try self.dg.lowerType(self.air.typeOfIndex(inst)); - // TODO this can be removed if we change host_size to be bits instead - // of bytes. - return self.builder.buildBitCast(struct_ptr, result_llvm_ty, ""); + const result_ty = self.air.typeOfIndex(inst); + const result_ty_info = result_ty.ptrInfo().data; + const result_llvm_ty = try self.dg.lowerType(result_ty); + + if (result_ty_info.host_size != 0) { + // From LLVM's perspective, a pointer to a packed struct and a pointer + // to a field of a packed struct are the same. The difference is in the + // Zig pointer type which provides information for how to mask and shift + // out the relevant bits when accessing the pointee. + // Here we perform a bitcast because we want to use the host_size + // as the llvm pointer element type. + return self.builder.buildBitCast(struct_ptr, result_llvm_ty, ""); + } + + // We have a pointer to a packed struct field that happens to be byte-aligned. + // Offset our operand pointer by the correct number of bytes. + const byte_offset = struct_ty.packedStructFieldByteOffset(field_index, target); + if (byte_offset == 0) { + return self.builder.buildBitCast(struct_ptr, result_llvm_ty, ""); + } + const llvm_bytes_ptr_ty = self.context.intType(8).pointerType(0); + const ptr_as_bytes = self.builder.buildBitCast(struct_ptr, llvm_bytes_ptr_ty, ""); + const llvm_usize = try self.dg.lowerType(Type.usize); + const llvm_index = llvm_usize.constInt(byte_offset, .False); + const indices: [1]*const llvm.Value = .{llvm_index}; + const new_ptr = self.builder.buildInBoundsGEP(ptr_as_bytes, &indices, indices.len, ""); + return self.builder.buildBitCast(new_ptr, result_llvm_ty, ""); }, else => { - const target = self.dg.module.getTarget(); var ty_buf: Type.Payload.Pointer = undefined; if (llvmFieldIndex(struct_ty, field_index, target, &ty_buf)) |llvm_field_index| { return self.builder.buildStructGEP(struct_ptr, llvm_field_index, ""); -- cgit v1.2.3