authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-17 19:38:27+00:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2026-03-18 01:02:29+01:00
log85837de476a919e42da101d42da848a5f181fb38
tree727f3d0fb0581aa5e5d77652f84e832dda90879e
parent0a2f6632810ceb6a17bffbafd846c5f3aaa24e64

llvm: solve a bunch of alignment bugs

I went over a bunch of calls to `std.zig.llvm.Builder.{load,store}` and added correct alignments where we previously passed the default alignment. This fixes some miscompilations, particularly when using underaligned pointers or *overaligned* slices. I have definitely missed some cases, but it's better to get some fixes in than for this to sit in a `git stash` forever. Resolves: https://codeberg.org/ziglang/zig/issues/31473 Resolves: https://codeberg.org/ziglang/zig/issues/30566

1 files changed, 47 insertions(+), 38 deletions(-)

src/codegen/llvm.zig+47-38
...@@ -1438,8 +1438,7 @@ pub const Object = struct {...@@ -1438,8 +1438,7 @@ pub const Object = struct {
1438 const param = wip.arg(llvm_arg_i);1438 const param = wip.arg(llvm_arg_i);
1439 llvm_arg_i += 1;1439 llvm_arg_i += 1;
1440 const field_ptr = try wip.gepStruct(llvm_ty, arg_ptr, field_i, "");1440 const field_ptr = try wip.gepStruct(llvm_ty, arg_ptr, field_i, "");
1441 const alignment =1441 const alignment = Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
1442 Builder.Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
1443 _ = try wip.store(.normal, param, field_ptr, alignment);1442 _ = try wip.store(.normal, param, field_ptr, alignment);
1444 }1443 }
14451444
...@@ -6151,7 +6150,7 @@ pub const FuncGen = struct {...@@ -6151,7 +6150,7 @@ pub const FuncGen = struct {
6151 const body = unwrapped_try.else_body;6150 const body = unwrapped_try.else_body;
6152 const err_union_ty = self.typeOf(unwrapped_try.error_union);6151 const err_union_ty = self.typeOf(unwrapped_try.error_union);
6153 const is_unused = self.liveness.isUnused(inst);6152 const is_unused = self.liveness.isUnused(inst);
6154 return lowerTry(self, err_union, body, err_union_ty, false, false, is_unused, err_cold);6153 return lowerTry(self, err_union, body, err_union_ty, false, .none, false, is_unused, err_cold);
6155 }6154 }
61566155
6157 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value {6156 fn airTryPtr(self: *FuncGen, inst: Air.Inst.Index, err_cold: bool) !Builder.Value {
...@@ -6159,12 +6158,13 @@ pub const FuncGen = struct {...@@ -6159,12 +6158,13 @@ pub const FuncGen = struct {
6159 const unwrapped_try = self.air.unwrapTryPtr(inst);6158 const unwrapped_try = self.air.unwrapTryPtr(inst);
6160 const err_union_ptr = try self.resolveInst(unwrapped_try.error_union_ptr);6159 const err_union_ptr = try self.resolveInst(unwrapped_try.error_union_ptr);
6161 const body = unwrapped_try.else_body;6160 const body = unwrapped_try.else_body;
6162 const err_union_ty = self.typeOf(unwrapped_try.error_union_ptr).childType(zcu);6161 const err_union_ptr_ty = self.typeOf(unwrapped_try.error_union_ptr);
6162 const err_union_ty = err_union_ptr_ty.childType(zcu);
6163 const is_unused = self.liveness.isUnused(inst);6163 const is_unused = self.liveness.isUnused(inst);
61646164
6165 self.maybeMarkAllowZeroAccess(self.typeOf(unwrapped_try.error_union_ptr).ptrInfo(zcu));6165 self.maybeMarkAllowZeroAccess(self.typeOf(unwrapped_try.error_union_ptr).ptrInfo(zcu));
61666166
6167 return lowerTry(self, err_union_ptr, body, err_union_ty, true, true, is_unused, err_cold);6167 return lowerTry(self, err_union_ptr, body, err_union_ty, true, err_union_ptr_ty.ptrAlignment(zcu), true, is_unused, err_cold);
6168 }6168 }
61696169
6170 fn lowerTry(6170 fn lowerTry(
...@@ -6173,6 +6173,7 @@ pub const FuncGen = struct {...@@ -6173,6 +6173,7 @@ pub const FuncGen = struct {
6173 body: []const Air.Inst.Index,6173 body: []const Air.Inst.Index,
6174 err_union_ty: Type,6174 err_union_ty: Type,
6175 operand_is_ptr: bool,6175 operand_is_ptr: bool,
6176 operand_ptr_align: InternPool.Alignment,
6176 can_elide_load: bool,6177 can_elide_load: bool,
6177 is_unused: bool,6178 is_unused: bool,
6178 err_cold: bool,6179 err_cold: bool,
...@@ -6185,15 +6186,19 @@ pub const FuncGen = struct {...@@ -6185,15 +6186,19 @@ pub const FuncGen = struct {
6185 const err_union_llvm_ty = try o.lowerType(pt, err_union_ty);6186 const err_union_llvm_ty = try o.lowerType(pt, err_union_ty);
6186 const error_type = try o.errorIntType(pt);6187 const error_type = try o.errorIntType(pt);
61876188
6189 const err_set_align: InternPool.Alignment, const payload_align: InternPool.Alignment = if (operand_is_ptr) .{
6190 operand_ptr_align.minStrict(Type.anyerror.abiAlignment(zcu)),
6191 operand_ptr_align.minStrict(payload_ty.abiAlignment(zcu)),
6192 } else .{ .none, .none };
6193
6188 if (!err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {6194 if (!err_union_ty.errorUnionSet(zcu).errorSetIsEmpty(zcu)) {
6189 const loaded = loaded: {6195 const loaded = loaded: {
6190 const access_kind: Builder.MemoryAccessKind =6196 const access_kind: Builder.MemoryAccessKind =
6191 if (err_union_ty.isVolatilePtr(zcu)) .@"volatile" else .normal;6197 if (err_union_ty.isVolatilePtr(zcu)) .@"volatile" else .normal;
61926198
6193 if (!payload_has_bits) {6199 if (!payload_has_bits) {
6194 // TODO add alignment to this load
6195 break :loaded if (operand_is_ptr)6200 break :loaded if (operand_is_ptr)
6196 try fg.wip.load(access_kind, error_type, err_union, .default, "")6201 try fg.wip.load(access_kind, error_type, err_union, err_set_align.toLlvm(), "")
6197 else6202 else
6198 err_union;6203 err_union;
6199 }6204 }
...@@ -6201,12 +6206,11 @@ pub const FuncGen = struct {...@@ -6201,12 +6206,11 @@ pub const FuncGen = struct {
6201 if (operand_is_ptr or isByRef(err_union_ty, zcu)) {6206 if (operand_is_ptr or isByRef(err_union_ty, zcu)) {
6202 const err_field_ptr =6207 const err_field_ptr =
6203 try fg.wip.gepStruct(err_union_llvm_ty, err_union, err_field_index, "");6208 try fg.wip.gepStruct(err_union_llvm_ty, err_union, err_field_index, "");
6204 // TODO add alignment to this load
6205 break :loaded try fg.wip.load(6209 break :loaded try fg.wip.load(
6206 if (operand_is_ptr) access_kind else .normal,6210 if (operand_is_ptr) access_kind else .normal,
6207 error_type,6211 error_type,
6208 err_field_ptr,6212 err_field_ptr,
6209 .default,6213 err_set_align.toLlvm(),
6210 "",6214 "",
6211 );6215 );
6212 }6216 }
...@@ -6232,15 +6236,14 @@ pub const FuncGen = struct {...@@ -6232,15 +6236,14 @@ pub const FuncGen = struct {
6232 return fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, "");6236 return fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, "");
6233 } else if (isByRef(err_union_ty, zcu)) {6237 } else if (isByRef(err_union_ty, zcu)) {
6234 const payload_ptr = try fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, "");6238 const payload_ptr = try fg.wip.gepStruct(err_union_llvm_ty, err_union, offset, "");
6235 const payload_alignment = payload_ty.abiAlignment(zcu).toLlvm();
6236 if (isByRef(payload_ty, zcu)) {6239 if (isByRef(payload_ty, zcu)) {
6237 if (can_elide_load)6240 if (can_elide_load)
6238 return payload_ptr;6241 return payload_ptr;
62396242
6240 return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal);6243 return fg.loadByRef(payload_ptr, payload_ty, payload_align.toLlvm(), .normal);
6241 }6244 }
6242 const load_ty = err_union_llvm_ty.structFields(&o.builder)[offset];6245 const load_ty = err_union_llvm_ty.structFields(&o.builder)[offset];
6243 return fg.wip.load(.normal, load_ty, payload_ptr, payload_alignment, "");6246 return fg.wip.load(.normal, load_ty, payload_ptr, payload_align.toLlvm(), "");
6244 }6247 }
6245 return fg.wip.extractValue(err_union, &.{offset}, "");6248 return fg.wip.extractValue(err_union, &.{offset}, "");
6246 }6249 }
...@@ -6713,20 +6716,20 @@ pub const FuncGen = struct {...@@ -6713,20 +6716,20 @@ pub const FuncGen = struct {
6713 const slice_ty = self.typeOf(bin_op.lhs);6716 const slice_ty = self.typeOf(bin_op.lhs);
6714 const slice = try self.resolveInst(bin_op.lhs);6717 const slice = try self.resolveInst(bin_op.lhs);
6715 const index = try self.resolveInst(bin_op.rhs);6718 const index = try self.resolveInst(bin_op.rhs);
6716 const elem_ty = slice_ty.childType(zcu);6719 const slice_info = slice_ty.ptrInfo(zcu);
6720 assert(slice_info.flags.size == .slice);
6721 const elem_ty: Type = .fromInterned(slice_info.child);
6717 const llvm_elem_ty = try o.lowerType(pt, elem_ty);6722 const llvm_elem_ty = try o.lowerType(pt, elem_ty);
6718 const base_ptr = try self.wip.extractValue(slice, &.{0}, "");6723 const base_ptr = try self.wip.extractValue(slice, &.{0}, "");
6719 const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");6724 const ptr = try self.wip.gep(.inbounds, llvm_elem_ty, base_ptr, &.{index}, "");
6725 const elem_align = slice_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu));
6726 const access_kind: Builder.MemoryAccessKind = if (slice_info.flags.is_volatile) .@"volatile" else .normal;
6727 self.maybeMarkAllowZeroAccess(slice_info);
6720 if (isByRef(elem_ty, zcu)) {6728 if (isByRef(elem_ty, zcu)) {
6721 self.maybeMarkAllowZeroAccess(slice_ty.ptrInfo(zcu));6729 return self.loadByRef(ptr, elem_ty, elem_align.toLlvm(), access_kind);
67226730 } else {
6723 const slice_align = (slice_ty.ptrAlignment(zcu).min(elem_ty.abiAlignment(zcu))).toLlvm();6731 return self.loadTruncate(access_kind, elem_ty, ptr, elem_align.toLlvm());
6724 return self.loadByRef(ptr, elem_ty, slice_align, if (slice_ty.isVolatilePtr(zcu)) .@"volatile" else .normal);
6725 }6732 }
6726
6727 self.maybeMarkAllowZeroAccess(slice_ty.ptrInfo(zcu));
6728
6729 return self.load(ptr, slice_ty);
6730 }6733 }
67316734
6732 fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {6735 fn airSliceElemPtr(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
...@@ -7507,7 +7510,7 @@ pub const FuncGen = struct {...@@ -7507,7 +7510,7 @@ pub const FuncGen = struct {
75077510
7508 if (optional_ty.optionalReprIsPayload(zcu)) {7511 if (optional_ty.optionalReprIsPayload(zcu)) {
7509 const loaded = if (operand_is_ptr)7512 const loaded = if (operand_is_ptr)
7510 try self.wip.load(access_kind, optional_llvm_ty, operand, .default, "")7513 try self.wip.load(access_kind, optional_llvm_ty, operand, operand_ty.ptrAlignment(zcu).toLlvm(), "")
7511 else7514 else
7512 operand;7515 operand;
7513 if (payload_ty.isSlice(zcu)) {7516 if (payload_ty.isSlice(zcu)) {
...@@ -7525,7 +7528,7 @@ pub const FuncGen = struct {...@@ -7525,7 +7528,7 @@ pub const FuncGen = struct {
75257528
7526 if (!payload_ty.hasRuntimeBits(zcu)) {7529 if (!payload_ty.hasRuntimeBits(zcu)) {
7527 const loaded = if (operand_is_ptr)7530 const loaded = if (operand_is_ptr)
7528 try self.wip.load(access_kind, optional_llvm_ty, operand, .default, "")7531 try self.wip.load(access_kind, optional_llvm_ty, operand, operand_ty.ptrAlignment(zcu).toLlvm(), "")
7529 else7532 else
7530 operand;7533 operand;
7531 return self.wip.icmp(cond, loaded, try o.builder.intValue(.i8, 0), "");7534 return self.wip.icmp(cond, loaded, try o.builder.intValue(.i8, 0), "");
...@@ -7568,7 +7571,7 @@ pub const FuncGen = struct {...@@ -7568,7 +7571,7 @@ pub const FuncGen = struct {
75687571
7569 if (!payload_ty.hasRuntimeBits(zcu)) {7572 if (!payload_ty.hasRuntimeBits(zcu)) {
7570 const loaded = if (operand_is_ptr)7573 const loaded = if (operand_is_ptr)
7571 try self.wip.load(access_kind, try o.lowerType(pt, err_union_ty), operand, .default, "")7574 try self.wip.load(access_kind, try o.lowerType(pt, err_union_ty), operand, operand_ty.ptrAlignment(zcu).toLlvm(), "")
7572 else7575 else
7573 operand;7576 operand;
7574 return self.wip.icmp(cond, loaded, zero, "");7577 return self.wip.icmp(cond, loaded, zero, "");
...@@ -7578,9 +7581,13 @@ pub const FuncGen = struct {...@@ -7578,9 +7581,13 @@ pub const FuncGen = struct {
75787581
7579 const loaded = if (operand_is_ptr or isByRef(err_union_ty, zcu)) loaded: {7582 const loaded = if (operand_is_ptr or isByRef(err_union_ty, zcu)) loaded: {
7580 const err_union_llvm_ty = try o.lowerType(pt, err_union_ty);7583 const err_union_llvm_ty = try o.lowerType(pt, err_union_ty);
7584 const err_alignment = if (operand_is_ptr)
7585 operand_ty.ptrAlignment(zcu).minStrict(Type.anyerror.abiAlignment(zcu))
7586 else
7587 .none;
7581 const err_field_ptr =7588 const err_field_ptr =
7582 try self.wip.gepStruct(err_union_llvm_ty, operand, err_field_index, "");7589 try self.wip.gepStruct(err_union_llvm_ty, operand, err_field_index, "");
7583 break :loaded try self.wip.load(access_kind, error_type, err_field_ptr, .default, "");7590 break :loaded try self.wip.load(access_kind, error_type, err_field_ptr, err_alignment.toLlvm(), "");
7584 } else try self.wip.extractValue(operand, &.{err_field_index}, "");7591 } else try self.wip.extractValue(operand, &.{err_field_index}, "");
7585 return self.wip.icmp(cond, loaded, zero, "");7592 return self.wip.icmp(cond, loaded, zero, "");
7586 }7593 }
...@@ -7625,6 +7632,7 @@ pub const FuncGen = struct {...@@ -7625,6 +7632,7 @@ pub const FuncGen = struct {
7625 self.maybeMarkAllowZeroAccess(optional_ptr_ty.ptrInfo(zcu));7632 self.maybeMarkAllowZeroAccess(optional_ptr_ty.ptrInfo(zcu));
76267633
7627 // We have a pointer to a i8. We need to set it to 1 and then return the same pointer.7634 // We have a pointer to a i8. We need to set it to 1 and then return the same pointer.
7635 // Default alignment store because align of the non null bit is 1 anyway.
7628 _ = try self.wip.store(access_kind, non_null_bit, operand, .default);7636 _ = try self.wip.store(access_kind, non_null_bit, operand, .default);
7629 return operand;7637 return operand;
7630 }7638 }
...@@ -7640,7 +7648,7 @@ pub const FuncGen = struct {...@@ -7640,7 +7648,7 @@ pub const FuncGen = struct {
76407648
7641 self.maybeMarkAllowZeroAccess(optional_ptr_ty.ptrInfo(zcu));7649 self.maybeMarkAllowZeroAccess(optional_ptr_ty.ptrInfo(zcu));
76427650
7643 // TODO set alignment on this store7651 // Default alignment store because align of the non null bit is 1 anyway.
7644 _ = try self.wip.store(access_kind, non_null_bit, non_null_ptr, .default);7652 _ = try self.wip.store(access_kind, non_null_bit, non_null_ptr, .default);
76457653
7646 // Then return the payload pointer (only if it's used).7654 // Then return the payload pointer (only if it's used).
...@@ -7728,7 +7736,7 @@ pub const FuncGen = struct {...@@ -7728,7 +7736,7 @@ pub const FuncGen = struct {
77287736
7729 self.maybeMarkAllowZeroAccess(operand_ty.ptrInfo(zcu));7737 self.maybeMarkAllowZeroAccess(operand_ty.ptrInfo(zcu));
77307738
7731 return self.wip.load(access_kind, error_type, operand, .default, "");7739 return self.wip.load(access_kind, error_type, operand, operand_ty.ptrAlignment(zcu).toLlvm(), "");
7732 }7740 }
77337741
7734 const offset = try errUnionErrorOffset(payload_ty, pt);7742 const offset = try errUnionErrorOffset(payload_ty, pt);
...@@ -7752,6 +7760,7 @@ pub const FuncGen = struct {...@@ -7752,6 +7760,7 @@ pub const FuncGen = struct {
7752 const operand = try self.resolveInst(ty_op.operand);7760 const operand = try self.resolveInst(ty_op.operand);
7753 const err_union_ptr_ty = self.typeOf(ty_op.operand);7761 const err_union_ptr_ty = self.typeOf(ty_op.operand);
7754 const err_union_ty = err_union_ptr_ty.childType(zcu);7762 const err_union_ty = err_union_ptr_ty.childType(zcu);
7763 const err_union_ptr_align = err_union_ptr_ty.ptrAlignment(zcu);
77557764
7756 const payload_ty = err_union_ty.errorUnionPayload(zcu);7765 const payload_ty = err_union_ty.errorUnionPayload(zcu);
7757 const non_error_val = try o.builder.intValue(try o.errorIntType(pt), 0);7766 const non_error_val = try o.builder.intValue(try o.errorIntType(pt), 0);
...@@ -7761,8 +7770,7 @@ pub const FuncGen = struct {...@@ -7761,8 +7770,7 @@ pub const FuncGen = struct {
77617770
7762 if (!payload_ty.hasRuntimeBits(zcu)) {7771 if (!payload_ty.hasRuntimeBits(zcu)) {
7763 self.maybeMarkAllowZeroAccess(err_union_ptr_ty.ptrInfo(zcu));7772 self.maybeMarkAllowZeroAccess(err_union_ptr_ty.ptrInfo(zcu));
77647773 _ = try self.wip.store(access_kind, non_error_val, operand, err_union_ptr_align.toLlvm());
7765 _ = try self.wip.store(access_kind, non_error_val, operand, .default);
7766 return operand;7774 return operand;
7767 }7775 }
7768 const err_union_llvm_ty = try o.lowerType(pt, err_union_ty);7776 const err_union_llvm_ty = try o.lowerType(pt, err_union_ty);
...@@ -7770,7 +7778,7 @@ pub const FuncGen = struct {...@@ -7770,7 +7778,7 @@ pub const FuncGen = struct {
7770 self.maybeMarkAllowZeroAccess(err_union_ptr_ty.ptrInfo(zcu));7778 self.maybeMarkAllowZeroAccess(err_union_ptr_ty.ptrInfo(zcu));
77717779
7772 const err_int_ty = try pt.errorIntType();7780 const err_int_ty = try pt.errorIntType();
7773 const error_alignment = err_int_ty.abiAlignment(zcu).toLlvm();7781 const error_alignment = err_int_ty.abiAlignment(zcu).minStrict(err_union_ptr_align).toLlvm();
7774 const error_offset = try errUnionErrorOffset(payload_ty, pt);7782 const error_offset = try errUnionErrorOffset(payload_ty, pt);
7775 // First set the non-error value.7783 // First set the non-error value.
7776 const non_null_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, error_offset, "");7784 const non_null_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, error_offset, "");
...@@ -8451,9 +8459,8 @@ pub const FuncGen = struct {...@@ -8451,9 +8459,8 @@ pub const FuncGen = struct {
8451 _ = try self.wip.store(.normal, result_val, field_ptr, result_alignment);8459 _ = try self.wip.store(.normal, result_val, field_ptr, result_alignment);
8452 }8460 }
8453 {8461 {
8454 const overflow_alignment = comptime Builder.Alignment.fromByteUnits(1);
8455 const field_ptr = try self.wip.gepStruct(llvm_inst_ty, alloca_inst, overflow_index, "");8462 const field_ptr = try self.wip.gepStruct(llvm_inst_ty, alloca_inst, overflow_index, "");
8456 _ = try self.wip.store(.normal, overflow_bit, field_ptr, overflow_alignment);8463 _ = try self.wip.store(.normal, overflow_bit, field_ptr, comptime .fromByteUnits(1));
8457 }8464 }
84588465
8459 return alloca_inst;8466 return alloca_inst;
...@@ -8813,9 +8820,8 @@ pub const FuncGen = struct {...@@ -8813,9 +8820,8 @@ pub const FuncGen = struct {
8813 _ = try self.wip.store(.normal, result, field_ptr, result_alignment);8820 _ = try self.wip.store(.normal, result, field_ptr, result_alignment);
8814 }8821 }
8815 {8822 {
8816 const field_alignment = comptime Builder.Alignment.fromByteUnits(1);
8817 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, overflow_index, "");8823 const field_ptr = try self.wip.gepStruct(llvm_dest_ty, alloca_inst, overflow_index, "");
8818 _ = try self.wip.store(.normal, overflow_bit, field_ptr, field_alignment);8824 _ = try self.wip.store(.normal, overflow_bit, field_ptr, comptime .fromByteUnits(1));
8819 }8825 }
8820 return alloca_inst;8826 return alloca_inst;
8821 }8827 }
...@@ -9971,15 +9977,18 @@ pub const FuncGen = struct {...@@ -9971,15 +9977,18 @@ pub const FuncGen = struct {
99719977
9972 const union_ptr = try self.resolveInst(bin_op.lhs);9978 const union_ptr = try self.resolveInst(bin_op.lhs);
9973 const new_tag = try self.resolveInst(bin_op.rhs);9979 const new_tag = try self.resolveInst(bin_op.rhs);
9980 const union_ptr_align = un_ptr_ty.ptrAlignment(zcu);
9974 if (layout.payload_size == 0) {9981 if (layout.payload_size == 0) {
9975 // TODO alignment on this store9982 _ = try self.wip.store(access_kind, new_tag, union_ptr, union_ptr_align.toLlvm());
9976 _ = try self.wip.store(access_kind, new_tag, union_ptr, .default);
9977 return .none;9983 return .none;
9978 }9984 }
9979 const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align));9985 const tag_index = @intFromBool(layout.tag_align.compare(.lt, layout.payload_align));
9980 const tag_field_ptr = try self.wip.gepStruct(try o.lowerType(pt, un_ty), union_ptr, tag_index, "");9986 const tag_field_ptr = try self.wip.gepStruct(try o.lowerType(pt, un_ty), union_ptr, tag_index, "");
9981 // TODO alignment on this store9987 const tag_ptr_align: InternPool.Alignment = switch (layout.tagOffset()) {
9982 _ = try self.wip.store(access_kind, new_tag, tag_field_ptr, .default);9988 0 => union_ptr_align,
9989 else => |off| .minStrict(union_ptr_align, .fromLog2Units(@ctz(off))),
9990 };
9991 _ = try self.wip.store(access_kind, new_tag, tag_field_ptr, tag_ptr_align.toLlvm());
9983 return .none;9992 return .none;
9984 }9993 }
99859994