diff options
| author | Jimmi Holst Christensen <jhc@dismail.de> | 2022-01-07 19:02:24 +0100 |
|---|---|---|
| committer | Jimmi Holst Christensen <jhc@dismail.de> | 2022-01-07 22:10:36 +0100 |
| commit | f48f687c051602bfc0e8098cb91b43d971541271 (patch) | |
| tree | 96ec22f2a2528495d66957f425d1b950a79d3d42 /src/codegen/llvm.zig | |
| parent | f78d3b27ca1bea33c92e2f8eae84589db28c06cb (diff) | |
| download | zig-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.zig | 54 |
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) { |
