stage2: LLVM: fix lowering of packed structs

* ensure enough capacity when building the LLVM type and value.
 * add explicit padding field and populate it to ensure proper
   alignment.
This commit is contained in:
Andrew Kelley 2021-12-24 02:37:54 -07:00
parent 5b171f446f
commit 6b8e33d14c
2 changed files with 47 additions and 1 deletions

View File

@ -845,9 +845,11 @@ pub const DeclGen = struct {
defer llvm_field_types.deinit(gpa);
if (struct_obj.layout == .Packed) {
try llvm_field_types.ensureUnusedCapacity(gpa, struct_obj.fields.count() * 2);
const target = dg.module.getTarget();
comptime assert(Type.packed_struct_layout_version == 1);
var offset: u64 = 0;
var big_align: u32 = 0;
var running_bits: u16 = 0;
for (struct_obj.fields.values()) |field| {
if (!field.ty.hasCodeGenBits()) continue;
@ -863,6 +865,7 @@ pub const DeclGen = struct {
};
const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
const int_align = int_ty.abiAlignment(target);
big_align = @maximum(big_align, int_align);
const llvm_int_ty = try dg.llvmType(int_ty);
const prev_offset = offset;
offset = std.mem.alignForwardGeneric(u64, offset, int_align);
@ -875,6 +878,7 @@ pub const DeclGen = struct {
offset += int_ty.abiSize(target);
running_bits = 0;
}
big_align = @maximum(big_align, field_align);
const prev_offset = offset;
offset = std.mem.alignForwardGeneric(u64, offset, field_align);
const padding_bytes = @intCast(c_uint, offset - prev_offset);
@ -894,6 +898,7 @@ pub const DeclGen = struct {
};
const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
const int_align = int_ty.abiAlignment(target);
big_align = @maximum(big_align, int_align);
const prev_offset = offset;
offset = std.mem.alignForwardGeneric(u64, offset, int_align);
const padding_bytes = @intCast(c_uint, offset - prev_offset);
@ -904,6 +909,14 @@ pub const DeclGen = struct {
const llvm_int_ty = try dg.llvmType(int_ty);
llvm_field_types.appendAssumeCapacity(llvm_int_ty);
}
const prev_offset = offset;
offset = std.mem.alignForwardGeneric(u64, offset, big_align);
const padding_bytes = @intCast(c_uint, offset - prev_offset);
if (padding_bytes != 0) {
const padding = dg.context.intType(8).arrayType(padding_bytes);
llvm_field_types.appendAssumeCapacity(padding);
}
} else {
for (struct_obj.fields.values()) |field| {
if (!field.ty.hasCodeGenBits()) continue;
@ -1319,8 +1332,9 @@ pub const DeclGen = struct {
const llvm_struct_ty = try dg.llvmType(tv.ty);
const field_vals = tv.val.castTag(.@"struct").?.data;
const gpa = dg.gpa;
const llvm_field_count = llvm_struct_ty.countStructElementTypes();
var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, field_vals.len);
var llvm_fields = try std.ArrayListUnmanaged(*const llvm.Value).initCapacity(gpa, llvm_field_count);
defer llvm_fields.deinit(gpa);
const struct_obj = tv.ty.castTag(.@"struct").?.data;
@ -1329,6 +1343,7 @@ pub const DeclGen = struct {
const fields = struct_obj.fields.values();
comptime assert(Type.packed_struct_layout_version == 1);
var offset: u64 = 0;
var big_align: u32 = 0;
var running_bits: u16 = 0;
var running_int: *const llvm.Value = llvm_struct_ty.structGetTypeAtIndex(0).constNull();
for (field_vals) |field_val, i| {
@ -1349,6 +1364,7 @@ pub const DeclGen = struct {
running_int = running_int.constOr(shifted);
running_bits += ty_bit_size;
} else {
big_align = @maximum(big_align, field_align);
if (running_bits != 0) {
var int_payload: Type.Payload.Bits = .{
.base = .{ .tag = .int_unsigned },
@ -1356,6 +1372,7 @@ pub const DeclGen = struct {
};
const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
const int_align = int_ty.abiAlignment(target);
big_align = @maximum(big_align, int_align);
const prev_offset = offset;
offset = std.mem.alignForwardGeneric(u64, offset, int_align);
const padding_bytes = @intCast(c_uint, offset - prev_offset);
@ -1382,6 +1399,32 @@ pub const DeclGen = struct {
offset += field.ty.abiSize(target);
}
}
if (running_bits != 0) {
var int_payload: Type.Payload.Bits = .{
.base = .{ .tag = .int_unsigned },
.data = running_bits,
};
const int_ty: Type = .{ .ptr_otherwise = &int_payload.base };
const int_align = int_ty.abiAlignment(target);
big_align = @maximum(big_align, int_align);
const prev_offset = offset;
offset = std.mem.alignForwardGeneric(u64, offset, int_align);
const padding_bytes = @intCast(c_uint, offset - prev_offset);
if (padding_bytes != 0) {
const padding = dg.context.intType(8).arrayType(padding_bytes);
llvm_fields.appendAssumeCapacity(padding.getUndef());
}
llvm_fields.appendAssumeCapacity(running_int);
offset += int_ty.abiSize(target);
}
const prev_offset = offset;
offset = std.mem.alignForwardGeneric(u64, offset, big_align);
const padding_bytes = @intCast(c_uint, offset - prev_offset);
if (padding_bytes != 0) {
const padding = dg.context.intType(8).arrayType(padding_bytes);
llvm_fields.appendAssumeCapacity(padding.getUndef());
}
} else {
for (field_vals) |field_val, i| {
const field_ty = tv.ty.structFieldType(i);

View File

@ -257,6 +257,9 @@ pub const Type = opaque {
pub const getElementType = LLVMGetElementType;
extern fn LLVMGetElementType(Ty: *const Type) *const Type;
pub const countStructElementTypes = LLVMCountStructElementTypes;
extern fn LLVMCountStructElementTypes(StructTy: *const Type) c_uint;
};
pub const Module = opaque {