diff options
| author | Andrew Kelley <andrew@ziglang.org> | 2021-12-24 02:37:54 -0700 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2021-12-24 02:37:54 -0700 |
| commit | 6b8e33d14c92229b1632c481906d7d698c584000 (patch) | |
| tree | 5d752c74a0c84102a91a67ee799dbdd66b37ad0c /src/codegen | |
| parent | 5b171f446f46c97de111bce0575452be0334a05e (diff) | |
| download | zig-6b8e33d14c92229b1632c481906d7d698c584000.tar.gz zig-6b8e33d14c92229b1632c481906d7d698c584000.zip | |
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.
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/llvm.zig | 45 | ||||
| -rw-r--r-- | src/codegen/llvm/bindings.zig | 3 |
2 files changed, 47 insertions, 1 deletions
diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index c87729cda6..8e274e2a43 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -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); diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index ac712e5681..36e5bf060a 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -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 { |
