authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-19 15:10:35-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-21 21:38:41-04:00
log7bab406c790566781406a7968be22961ed7c305d
treee2f778d1c66dd62bf41da837bb76a882b792ec6e
parent5aa82ed477b85cf8681bc0dc65f97e813990a2ed

InternPool: store alignment of anon decls

Commit 5393e56500d499753dbc39704c0161b47d1e4d5c has a flaw pointed out by @mlugg: the `ty` field of pointer values changes when comptime values are pointer-casted. This commit introduces a new encoding which additionally stores the "original pointer type" which is used to store the alignment of the anonymous decl, and potentially other information in the future such as section and pointer address space. However, this new encoding is only used when the original pointer type differs from the casted pointer type in a meaningful way. I was able to make the LLVM backend and the C backend lower anonymous decls with the appropriate alignment, however I will need some help figuring out how to do this for the backends that lower anonymous decls via src/codegen.zig and the wasm backend.

13 files changed, 189 insertions(+), 44 deletions(-)

src/Compilation.zig+1
......@@ -3545,6 +3545,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
35453545 .fwd_decl = fwd_decl.toManaged(gpa),
35463546 .ctypes = .{},
35473547 .anon_decl_deps = .{},
3548 .aligned_anon_decls = .{},
35483549 };
35493550 defer {
35503551 dg.ctypes.deinit(gpa);
src/InternPool.zig+86-14
......@@ -1074,7 +1074,7 @@ pub const Key = union(enum) {
10741074
10751075 decl: Module.Decl.Index,
10761076 mut_decl: MutDecl,
1077 anon_decl: Index,
1077 anon_decl: AnonDecl,
10781078 comptime_field: Index,
10791079 int: Index,
10801080 eu_payload: Index,
......@@ -1090,6 +1090,14 @@ pub const Key = union(enum) {
10901090 base: Index,
10911091 index: u64,
10921092 };
1093 pub const AnonDecl = extern struct {
1094 val: Index,
1095 /// Contains the canonical pointer type of the anonymous
1096 /// declaration. This may equal `ty` of the `Ptr` or it may be
1097 /// different. Importantly, when lowering the anonymous decl,
1098 /// the original pointer type alignment must be used.
1099 orig_ty: Index,
1100 };
10931101 };
10941102 };
10951103
......@@ -1231,7 +1239,8 @@ pub const Key = union(enum) {
12311239 common ++ asBytes(&x.decl) ++ asBytes(&x.runtime_index),
12321240 ),
12331241
1234 .anon_decl,
1242 .anon_decl => |x| Hash.hash(seed2, common ++ asBytes(&x)),
1243
12351244 .int,
12361245 .eu_payload,
12371246 .opt_payload,
......@@ -1500,7 +1509,8 @@ pub const Key = union(enum) {
15001509 return switch (a_info.addr) {
15011510 .decl => |a_decl| a_decl == b_info.addr.decl,
15021511 .mut_decl => |a_mut_decl| std.meta.eql(a_mut_decl, b_info.addr.mut_decl),
1503 .anon_decl => |a_decl| a_decl == b_info.addr.anon_decl,
1512 .anon_decl => |ad| ad.val == b_info.addr.anon_decl.val and
1513 ad.orig_ty == b_info.addr.anon_decl.orig_ty,
15041514 .int => |a_int| a_int == b_info.addr.int,
15051515 .eu_payload => |a_eu_payload| a_eu_payload == b_info.addr.eu_payload,
15061516 .opt_payload => |a_opt_payload| a_opt_payload == b_info.addr.opt_payload,
......@@ -2133,6 +2143,7 @@ pub const Index = enum(u32) {
21332143 ptr_decl: struct { data: *PtrDecl },
21342144 ptr_mut_decl: struct { data: *PtrMutDecl },
21352145 ptr_anon_decl: struct { data: *PtrAnonDecl },
2146 ptr_anon_decl_aligned: struct { data: *PtrAnonDeclAligned },
21362147 ptr_comptime_field: struct { data: *PtrComptimeField },
21372148 ptr_int: struct { data: *PtrBase },
21382149 ptr_eu_payload: struct { data: *PtrBase },
......@@ -2583,8 +2594,16 @@ pub const Tag = enum(u8) {
25832594 /// data is extra index of `PtrMutDecl`, which contains the type and address.
25842595 ptr_mut_decl,
25852596 /// A pointer to an anonymous decl.
2586 /// data is extra index of `PtrAnonDecl`, which contains the type and decl value.
2597 /// data is extra index of `PtrAnonDecl`, which contains the pointer type and decl value.
2598 /// The alignment of the anonymous decl is communicated via the pointer type.
25872599 ptr_anon_decl,
2600 /// A pointer to an anonymous decl.
2601 /// data is extra index of `PtrAnonDeclAligned`, which contains the pointer
2602 /// type and decl value.
2603 /// The original pointer type is also provided, which will be different than `ty`.
2604 /// This encoding is only used when a pointer to an anonymous decl is
2605 /// coerced to a different pointer type with a different alignment.
2606 ptr_anon_decl_aligned,
25882607 /// data is extra index of `PtrComptimeField`, which contains the pointer type and field value.
25892608 ptr_comptime_field,
25902609 /// A pointer with an integer value.
......@@ -2781,6 +2800,7 @@ pub const Tag = enum(u8) {
27812800 .ptr_decl => PtrDecl,
27822801 .ptr_mut_decl => PtrMutDecl,
27832802 .ptr_anon_decl => PtrAnonDecl,
2803 .ptr_anon_decl_aligned => PtrAnonDeclAligned,
27842804 .ptr_comptime_field => PtrComptimeField,
27852805 .ptr_int => PtrBase,
27862806 .ptr_eu_payload => PtrBase,
......@@ -3383,6 +3403,13 @@ pub const PtrAnonDecl = struct {
33833403 val: Index,
33843404};
33853405
3406pub const PtrAnonDeclAligned = struct {
3407 ty: Index,
3408 val: Index,
3409 /// Must be nonequal to `ty`. Only the alignment from this value is important.
3410 orig_ty: Index,
3411};
3412
33863413pub const PtrMutDecl = struct {
33873414 ty: Index,
33883415 decl: Module.Decl.Index,
......@@ -3736,7 +3763,20 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
37363763 const info = ip.extraData(PtrAnonDecl, data);
37373764 return .{ .ptr = .{
37383765 .ty = info.ty,
3739 .addr = .{ .anon_decl = info.val },
3766 .addr = .{ .anon_decl = .{
3767 .val = info.val,
3768 .orig_ty = info.ty,
3769 } },
3770 } };
3771 },
3772 .ptr_anon_decl_aligned => {
3773 const info = ip.extraData(PtrAnonDeclAligned, data);
3774 return .{ .ptr = .{
3775 .ty = info.ty,
3776 .addr = .{ .anon_decl = .{
3777 .val = info.val,
3778 .orig_ty = info.orig_ty,
3779 } },
37403780 } };
37413781 },
37423782 .ptr_comptime_field => {
......@@ -3817,7 +3857,17 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
38173857 } };
38183858 },
38193859 .ptr_anon_decl => .{
3820 .anon_decl = ip.extraData(PtrAnonDecl, ptr_item.data).val,
3860 .anon_decl = .{
3861 .val = ip.extraData(PtrAnonDecl, ptr_item.data).val,
3862 .orig_ty = info.ty,
3863 },
3864 },
3865 .ptr_anon_decl_aligned => b: {
3866 const sub_info = ip.extraData(PtrAnonDeclAligned, ptr_item.data);
3867 break :b .{ .anon_decl = .{
3868 .val = sub_info.val,
3869 .orig_ty = sub_info.orig_ty,
3870 } };
38213871 },
38223872 .ptr_comptime_field => .{
38233873 .comptime_field = ip.extraData(PtrComptimeField, ptr_item.data).field_val,
......@@ -4571,13 +4621,22 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
45714621 .runtime_index = mut_decl.runtime_index,
45724622 }),
45734623 }),
4574 .anon_decl => |anon_decl| ip.items.appendAssumeCapacity(.{
4575 .tag = .ptr_anon_decl,
4576 .data = try ip.addExtra(gpa, PtrAnonDecl{
4577 .ty = ptr.ty,
4578 .val = anon_decl,
4579 }),
4580 }),
4624 .anon_decl => |anon_decl| ip.items.appendAssumeCapacity(
4625 if (ptrsHaveSameAlignment(ip, ptr.ty, ptr_type, anon_decl.orig_ty)) .{
4626 .tag = .ptr_anon_decl,
4627 .data = try ip.addExtra(gpa, PtrAnonDecl{
4628 .ty = ptr.ty,
4629 .val = anon_decl.val,
4630 }),
4631 } else .{
4632 .tag = .ptr_anon_decl_aligned,
4633 .data = try ip.addExtra(gpa, PtrAnonDeclAligned{
4634 .ty = ptr.ty,
4635 .val = anon_decl.val,
4636 .orig_ty = anon_decl.orig_ty,
4637 }),
4638 },
4639 ),
45814640 .comptime_field => |field_val| {
45824641 assert(field_val != .none);
45834642 ip.items.appendAssumeCapacity(.{
......@@ -7184,6 +7243,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
71847243 .ptr_decl => @sizeOf(PtrDecl),
71857244 .ptr_mut_decl => @sizeOf(PtrMutDecl),
71867245 .ptr_anon_decl => @sizeOf(PtrAnonDecl),
7246 .ptr_anon_decl_aligned => @sizeOf(PtrAnonDeclAligned),
71877247 .ptr_comptime_field => @sizeOf(PtrComptimeField),
71887248 .ptr_int => @sizeOf(PtrBase),
71897249 .ptr_eu_payload => @sizeOf(PtrBase),
......@@ -7314,6 +7374,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
73147374 .ptr_decl,
73157375 .ptr_mut_decl,
73167376 .ptr_anon_decl,
7377 .ptr_anon_decl_aligned,
73177378 .ptr_comptime_field,
73187379 .ptr_int,
73197380 .ptr_eu_payload,
......@@ -7695,6 +7756,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
76957756 inline .ptr_decl,
76967757 .ptr_mut_decl,
76977758 .ptr_anon_decl,
7759 .ptr_anon_decl_aligned,
76987760 .ptr_comptime_field,
76997761 .ptr_int,
77007762 .ptr_eu_payload,
......@@ -7855,7 +7917,7 @@ pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.Addr.Tag {
78557917 switch (ip.items.items(.tag)[base]) {
78567918 .ptr_decl => return .decl,
78577919 .ptr_mut_decl => return .mut_decl,
7858 .ptr_anon_decl => return .anon_decl,
7920 .ptr_anon_decl, .ptr_anon_decl_aligned => return .anon_decl,
78597921 .ptr_comptime_field => return .comptime_field,
78607922 .ptr_int => return .int,
78617923 inline .ptr_eu_payload,
......@@ -8032,6 +8094,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
80328094 .ptr_decl,
80338095 .ptr_mut_decl,
80348096 .ptr_anon_decl,
8097 .ptr_anon_decl_aligned,
80358098 .ptr_comptime_field,
80368099 .ptr_int,
80378100 .ptr_eu_payload,
......@@ -8281,3 +8344,12 @@ pub fn addFieldName(
82818344 ip.extra.items[names_start + field_index] = @intFromEnum(name);
82828345 return null;
82838346}
8347
8348/// Used only by `get` for pointer values, and mainly intended to use `Tag.ptr_anon_decl`
8349/// encoding instead of `Tag.ptr_anon_decl_aligned` when possible.
8350fn ptrsHaveSameAlignment(ip: *InternPool, a_ty: Index, a_info: Key.PtrType, b_ty: Index) bool {
8351 if (a_ty == b_ty) return true;
8352 const b_info = ip.indexToKey(b_ty).ptr_type;
8353 return a_info.flags.alignment == b_info.flags.alignment and
8354 (a_info.child == b_info.child or a_info.flags.alignment != .none);
8355}
src/Sema.zig+11-3
......@@ -3659,7 +3659,10 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
36593659 if (try sema.resolveComptimeKnownAllocValue(block, alloc, null)) |val| {
36603660 const new_mut_ptr = Air.internedToRef((try mod.intern(.{ .ptr = .{
36613661 .ty = alloc_ty.toIntern(),
3662 .addr = .{ .anon_decl = val },
3662 .addr = .{ .anon_decl = .{
3663 .val = val,
3664 .orig_ty = alloc_ty.toIntern(),
3665 } },
36633666 } })));
36643667 return sema.makePtrConst(block, new_mut_ptr);
36653668 }
......@@ -5540,7 +5543,10 @@ fn addStrLitNoAlias(sema: *Sema, bytes: []const u8) CompileError!Air.Inst.Ref {
55405543 });
55415544 return Air.internedToRef((try mod.intern(.{ .ptr = .{
55425545 .ty = ptr_ty.toIntern(),
5543 .addr = .{ .anon_decl = val },
5546 .addr = .{ .anon_decl = .{
5547 .val = val,
5548 .orig_ty = ptr_ty.toIntern(),
5549 } },
55445550 } })));
55455551}
55465552
......@@ -30546,7 +30552,8 @@ fn beginComptimePtrLoad(
3054630552 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
3054730553 };
3054830554 },
30549 .anon_decl => |decl_val| blk: {
30555 .anon_decl => |anon_decl| blk: {
30556 const decl_val = anon_decl.val;
3055030557 if (decl_val.toValue().getVariable(mod) != null) return error.RuntimeLoad;
3055130558 const decl_ty = ip.typeOf(decl_val).toType();
3055230559 const decl_tv: TypedValue = .{ .ty = decl_ty, .val = decl_val.toValue() };
......@@ -36650,6 +36657,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3665036657 .simple_value,
3665136658 .ptr_decl,
3665236659 .ptr_anon_decl,
36660 .ptr_anon_decl_aligned,
3665336661 .ptr_mut_decl,
3665436662 .ptr_comptime_field,
3665536663 .ptr_int,
src/TypedValue.zig+2-1
......@@ -321,7 +321,8 @@ pub fn print(
321321 .val = decl.val,
322322 }, writer, level - 1, mod);
323323 },
324 .anon_decl => |decl_val| {
324 .anon_decl => |anon_decl| {
325 const decl_val = anon_decl.val;
325326 if (level == 0) return writer.print("(anon decl '{d}')", .{
326327 @intFromEnum(decl_val),
327328 });
src/arch/wasm/CodeGen.zig+13-4
......@@ -3139,16 +3139,25 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In
31393139 return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset);
31403140}
31413141
3142fn lowerAnonDeclRef(func: *CodeGen, anon_decl: InternPool.Index, offset: u32) InnerError!WValue {
3142fn lowerAnonDeclRef(
3143 func: *CodeGen,
3144 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
3145 offset: u32,
3146) InnerError!WValue {
31433147 const mod = func.bin_file.base.options.module.?;
3144 const ty = mod.intern_pool.typeOf(anon_decl).toType();
3148 const decl_val = anon_decl.val;
3149 const ty = mod.intern_pool.typeOf(decl_val).toType();
31453150
31463151 const is_fn_body = ty.zigTypeTag(mod) == .Fn;
31473152 if (!is_fn_body and !ty.hasRuntimeBitsIgnoreComptime(mod)) {
31483153 return WValue{ .imm32 = 0xaaaaaaaa };
31493154 }
31503155
3151 const res = try func.bin_file.lowerAnonDecl(anon_decl, func.decl.srcLoc(mod));
3156 const alignment = mod.intern_pool.indexToKey(anon_decl.orig_ty).ptr_type.flags.alignment;
3157 if (alignment != .none) {
3158 @panic("TODO how to make this anon decl be aligned?");
3159 }
3160 const res = try func.bin_file.lowerAnonDecl(decl_val, func.decl.srcLoc(mod));
31523161 switch (res) {
31533162 .ok => {},
31543163 .fail => |em| {
......@@ -3156,7 +3165,7 @@ fn lowerAnonDeclRef(func: *CodeGen, anon_decl: InternPool.Index, offset: u32) In
31563165 return error.CodegenFail;
31573166 },
31583167 }
3159 const target_atom_index = func.bin_file.anon_decls.get(anon_decl).?;
3168 const target_atom_index = func.bin_file.anon_decls.get(decl_val).?;
31603169 const target_sym_index = func.bin_file.getAtom(target_atom_index).getSymbolIndex().?;
31613170 if (is_fn_body) {
31623171 return WValue{ .function_index = target_sym_index };
src/codegen.zig+6-1
......@@ -713,7 +713,7 @@ const RelocInfo = struct {
713713fn lowerAnonDeclRef(
714714 bin_file: *link.File,
715715 src_loc: Module.SrcLoc,
716 decl_val: InternPool.Index,
716 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
717717 code: *std.ArrayList(u8),
718718 debug_output: DebugInfoOutput,
719719 reloc_info: RelocInfo,
......@@ -723,6 +723,7 @@ fn lowerAnonDeclRef(
723723 const mod = bin_file.options.module.?;
724724
725725 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
726 const decl_val = anon_decl.val;
726727 const decl_ty = mod.intern_pool.typeOf(decl_val).toType();
727728 const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
728729 if (!is_fn_body and !decl_ty.hasRuntimeBits(mod)) {
......@@ -736,6 +737,10 @@ fn lowerAnonDeclRef(
736737 .fail => |em| return .{ .fail = em },
737738 }
738739
740 const alignment = mod.intern_pool.indexToKey(anon_decl.orig_ty).ptr_type.flags.alignment;
741 if (alignment != .none) {
742 @panic("TODO how to make this anon decl be aligned?");
743 }
739744 const vaddr = try bin_file.getAnonDeclVAddr(decl_val, .{
740745 .parent_atom_index = reloc_info.parent_atom_index,
741746 .offset = code.items.len,
src/codegen/c.zig+19-2
......@@ -531,6 +531,7 @@ pub const DeclGen = struct {
531531 /// Keeps track of anonymous decls that need to be rendered before this
532532 /// (named) Decl in the output C code.
533533 anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, C.DeclBlock),
534 aligned_anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment),
534535
535536 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
536537 @setCold(true);
......@@ -548,11 +549,12 @@ pub const DeclGen = struct {
548549 writer: anytype,
549550 ty: Type,
550551 ptr_val: Value,
551 decl_val: InternPool.Index,
552 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
552553 location: ValueRenderLocation,
553554 ) error{ OutOfMemory, AnalysisFail }!void {
554555 const mod = dg.module;
555556 const ip = &mod.intern_pool;
557 const decl_val = anon_decl.val;
556558 const decl_ty = ip.typeOf(decl_val).toType();
557559
558560 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
......@@ -592,8 +594,23 @@ pub const DeclGen = struct {
592594
593595 // Indicate that the anon decl should be rendered to the output so that
594596 // our reference above is not undefined.
597 const ptr_type = ip.indexToKey(anon_decl.orig_ty).ptr_type;
595598 const gop = try dg.anon_decl_deps.getOrPut(dg.gpa, decl_val);
596599 if (!gop.found_existing) gop.value_ptr.* = .{};
600
601 // Only insert an alignment entry if the alignment is greater than ABI
602 // alignment. If there is already an entry, keep the greater alignment.
603 const explicit_alignment = ptr_type.flags.alignment;
604 if (explicit_alignment != .none) {
605 const abi_alignment = ptr_type.child.toType().abiAlignment(mod);
606 if (explicit_alignment.compareStrict(.gt, abi_alignment)) {
607 const aligned_gop = try dg.aligned_anon_decls.getOrPut(dg.gpa, decl_val);
608 aligned_gop.value_ptr.* = if (aligned_gop.found_existing)
609 aligned_gop.value_ptr.maxStrict(explicit_alignment)
610 else
611 explicit_alignment;
612 }
613 }
597614 }
598615
599616 fn renderDeclValue(
......@@ -651,7 +668,7 @@ pub const DeclGen = struct {
651668 switch (ptr.addr) {
652669 .decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), d, location),
653670 .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), md.decl, location),
654 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val.toValue(), decl_val, location),
671 .anon_decl => |anon_decl| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val.toValue(), anon_decl, location),
655672 .int => |int| {
656673 try writer.writeByte('(');
657674 try dg.renderCType(writer, ptr_cty);
src/codegen/llvm.zig+16-15
......@@ -3051,9 +3051,17 @@ pub const Object = struct {
30513051 llvm_addr_space: Builder.AddrSpace,
30523052 alignment: InternPool.Alignment,
30533053 ) Error!Builder.Variable.Index {
3054 assert(alignment != .none);
30543055 // TODO: Add address space to the anon_decl_map
30553056 const gop = try o.anon_decl_map.getOrPut(o.gpa, decl_val);
3056 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.variable;
3057 if (gop.found_existing) {
3058 // Keep the greater of the two alignments.
3059 const variable_index = gop.value_ptr.ptr(&o.builder).kind.variable;
3060 const old_alignment = InternPool.Alignment.fromLlvm(variable_index.getAlignment(&o.builder));
3061 const max_alignment = old_alignment.maxStrict(alignment);
3062 variable_index.setAlignment(max_alignment.toLlvm(), &o.builder);
3063 return variable_index;
3064 }
30573065 errdefer assert(o.anon_decl_map.remove(decl_val));
30583066
30593067 const mod = o.module;
......@@ -3069,8 +3077,7 @@ pub const Object = struct {
30693077 try variable_index.setInitializer(try o.lowerValue(decl_val), &o.builder);
30703078 variable_index.setLinkage(.internal, &o.builder);
30713079 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
3072 if (alignment != .none)
3073 variable_index.setAlignment(alignment.toLlvm(), &o.builder);
3080 variable_index.setAlignment(alignment.toLlvm(), &o.builder);
30743081 return variable_index;
30753082 }
30763083
......@@ -4253,13 +4260,6 @@ pub const Object = struct {
42534260 return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint);
42544261 }
42554262
4256 fn lowerParentPtrAnonDecl(o: *Object, decl_val: InternPool.Index) Error!Builder.Constant {
4257 const mod = o.module;
4258 const decl_ty = mod.intern_pool.typeOf(decl_val).toType();
4259 const ptr_ty = try mod.singleMutPtrType(decl_ty);
4260 return o.lowerAnonDeclRef(ptr_ty, decl_val);
4261 }
4262
42634263 fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {
42644264 const mod = o.module;
42654265 const decl = mod.declPtr(decl_index);
......@@ -4275,7 +4275,7 @@ pub const Object = struct {
42754275 return switch (ptr.addr) {
42764276 .decl => |decl| try o.lowerParentPtrDecl(decl),
42774277 .mut_decl => |mut_decl| try o.lowerParentPtrDecl(mut_decl.decl),
4278 .anon_decl => |anon_decl| try o.lowerParentPtrAnonDecl(anon_decl),
4278 .anon_decl => |ad| try o.lowerAnonDeclRef(ad.orig_ty.toType(), ad),
42794279 .int => |int| try o.lowerIntAsPtr(int),
42804280 .eu_payload => |eu_ptr| {
42814281 const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue());
......@@ -4394,10 +4394,11 @@ pub const Object = struct {
43944394 fn lowerAnonDeclRef(
43954395 o: *Object,
43964396 ptr_ty: Type,
4397 decl_val: InternPool.Index,
4397 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
43984398 ) Error!Builder.Constant {
43994399 const mod = o.module;
44004400 const ip = &mod.intern_pool;
4401 const decl_val = anon_decl.val;
44014402 const decl_ty = ip.typeOf(decl_val).toType();
44024403 const target = mod.getTarget();
44034404
......@@ -4416,9 +4417,9 @@ pub const Object = struct {
44164417 if (is_fn_body)
44174418 @panic("TODO");
44184419
4419 const addr_space = target_util.defaultAddressSpace(target, .global_constant);
4420 const llvm_addr_space = toLlvmAddressSpace(addr_space, target);
4421 const alignment = ptr_ty.ptrAlignment(mod);
4420 const orig_ty = anon_decl.orig_ty.toType();
4421 const llvm_addr_space = toLlvmAddressSpace(orig_ty.ptrAddressSpace(mod), target);
4422 const alignment = orig_ty.ptrAlignment(mod);
44224423 const llvm_global = (try o.resolveGlobalAnonDecl(decl_val, llvm_addr_space, alignment)).ptrConst(&o.builder).global;
44234424
44244425 const llvm_val = try o.builder.convConst(
src/codegen/llvm/Builder.zig+6
......@@ -2477,6 +2477,12 @@ pub const Variable = struct {
24772477 self.ptr(builder).alignment = alignment;
24782478 }
24792479
2480 pub fn getAlignment(self: Index, builder: *Builder) Alignment {
2481 if (builder.useLibLlvm())
2482 return Alignment.fromByteUnits(self.toLlvm(builder).getAlignment());
2483 return self.ptr(builder).alignment;
2484 }
2485
24802486 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
24812487 return self.ptrConst(builder).global.toLlvm(builder);
24822488 }
src/codegen/llvm/bindings.zig+3
......@@ -273,6 +273,9 @@ pub const Value = opaque {
273273 pub const setAlignment = LLVMSetAlignment;
274274 extern fn LLVMSetAlignment(V: *Value, Bytes: c_uint) void;
275275
276 pub const getAlignment = LLVMGetAlignment;
277 extern fn LLVMGetAlignment(V: *Value) c_uint;
278
276279 pub const setFunctionCallConv = LLVMSetFunctionCallConv;
277280 extern fn LLVMSetFunctionCallConv(Fn: *Value, CC: CallConv) void;
278281
src/codegen/spirv.zig+6-1
......@@ -959,12 +959,17 @@ const DeclGen = struct {
959959 }
960960 }
961961
962 fn constantAnonDeclRef(self: *DeclGen, ty: Type, decl_val: InternPool.Index) !IdRef {
962 fn constantAnonDeclRef(
963 self: *DeclGen,
964 ty: Type,
965 anon_decl: InternPool.Key.Ptr.Addr.AnonDecl,
966 ) !IdRef {
963967 // TODO: Merge this function with constantDeclRef.
964968
965969 const mod = self.module;
966970 const ip = &mod.intern_pool;
967971 const ty_ref = try self.resolveType(ty, .direct);
972 const decl_val = anon_decl.val;
968973 const decl_ty = ip.typeOf(decl_val).toType();
969974
970975 if (decl_val.toValue().getFunction(mod)) |func| {
src/link/C.zig+18-1
......@@ -7,6 +7,7 @@ const fs = std.fs;
77const C = @This();
88const Module = @import("../Module.zig");
99const InternPool = @import("../InternPool.zig");
10const Alignment = InternPool.Alignment;
1011const Compilation = @import("../Compilation.zig");
1112const codegen = @import("../codegen/c.zig");
1213const link = @import("../link.zig");
......@@ -30,6 +31,10 @@ string_bytes: std.ArrayListUnmanaged(u8) = .{},
3031/// Tracks all the anonymous decls that are used by all the decls so they can
3132/// be rendered during flush().
3233anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, DeclBlock) = .{},
34/// Sparse set of anon decls that are overaligned. Underaligned anon decls are
35/// lowered the same as ABI-aligned anon decls. The keys here are a subset of
36/// the keys of `anon_decls`.
37aligned_anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment) = .{},
3338
3439/// Optimization, `updateDecl` reuses this buffer rather than creating a new
3540/// one with every call.
......@@ -125,6 +130,7 @@ pub fn deinit(self: *C) void {
125130 db.deinit(gpa);
126131 }
127132 self.anon_decls.deinit(gpa);
133 self.aligned_anon_decls.deinit(gpa);
128134
129135 self.string_bytes.deinit(gpa);
130136 self.fwd_decl_buf.deinit(gpa);
......@@ -179,6 +185,7 @@ pub fn updateFunc(
179185 .fwd_decl = fwd_decl.toManaged(gpa),
180186 .ctypes = ctypes.*,
181187 .anon_decl_deps = self.anon_decls,
188 .aligned_anon_decls = self.aligned_anon_decls,
182189 },
183190 .code = code.toManaged(gpa),
184191 .indent_writer = undefined, // set later so we can get a pointer to object.code
......@@ -189,6 +196,7 @@ pub fn updateFunc(
189196 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
190197 defer {
191198 self.anon_decls = function.object.dg.anon_decl_deps;
199 self.aligned_anon_decls = function.object.dg.aligned_anon_decls;
192200 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
193201 code.* = function.object.code.moveToUnmanaged();
194202 function.deinit();
......@@ -232,6 +240,7 @@ fn updateAnonDecl(self: *C, module: *Module, i: usize) !void {
232240 .fwd_decl = fwd_decl.toManaged(gpa),
233241 .ctypes = .{},
234242 .anon_decl_deps = self.anon_decls,
243 .aligned_anon_decls = self.aligned_anon_decls,
235244 },
236245 .code = code.toManaged(gpa),
237246 .indent_writer = undefined, // set later so we can get a pointer to object.code
......@@ -240,6 +249,7 @@ fn updateAnonDecl(self: *C, module: *Module, i: usize) !void {
240249
241250 defer {
242251 self.anon_decls = object.dg.anon_decl_deps;
252 self.aligned_anon_decls = object.dg.aligned_anon_decls;
243253 object.dg.ctypes.deinit(object.dg.gpa);
244254 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
245255 code.* = object.code.moveToUnmanaged();
......@@ -250,7 +260,8 @@ fn updateAnonDecl(self: *C, module: *Module, i: usize) !void {
250260 .val = anon_decl.toValue(),
251261 };
252262 const c_value: codegen.CValue = .{ .constant = anon_decl };
253 codegen.genDeclValue(&object, tv, false, c_value, .none, .none) catch |err| switch (err) {
263 const alignment: Alignment = self.aligned_anon_decls.get(anon_decl) orelse .none;
264 codegen.genDeclValue(&object, tv, false, c_value, alignment, .none) catch |err| switch (err) {
254265 error.AnalysisFail => {
255266 @panic("TODO: C backend AnalysisFail on anonymous decl");
256267 //try module.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
......@@ -296,6 +307,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
296307 .fwd_decl = fwd_decl.toManaged(gpa),
297308 .ctypes = ctypes.*,
298309 .anon_decl_deps = self.anon_decls,
310 .aligned_anon_decls = self.aligned_anon_decls,
299311 },
300312 .code = code.toManaged(gpa),
301313 .indent_writer = undefined, // set later so we can get a pointer to object.code
......@@ -303,6 +315,7 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
303315 object.indent_writer = .{ .underlying_writer = object.code.writer() };
304316 defer {
305317 self.anon_decls = object.dg.anon_decl_deps;
318 self.aligned_anon_decls = object.dg.aligned_anon_decls;
306319 object.dg.ctypes.deinit(object.dg.gpa);
307320 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
308321 code.* = object.code.moveToUnmanaged();
......@@ -602,6 +615,7 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
602615 .fwd_decl = fwd_decl.toManaged(gpa),
603616 .ctypes = ctypes.*,
604617 .anon_decl_deps = self.anon_decls,
618 .aligned_anon_decls = self.aligned_anon_decls,
605619 },
606620 .code = code.toManaged(gpa),
607621 .indent_writer = undefined, // set later so we can get a pointer to object.code
......@@ -609,6 +623,7 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
609623 object.indent_writer = .{ .underlying_writer = object.code.writer() };
610624 defer {
611625 self.anon_decls = object.dg.anon_decl_deps;
626 self.aligned_anon_decls = object.dg.aligned_anon_decls;
612627 object.dg.ctypes.deinit(gpa);
613628 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
614629 code.* = object.code.moveToUnmanaged();
......@@ -642,6 +657,7 @@ fn flushLazyFn(
642657 .fwd_decl = fwd_decl.toManaged(gpa),
643658 .ctypes = ctypes.*,
644659 .anon_decl_deps = .{},
660 .aligned_anon_decls = .{},
645661 },
646662 .code = code.toManaged(gpa),
647663 .indent_writer = undefined, // set later so we can get a pointer to object.code
......@@ -651,6 +667,7 @@ fn flushLazyFn(
651667 // If this assert trips just handle the anon_decl_deps the same as
652668 // `updateFunc()` does.
653669 assert(object.dg.anon_decl_deps.count() == 0);
670 assert(object.dg.aligned_anon_decls.count() == 0);
654671 object.dg.ctypes.deinit(gpa);
655672 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
656673 code.* = object.code.moveToUnmanaged();
src/value.zig+2-2
......@@ -1571,7 +1571,7 @@ pub const Value = struct {
15711571 .none => switch (ip.indexToKey(switch (ptr.addr) {
15721572 .decl => |decl| mod.declPtr(decl).ty.toIntern(),
15731573 .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).ty.toIntern(),
1574 .anon_decl => |anon_decl| ip.typeOf(anon_decl),
1574 .anon_decl => |anon_decl| ip.typeOf(anon_decl.val),
15751575 .comptime_field => |comptime_field| ip.typeOf(comptime_field),
15761576 else => unreachable,
15771577 })) {
......@@ -1604,7 +1604,7 @@ pub const Value = struct {
16041604 })).toValue(),
16051605 .ptr => |ptr| switch (ptr.addr) {
16061606 .decl => |decl| mod.declPtr(decl).val.maybeElemValue(mod, index),
1607 .anon_decl => |anon_decl| anon_decl.toValue().maybeElemValue(mod, index),
1607 .anon_decl => |anon_decl| anon_decl.val.toValue().maybeElemValue(mod, index),
16081608 .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod))
16091609 .toValue().maybeElemValue(mod, index),
16101610 .int, .eu_payload => null,