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 {
674674 },
675675 } else first[first.len..];
676676 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);
678 const pref_align: Alignment = if (field_it.next()) |pref_align|
679 .fromByteUnits(std.fmt.parseInt(u64, pref_align, 10) catch unreachable)
680 else
681 abi_align;
677 const abi_align: Alignment = .fromByteUnits(
678 @divExact(std.fmt.parseInt(u64, field_it.next().?, 10) catch unreachable, 8),
679 );
680 const pref_align: Alignment = if (field_it.next()) |pref_align| .fromByteUnits(
681 @divExact(std.fmt.parseInt(u64, pref_align, 10) catch unreachable, 8),
682 ) else abi_align;
682683 const index_bit_width = if (field_it.next()) |index_bit_width|
683684 std.fmt.parseInt(PointerSpec.BitWidth, index_bit_width, 10) catch unreachable
684685 else
......@@ -708,11 +709,12 @@ pub const DataLayout = struct {
708709 }
709710 var field_it = std.mem.splitScalar(u8, spec[1..], ':');
710711 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 pref_align: Alignment = if (field_it.next()) |pref_align|
713 .fromByteUnits(std.fmt.parseInt(u64, pref_align, 10) catch unreachable)
714 else
715 abi_align;
712 const abi_align: Alignment = .fromByteUnits(
713 @divExact(std.fmt.parseInt(u64, field_it.next().?, 10) catch unreachable, 8),
714 );
715 const pref_align: Alignment = if (field_it.next()) |pref_align| .fromByteUnits(
716 @divExact(std.fmt.parseInt(u64, pref_align, 10) catch unreachable, 8),
717 ) else abi_align;
716718 assert(field_it.peek() == null);
717719 const specs = switch (kind) {
718720 else => unreachable,
......@@ -720,7 +722,10 @@ pub const DataLayout = struct {
720722 'f' => &float_specs,
721723 'v' => &vector_specs,
722724 };
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;
724729 },
725730 'n' => {
726731 var field_it = std.mem.splitScalar(u8, spec[1..], ':');
......@@ -784,45 +789,52 @@ pub const DataLayout = struct {
784789 data_layout.pointer_specs.deinit(gpa);
785790 }
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 {
788793 const specs = data_layout.int_specs.keys();
789794 return specs[
790795 @min(std.sort.lowerBound(PrimitiveSpec, specs, bit_width, struct {
791 fn order(ctx: PrimitiveSpec.BitWidth, spec: PrimitiveSpec) std.math.Order {
792 return std.math.order(ctx, spec.bit_width);
796 fn order(ctx: Type.Size, spec: PrimitiveSpec) std.math.Order {
797 return std.math.order(ctx.fixed, spec.bit_width);
793798 }
794799 }.order), specs.len - 1)
795800 ];
796801 }
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);
799805 if (data_layout.float_specs.getEntry(.{
800 .bit_width = bit_width,
806 .bit_width = fixed_bit_width,
801807 .abi_align = .default,
802808 .pref_align = .default,
803809 })) |entry| return entry.key_ptr.*;
804810 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)),
806812 );
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 };
808818 }
809819
810 pub fn getVectorSpec(
811 data_layout: *const DataLayout,
812 bit_width: PrimitiveSpec.BitWidth,
813 store_size: Type.Size,
814 ) PrimitiveSpec {
815 if (data_layout.float_specs.getEntry(.{
816 .bit_width = bit_width,
820 pub fn getVectorSpec(data_layout: *const DataLayout, bit_width: Type.Size) PrimitiveSpec {
821 const known_min_bit_width: PrimitiveSpec.BitWidth = @intCast(switch (bit_width) {
822 .fixed, .scalable => |known_min| known_min,
823 });
824 if (data_layout.vector_specs.getEntry(.{
825 .bit_width = known_min_bit_width,
817826 .abi_align = .default,
818827 .pref_align = .default,
819828 })) |entry| return entry.key_ptr.*;
820 const default_align: Alignment = .fromByteUnits(
821 std.math.ceilPowerOfTwoAssert(PrimitiveSpec.BitWidth, switch (store_size) {
822 .fixed, .scalable => |known_min| known_min,
823 }),
824 );
825 return .{ .bit_width = bit_width, .abi_align = default_align, .pref_align = default_align };
829 const default_align: Alignment = .fromByteUnits(std.math.ceilPowerOfTwoAssert(
830 PrimitiveSpec.BitWidth,
831 std.mem.alignForward(PrimitiveSpec.BitWidth, known_min_bit_width, 8),
832 ));
833 return .{
834 .bit_width = known_min_bit_width,
835 .abi_align = default_align,
836 .pref_align = default_align,
837 };
826838 }
827839
828840 pub fn getPointerSpec(data_layout: *const DataLayout, addr_space: AddrSpace) PointerSpec {
......@@ -1699,6 +1711,22 @@ pub const Type = enum(u32) {
16991711 .pointer => .{
17001712 .fixed = builder.data_layout.getPointerSpec(@fromBackingInt(@intCast(item.data))).bit_width,
17011713 },
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) },
17021730 };
17031731 }
17041732
......@@ -1716,7 +1744,7 @@ pub const Type = enum(u32) {
17161744 };
17171745 },
17181746 .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));
17201748 return switch (kind) {
17211749 .abi => spec.abi_align,
17221750 .pref => spec.pref_align,
......@@ -1725,7 +1753,7 @@ pub const Type = enum(u32) {
17251753 .x86_amx => return comptime .fromByteUnits(64),
17261754 },
17271755 .integer => {
1728 const spec = builder.data_layout.getIntegerSpec(@intCast(item.data));
1756 const spec = builder.data_layout.getIntegerSpec(.{ .fixed = item.data });
17291757 return switch (kind) {
17301758 .abi => spec.abi_align,
17311759 .pref => spec.pref_align,
......@@ -1738,6 +1766,13 @@ pub const Type = enum(u32) {
17381766 .pref => spec.flags.pref_align,
17391767 };
17401768 },
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 },
17411776 }
17421777 }
17431778};
src/codegen/llvm.zig+1-1
......@@ -2484,7 +2484,7 @@ pub const Object = struct {
24842484 .memory_access => {},
24852485 .in_memory => {
24862486 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;
24882488 if (zig_align < llvm_align.toByteUnits().?) return o.builder.arrayType(abi_size, .i8);
24892489 },
24902490 }
src/dev.zig+39-26
......@@ -32,6 +32,14 @@ pub const Env = enum {
3232 /// - `zig build-* -ofmt=c`
3333 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
3543 /// - sema
3644 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target powerpc(64)(le)-linux --listen=-`
3745 @"powerpc-linux",
......@@ -44,6 +52,10 @@ pub const Env = enum {
4452 /// - `zig build-* -fno-llvm -fno-lld -target spirv(32/64)-* --listen=-`
4553 spirv,
4654
55 /// - sema
56 /// - `zig build-* -fno-llvm -fno-lld -target spork8-* --listen=-`
57 spork8,
58
4759 /// - sema
4860 /// - `zig build-* -fno-llvm -fno-lld -target wasm32-* --listen=-`
4961 wasm,
......@@ -56,14 +68,6 @@ pub const Env = enum {
5668 /// - `zig build-* -fincremental -fno-llvm -fno-lld -target x86_64-windows --listen=-`
5769 @"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
6771 pub inline fn supports(comptime dev_env: Env, comptime feature: Feature) bool {
6872 return switch (dev_env) {
6973 .full => true,
......@@ -186,6 +190,24 @@ pub const Env = enum {
186190 => true,
187191 else => Env.sema.supports(feature),
188192 },
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 },
189211 .@"powerpc-linux" => switch (feature) {
190212 .stdio_listen,
191213 .incremental,
......@@ -207,6 +229,15 @@ pub const Env = enum {
207229 => true,
208230 else => Env.sema.supports(feature),
209231 },
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 },
210241 .wasm => switch (feature) {
211242 .incremental,
212243 .legalize,
......@@ -235,24 +266,6 @@ pub const Env = enum {
235266 => true,
236267 else => Env.sema.supports(feature),
237268 },
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 },
256269 };
257270 }
258271