authorgravatar for jhc@dismail.deJimmi Holst Christensen <jhc@dismail.de> 2022-01-07 19:02:24+01:00
committergravatar for jhc@dismail.deJimmi Holst Christensen <jhc@dismail.de> 2022-01-07 22:10:36+01:00
logf48f687c051602bfc0e8098cb91b43d971541271
tree96ec22f2a2528495d66957f425d1b950a79d3d42
parentf78d3b27ca1bea33c92e2f8eae84589db28c06cb

Fix llvmFieldIndex for zero sized fields

It is possible for Zig to emit field ptr instructions to fields whos type is zero sized. In this case llvm should return a pointer which points to the next none zero sized parameter.

1 files changed, 35 insertions(+), 19 deletions(-)

src/codegen/llvm.zig+35-19
...@@ -2647,7 +2647,7 @@ pub const FuncGen = struct {...@@ -2647,7 +2647,7 @@ pub const FuncGen = struct {
2647 switch (struct_ty.zigTypeTag()) {2647 switch (struct_ty.zigTypeTag()) {
2648 .Struct => {2648 .Struct => {
2649 var ptr_ty_buf: Type.Payload.Pointer = undefined;2649 var ptr_ty_buf: Type.Payload.Pointer = undefined;
2650 const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf);2650 const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;
2651 const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, "");2651 const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, "");
2652 const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base);2652 const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base);
2653 return self.load(field_ptr, field_ptr_ty);2653 return self.load(field_ptr, field_ptr_ty);
...@@ -4354,8 +4354,18 @@ pub const FuncGen = struct {...@@ -4354,8 +4354,18 @@ pub const FuncGen = struct {
4354 .Struct => {4354 .Struct => {
4355 const target = self.dg.module.getTarget();4355 const target = self.dg.module.getTarget();
4356 var ty_buf: Type.Payload.Pointer = undefined;4356 var ty_buf: Type.Payload.Pointer = undefined;
4357 const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ty_buf);4357 if (llvmFieldIndex(struct_ty, field_index, target, &ty_buf)) |llvm_field_index| {
4358 return self.builder.buildStructGEP(struct_ptr, llvm_field_index, "");4358 return self.builder.buildStructGEP(struct_ptr, llvm_field_index, "");
4359 } else {
4360 // If we found no index then this means this is a zero sized field at the
4361 // end of the struct. Treat our struct pointer as an array of two and get
4362 // the index to the element at index `1` to get a pointer to the end of
4363 // the struct.
4364 const llvm_usize = try self.dg.llvmType(Type.usize);
4365 const llvm_index = llvm_usize.constInt(1, .False);
4366 const indices: [1]*const llvm.Value = .{llvm_index};
4367 return self.builder.buildInBoundsGEP(struct_ptr, &indices, indices.len, "");
4368 }
4359 },4369 },
4360 .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index),4370 .Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index),
4361 else => unreachable,4371 else => unreachable,
...@@ -4750,32 +4760,37 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca...@@ -4750,32 +4760,37 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca
4750 };4760 };
4751}4761}
47524762
4753/// Take into account 0 bit fields.4763/// Take into account 0 bit fields. Returns null if an llvm field could not be found. This only
4764/// happends if you want the field index of a zero sized field at the end of the struct.
4754fn llvmFieldIndex(4765fn llvmFieldIndex(
4755 ty: Type,4766 ty: Type,
4756 field_index: u32,4767 field_index: u32,
4757 target: std.Target,4768 target: std.Target,
4758 ptr_pl_buf: *Type.Payload.Pointer,4769 ptr_pl_buf: *Type.Payload.Pointer,
4759) c_uint {4770) ?c_uint {
4760 const struct_obj = ty.castTag(.@"struct").?.data;4771 const struct_obj = ty.castTag(.@"struct").?.data;
4761 if (struct_obj.layout != .Packed) {4772 if (struct_obj.layout != .Packed) {
4762 var llvm_field_index: c_uint = 0;4773 var llvm_field_index: c_uint = 0;
4763 for (struct_obj.fields.values()) |field, i| {4774 for (struct_obj.fields.values()) |field, i| {
4764 if (!field.ty.hasCodeGenBits()) continue;4775 if (!field.ty.hasCodeGenBits())
47654776 continue;
4766 if (i == field_index) {4777 if (field_index > i) {
4767 ptr_pl_buf.* = .{4778 llvm_field_index += 1;
4768 .data = .{4779 continue;
4769 .pointee_type = field.ty,
4770 .@"align" = field.normalAlignment(target),
4771 .@"addrspace" = .generic,
4772 },
4773 };
4774 return llvm_field_index;
4775 }4780 }
4776 llvm_field_index += 1;4781
4782 ptr_pl_buf.* = .{
4783 .data = .{
4784 .pointee_type = field.ty,
4785 .@"align" = field.normalAlignment(target),
4786 .@"addrspace" = .generic,
4787 },
4788 };
4789 return llvm_field_index;
4790 } else {
4791 // We did not find an llvm field that corrispons to this zig field.
4792 return null;
4777 }4793 }
4778 unreachable;
4779 }4794 }
47804795
4781 // Our job here is to return the host integer field index.4796 // Our job here is to return the host integer field index.
...@@ -4784,7 +4799,8 @@ fn llvmFieldIndex(...@@ -4784,7 +4799,8 @@ fn llvmFieldIndex(
4784 var running_bits: u16 = 0;4799 var running_bits: u16 = 0;
4785 var llvm_field_index: c_uint = 0;4800 var llvm_field_index: c_uint = 0;
4786 for (struct_obj.fields.values()) |field, i| {4801 for (struct_obj.fields.values()) |field, i| {
4787 if (!field.ty.hasCodeGenBits()) continue;4802 if (!field.ty.hasCodeGenBits())
4803 continue;
47884804
4789 const field_align = field.packedAlignment();4805 const field_align = field.packedAlignment();
4790 if (field_align == 0) {4806 if (field_align == 0) {