authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-10-06 07:50:55-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2026-10-07 19:16:44-04:00
log0bcb597164f54aed060414505643696b31b12fc8
treeaca4c55b5307e83371ef481f603ca257a58e1f2a
parentc6044e6a109aa3a01eb9daadb13c6256b80e853c

llvm.Builder: fix incorrect data layout parsing and storage

Closes #37099

3 files changed, 108 insertions(+), 60 deletions(-)

lib/std/zig/llvm/Builder.zig+68-33
...@@ -674,11 +674,12 @@ pub const DataLayout = struct {...@@ -674,11 +674,12 @@ pub const DataLayout = struct {
674 },674 },
675 } else first[first.len..];675 } else first[first.len..];
676 const bit_width = std.fmt.parseInt(PointerSpec.BitWidth, field_it.next().?, 10) catch unreachable;676 const bit_width = std.fmt.parseInt(PointerSpec.BitWidth, field_it.next().?, 10) catch unreachable;
677 const abi_align: Alignment = .fromByteUnits(std.fmt.parseInt(u64, field_it.next().?, 10) catch unreachable);677 const abi_align: Alignment = .fromByteUnits(
678 const pref_align: Alignment = if (field_it.next()) |pref_align|678 @divExact(std.fmt.parseInt(u64, field_it.next().?, 10) catch unreachable, 8),
679 .fromByteUnits(std.fmt.parseInt(u64, pref_align, 10) catch unreachable)679 );
680 else680 const pref_align: Alignment = if (field_it.next()) |pref_align| .fromByteUnits(
681 abi_align;681 @divExact(std.fmt.parseInt(u64, pref_align, 10) catch unreachable, 8),
682 ) else abi_align;
682 const index_bit_width = if (field_it.next()) |index_bit_width|683 const index_bit_width = if (field_it.next()) |index_bit_width|
683 std.fmt.parseInt(PointerSpec.BitWidth, index_bit_width, 10) catch unreachable684 std.fmt.parseInt(PointerSpec.BitWidth, index_bit_width, 10) catch unreachable
684 else685 else
...@@ -708,11 +709,12 @@ pub const DataLayout = struct {...@@ -708,11 +709,12 @@ pub const DataLayout = struct {
708 }709 }
709 var field_it = std.mem.splitScalar(u8, spec[1..], ':');710 var field_it = std.mem.splitScalar(u8, spec[1..], ':');
710 const bit_width = std.fmt.parseInt(PrimitiveSpec.BitWidth, field_it.first(), 10) catch unreachable;711 const bit_width = std.fmt.parseInt(PrimitiveSpec.BitWidth, field_it.first(), 10) catch unreachable;
711 const abi_align: Alignment = .fromByteUnits(std.fmt.parseInt(u64, field_it.next().?, 10) catch unreachable);712 const abi_align: Alignment = .fromByteUnits(
712 const pref_align: Alignment = if (field_it.next()) |pref_align|713 @divExact(std.fmt.parseInt(u64, field_it.next().?, 10) catch unreachable, 8),
713 .fromByteUnits(std.fmt.parseInt(u64, pref_align, 10) catch unreachable)714 );
714 else715 const pref_align: Alignment = if (field_it.next()) |pref_align| .fromByteUnits(
715 abi_align;716 @divExact(std.fmt.parseInt(u64, pref_align, 10) catch unreachable, 8),
717 ) else abi_align;
716 assert(field_it.peek() == null);718 assert(field_it.peek() == null);
717 const specs = switch (kind) {719 const specs = switch (kind) {
718 else => unreachable,720 else => unreachable,
...@@ -720,7 +722,10 @@ pub const DataLayout = struct {...@@ -720,7 +722,10 @@ pub const DataLayout = struct {
720 'f' => &float_specs,722 'f' => &float_specs,
721 'v' => &vector_specs,723 'v' => &vector_specs,
722 };724 };
723 try specs.put(gpa, .{ .bit_width = bit_width, .abi_align = abi_align, .pref_align = pref_align }, {});725 const primitive_spec: PrimitiveSpec =
726 .{ .bit_width = bit_width, .abi_align = abi_align, .pref_align = pref_align };
727 const gop = try specs.getOrPut(gpa, primitive_spec);
728 gop.key_ptr.* = primitive_spec;
724 },729 },
725 'n' => {730 'n' => {
726 var field_it = std.mem.splitScalar(u8, spec[1..], ':');731 var field_it = std.mem.splitScalar(u8, spec[1..], ':');
...@@ -784,45 +789,52 @@ pub const DataLayout = struct {...@@ -784,45 +789,52 @@ pub const DataLayout = struct {
784 data_layout.pointer_specs.deinit(gpa);789 data_layout.pointer_specs.deinit(gpa);
785 }790 }
786791
787 pub fn getIntegerSpec(data_layout: *const DataLayout, bit_width: PrimitiveSpec.BitWidth) PrimitiveSpec {792 pub fn getIntegerSpec(data_layout: *const DataLayout, bit_width: Type.Size) PrimitiveSpec {
788 const specs = data_layout.int_specs.keys();793 const specs = data_layout.int_specs.keys();
789 return specs[794 return specs[
790 @min(std.sort.lowerBound(PrimitiveSpec, specs, bit_width, struct {795 @min(std.sort.lowerBound(PrimitiveSpec, specs, bit_width, struct {
791 fn order(ctx: PrimitiveSpec.BitWidth, spec: PrimitiveSpec) std.math.Order {796 fn order(ctx: Type.Size, spec: PrimitiveSpec) std.math.Order {
792 return std.math.order(ctx, spec.bit_width);797 return std.math.order(ctx.fixed, spec.bit_width);
793 }798 }
794 }.order), specs.len - 1)799 }.order), specs.len - 1)
795 ];800 ];
796 }801 }
797802
798 pub fn getFloatSpec(data_layout: *const DataLayout, bit_width: PrimitiveSpec.BitWidth) PrimitiveSpec {803 pub fn getFloatSpec(data_layout: *const DataLayout, bit_width: Type.Size) PrimitiveSpec {
804 const fixed_bit_width: PrimitiveSpec.BitWidth = @intCast(bit_width.fixed);
799 if (data_layout.float_specs.getEntry(.{805 if (data_layout.float_specs.getEntry(.{
800 .bit_width = bit_width,806 .bit_width = fixed_bit_width,
801 .abi_align = .default,807 .abi_align = .default,
802 .pref_align = .default,808 .pref_align = .default,
803 })) |entry| return entry.key_ptr.*;809 })) |entry| return entry.key_ptr.*;
804 const default_align: Alignment = .fromByteUnits(810 const default_align: Alignment = .fromByteUnits(
805 std.math.ceilPowerOfTwoAssert(PrimitiveSpec.BitWidth, bit_width / 8),811 std.math.ceilPowerOfTwoAssert(PrimitiveSpec.BitWidth, @divExact(fixed_bit_width, 8)),
806 );812 );
807 return .{ .bit_width = bit_width, .abi_align = default_align, .pref_align = default_align };813 return .{
814 .bit_width = fixed_bit_width,
815 .abi_align = default_align,
816 .pref_align = default_align,
817 };
808 }818 }
809819
810 pub fn getVectorSpec(820 pub fn getVectorSpec(data_layout: *const DataLayout, bit_width: Type.Size) PrimitiveSpec {
811 data_layout: *const DataLayout,821 const known_min_bit_width: PrimitiveSpec.BitWidth = @intCast(switch (bit_width) {
812 bit_width: PrimitiveSpec.BitWidth,822 .fixed, .scalable => |known_min| known_min,
813 store_size: Type.Size,823 });
814 ) PrimitiveSpec {824 if (data_layout.vector_specs.getEntry(.{
815 if (data_layout.float_specs.getEntry(.{825 .bit_width = known_min_bit_width,
816 .bit_width = bit_width,
817 .abi_align = .default,826 .abi_align = .default,
818 .pref_align = .default,827 .pref_align = .default,
819 })) |entry| return entry.key_ptr.*;828 })) |entry| return entry.key_ptr.*;
820 const default_align: Alignment = .fromByteUnits(829 const default_align: Alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(
821 std.math.ceilPowerOfTwoAssert(PrimitiveSpec.BitWidth, switch (store_size) {830 PrimitiveSpec.BitWidth,
822 .fixed, .scalable => |known_min| known_min,831 std.mem.alignForward(PrimitiveSpec.BitWidth, known_min_bit_width, 8),
823 }),832 ));
824 );833 return .{
825 return .{ .bit_width = bit_width, .abi_align = default_align, .pref_align = default_align };834 .bit_width = known_min_bit_width,
835 .abi_align = default_align,
836 .pref_align = default_align,
837 };
826 }838 }
827839
828 pub fn getPointerSpec(data_layout: *const DataLayout, addr_space: AddrSpace) PointerSpec {840 pub fn getPointerSpec(data_layout: *const DataLayout, addr_space: AddrSpace) PointerSpec {
...@@ -1699,6 +1711,22 @@ pub const Type = enum(u32) {...@@ -1699,6 +1711,22 @@ pub const Type = enum(u32) {
1699 .pointer => .{1711 .pointer => .{
1700 .fixed = builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(item.data))).bit_width,1712 .fixed = builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(item.data))).bit_width,
1701 },1713 },
1714 .vector, .scalable_vector => {
1715 const extra = builder.typeExtraData(Type.Vector, item.data);
1716 const min_bits = extra.len * extra.child.bits(builder).fixed;
1717 return switch (item.tag) {
1718 else => unreachable,
1719 .vector => .{ .fixed = min_bits },
1720 .scalable_vector => .{ .scalable = min_bits },
1721 };
1722 },
1723 };
1724 }
1725
1726 pub fn storeSize(ty: Type, builder: *const Builder) Size {
1727 return switch (ty.bits(builder)) {
1728 .fixed => |fixed| .{ .fixed = @divCeil(fixed, 8) },
1729 .scalable => |known_min| .{ .scalable = @divCeil(known_min, 8) },
1702 };1730 };
1703 }1731 }
17041732
...@@ -1716,7 +1744,7 @@ pub const Type = enum(u32) {...@@ -1716,7 +1744,7 @@ pub const Type = enum(u32) {
1716 };1744 };
1717 },1745 },
1718 .half, .bfloat, .float, .double, .ppc_fp128, .fp128, .x86_fp80 => {1746 .half, .bfloat, .float, .double, .ppc_fp128, .fp128, .x86_fp80 => {
1719 const spec = builder.data_layout.getFloatSpec(@intCast(ty.bits(builder).fixed));1747 const spec = builder.data_layout.getFloatSpec(ty.bits(builder));
1720 return switch (kind) {1748 return switch (kind) {
1721 .abi => spec.abi_align,1749 .abi => spec.abi_align,
1722 .pref => spec.pref_align,1750 .pref => spec.pref_align,
...@@ -1725,7 +1753,7 @@ pub const Type = enum(u32) {...@@ -1725,7 +1753,7 @@ pub const Type = enum(u32) {
1725 .x86_amx => return comptime .fromByteUnits(64),1753 .x86_amx => return comptime .fromByteUnits(64),
1726 },1754 },
1727 .integer => {1755 .integer => {
1728 const spec = builder.data_layout.getIntegerSpec(@intCast(item.data));1756 const spec = builder.data_layout.getIntegerSpec(.{ .fixed = item.data });
1729 return switch (kind) {1757 return switch (kind) {
1730 .abi => spec.abi_align,1758 .abi => spec.abi_align,
1731 .pref => spec.pref_align,1759 .pref => spec.pref_align,
...@@ -1738,6 +1766,13 @@ pub const Type = enum(u32) {...@@ -1738,6 +1766,13 @@ pub const Type = enum(u32) {
1738 .pref => spec.flags.pref_align,1766 .pref => spec.flags.pref_align,
1739 };1767 };
1740 },1768 },
1769 .vector, .scalable_vector => {
1770 const spec = builder.data_layout.getVectorSpec(ty.bits(builder));
1771 return switch (kind) {
1772 .abi => spec.abi_align,
1773 .pref => spec.pref_align,
1774 };
1775 },
1741 }1776 }
1742 }1777 }
1743};1778};
src/codegen/llvm.zig+1-1
...@@ -2484,7 +2484,7 @@ pub const Object = struct {...@@ -2484,7 +2484,7 @@ pub const Object = struct {
2484 .memory_access => {},2484 .memory_access => {},
2485 .in_memory => {2485 .in_memory => {
2486 const zig_align = std.zig.target.intAlignment(target, bits);2486 const zig_align = std.zig.target.intAlignment(target, bits);
2487 const llvm_align = o.builder.data_layout.getIntegerSpec(llvm_bit_width).abi_align;2487 const llvm_align = o.builder.data_layout.getIntegerSpec(.{ .fixed = llvm_bit_width }).abi_align;
2488 if (zig_align < llvm_align.toByteUnits().?) return o.builder.arrayType(abi_size, .i8);2488 if (zig_align < llvm_align.toByteUnits().?) return o.builder.arrayType(abi_size, .i8);
2489 },2489 },
2490 }2490 }
src/dev.zig+39-26
...@@ -32,6 +32,14 @@ pub const Env = enum {...@@ -32,6 +32,14 @@ pub const Env = enum {
32 /// - `zig build-* -ofmt=c`32 /// - `zig build-* -ofmt=c`
33 cbe,33 cbe,
3434
35 /// - sema
36 /// - zig build-* -fincremental -fllvm -flld --listen=-`
37 llvm,
38
39 /// - sema
40 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target loongarch(32/64)-linux --listen=-`
41 @"loongarch-linux",
42
35 /// - sema43 /// - sema
36 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target powerpc(64)(le)-linux --listen=-`44 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target powerpc(64)(le)-linux --listen=-`
37 @"powerpc-linux",45 @"powerpc-linux",
...@@ -44,6 +52,10 @@ pub const Env = enum {...@@ -44,6 +52,10 @@ pub const Env = enum {
44 /// - `zig build-* -fno-llvm -fno-lld -target spirv(32/64)-* --listen=-`52 /// - `zig build-* -fno-llvm -fno-lld -target spirv(32/64)-* --listen=-`
45 spirv,53 spirv,
4654
55 /// - sema
56 /// - `zig build-* -fno-llvm -fno-lld -target spork8-* --listen=-`
57 spork8,
58
47 /// - sema59 /// - sema
48 /// - `zig build-* -fno-llvm -fno-lld -target wasm32-* --listen=-`60 /// - `zig build-* -fno-llvm -fno-lld -target wasm32-* --listen=-`
49 wasm,61 wasm,
...@@ -56,14 +68,6 @@ pub const Env = enum {...@@ -56,14 +68,6 @@ pub const Env = enum {
56 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-windows --listen=-`68 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-windows --listen=-`
57 @"x86_64-windows",69 @"x86_64-windows",
5870
59 /// - sema
60 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target loongarch(32/64)-linux --listen=-`
61 @"loongarch-linux",
62
63 /// - sema
64 /// - `zig build-* -fno-llvm -fno-lld -target spork8-* --listen=-`
65 spork8,
66
67 pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool {71 pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool {
68 return switch (dev_env) {72 return switch (dev_env) {
69 .full => true,73 .full => true,
...@@ -186,6 +190,24 @@ pub const Env = enum {...@@ -186,6 +190,24 @@ pub const Env = enum {
186 => true,190 => true,
187 else => Env.sema.supports(feature),191 else => Env.sema.supports(feature),
188 },192 },
193 .llvm => switch (feature) {
194 .stdio_listen,
195 .incremental,
196 .legalize,
197 .llvm_backend,
198 .lld_linker,
199 => true,
200 else => Env.sema.supports(feature),
201 },
202 .@"loongarch-linux" => switch (feature) {
203 .stdio_listen,
204 .incremental,
205 .legalize,
206 .loongarch_backend,
207 .elf2_linker,
208 => true,
209 else => Env.sema.supports(feature),
210 },
189 .@"powerpc-linux" => switch (feature) {211 .@"powerpc-linux" => switch (feature) {
190 .stdio_listen,212 .stdio_listen,
191 .incremental,213 .incremental,
...@@ -207,6 +229,15 @@ pub const Env = enum {...@@ -207,6 +229,15 @@ pub const Env = enum {
207 => true,229 => true,
208 else => Env.sema.supports(feature),230 else => Env.sema.supports(feature),
209 },231 },
232 .spork8 => switch (feature) {
233 .stdio_listen,
234 .incremental,
235 .legalize,
236 .spork8_backend,
237 .spork8_linker,
238 => true,
239 else => Env.sema.supports(feature),
240 },
210 .wasm => switch (feature) {241 .wasm => switch (feature) {
211 .incremental,242 .incremental,
212 .legalize,243 .legalize,
...@@ -235,24 +266,6 @@ pub const Env = enum {...@@ -235,24 +266,6 @@ pub const Env = enum {
235 => true,266 => true,
236 else => Env.sema.supports(feature),267 else => Env.sema.supports(feature),
237 },268 },
238 .@"loongarch-linux" => switch (feature) {
239 .stdio_listen,
240 .incremental,
241 .legalize,
242 .loongarch_backend,
243 .elf2_linker,
244 => true,
245 else => Env.sema.supports(feature),
246 },
247 .spork8 => switch (feature) {
248 .stdio_listen,
249 .incremental,
250 .legalize,
251 .spork8_backend,
252 .spork8_linker,
253 => true,
254 else => Env.sema.supports(feature),
255 },
256 };269 };
257 }270 }
258271