aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/llvm.zig
diff options
context:
space:
mode:
authorJimmi Holst Christensen <jhc@dismail.de>2022-01-07 19:02:24 +0100
committerJimmi Holst Christensen <jhc@dismail.de>2022-01-07 22:10:36 +0100
commitf48f687c051602bfc0e8098cb91b43d971541271 (patch)
tree96ec22f2a2528495d66957f425d1b950a79d3d42 /src/codegen/llvm.zig
parentf78d3b27ca1bea33c92e2f8eae84589db28c06cb (diff)
downloadzig-f48f687c051602bfc0e8098cb91b43d971541271.tar.gz
zig-f48f687c051602bfc0e8098cb91b43d971541271.zip
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.
Diffstat (limited to 'src/codegen/llvm.zig')
-rw-r--r--src/codegen/llvm.zig54
1 files changed, 35 insertions, 19 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig
index b1046582fa..98b906741d 100644
--- a/src/codegen/llvm.zig
+++ b/src/codegen/llvm.zig
@@ -2647,7 +2647,7 @@ pub const FuncGen = struct {
switch (struct_ty.zigTypeTag()) {
.Struct => {
var ptr_ty_buf: Type.Payload.Pointer = undefined;
- const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf);
+ const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ptr_ty_buf).?;
const field_ptr = self.builder.buildStructGEP(struct_llvm_val, llvm_field_index, "");
const field_ptr_ty = Type.initPayload(&ptr_ty_buf.base);
return self.load(field_ptr, field_ptr_ty);
@@ -4354,8 +4354,18 @@ pub const FuncGen = struct {
.Struct => {
const target = self.dg.module.getTarget();
var ty_buf: Type.Payload.Pointer = undefined;
- const llvm_field_index = llvmFieldIndex(struct_ty, field_index, target, &ty_buf);
- return self.builder.buildStructGEP(struct_ptr, llvm_field_index, "");
+ if (llvmFieldIndex(struct_ty, field_index, target, &ty_buf)) |llvm_field_index| {
+ return self.builder.buildStructGEP(struct_ptr, llvm_field_index, "");
+ } else {
+ // If we found no index then this means this is a zero sized field at the
+ // end of the struct. Treat our struct pointer as an array of two and get
+ // the index to the element at index `1` to get a pointer to the end of
+ // the struct.
+ const llvm_usize = try self.dg.llvmType(Type.usize);
+ const llvm_index = llvm_usize.constInt(1, .False);
+ const indices: [1]*const llvm.Value = .{llvm_index};
+ return self.builder.buildInBoundsGEP(struct_ptr, &indices, indices.len, "");
+ }
},
.Union => return self.unionFieldPtr(inst, struct_ptr, struct_ty, field_index),
else => unreachable,
@@ -4750,32 +4760,37 @@ fn toLlvmCallConv(cc: std.builtin.CallingConvention, target: std.Target) llvm.Ca
};
}
-/// Take into account 0 bit fields.
+/// Take into account 0 bit fields. Returns null if an llvm field could not be found. This only
+/// happends if you want the field index of a zero sized field at the end of the struct.
fn llvmFieldIndex(
ty: Type,
field_index: u32,
target: std.Target,
ptr_pl_buf: *Type.Payload.Pointer,
-) c_uint {
+) ?c_uint {
const struct_obj = ty.castTag(.@"struct").?.data;
if (struct_obj.layout != .Packed) {
var llvm_field_index: c_uint = 0;
for (struct_obj.fields.values()) |field, i| {
- if (!field.ty.hasCodeGenBits()) continue;
-
- if (i == field_index) {
- ptr_pl_buf.* = .{
- .data = .{
- .pointee_type = field.ty,
- .@"align" = field.normalAlignment(target),
- .@"addrspace" = .generic,
- },
- };
- return llvm_field_index;
+ if (!field.ty.hasCodeGenBits())
+ continue;
+ if (field_index > i) {
+ llvm_field_index += 1;
+ continue;
}
- llvm_field_index += 1;
+
+ ptr_pl_buf.* = .{
+ .data = .{
+ .pointee_type = field.ty,
+ .@"align" = field.normalAlignment(target),
+ .@"addrspace" = .generic,
+ },
+ };
+ return llvm_field_index;
+ } else {
+ // We did not find an llvm field that corrispons to this zig field.
+ return null;
}
- unreachable;
}
// Our job here is to return the host integer field index.
@@ -4784,7 +4799,8 @@ fn llvmFieldIndex(
var running_bits: u16 = 0;
var llvm_field_index: c_uint = 0;
for (struct_obj.fields.values()) |field, i| {
- if (!field.ty.hasCodeGenBits()) continue;
+ if (!field.ty.hasCodeGenBits())
+ continue;
const field_align = field.packedAlignment();
if (field_align == 0) {