authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-09-24 19:22:25-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-03 12:12:50-07:00
logc0b55125443cab63945205b2f7c66bf12cae71e1
treec47592afbee6b860b6a611e594ab8e7ed732e621
parent4df7f7c86a0a105b5d3764121f259a39487a6c8a

compiler: start handling anonymous decls differently

Instead of explicitly creating a `Module.Decl` object for each anonymous declaration, each `InternPool.Index` value is implicitly understood to be an anonymous declaration when encountered by backend codegen. The memory management strategy for these anonymous decls then becomes to garbage collect them along with standard InternPool garbage. In the interest of a smooth transition, this commit only implements this new scheme for string literals and leaves all the previous mechanisms in place.

10 files changed, 201 insertions(+), 58 deletions(-)

src/InternPool.zig+40-4
......@@ -1074,6 +1074,7 @@ pub const Key = union(enum) {
10741074
10751075 decl: Module.Decl.Index,
10761076 mut_decl: MutDecl,
1077 anon_decl: Index,
10771078 comptime_field: Index,
10781079 int: Index,
10791080 eu_payload: Index,
......@@ -1230,10 +1231,12 @@ pub const Key = union(enum) {
12301231 asBytes(&x.decl) ++ asBytes(&x.runtime_index),
12311232 ),
12321233
1233 .int, .eu_payload, .opt_payload, .comptime_field => |int| Hash.hash(
1234 seed2,
1235 asBytes(&int),
1236 ),
1234 .anon_decl,
1235 .int,
1236 .eu_payload,
1237 .opt_payload,
1238 .comptime_field,
1239 => |int| Hash.hash(seed2, asBytes(&int)),
12371240
12381241 .elem, .field => |x| Hash.hash(
12391242 seed2,
......@@ -1497,6 +1500,7 @@ pub const Key = union(enum) {
14971500 return switch (a_info.addr) {
14981501 .decl => |a_decl| a_decl == b_info.addr.decl,
14991502 .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,
15001504 .int => |a_int| a_int == b_info.addr.int,
15011505 .eu_payload => |a_eu_payload| a_eu_payload == b_info.addr.eu_payload,
15021506 .opt_payload => |a_opt_payload| a_opt_payload == b_info.addr.opt_payload,
......@@ -2123,6 +2127,7 @@ pub const Index = enum(u32) {
21232127 simple_value: struct { data: SimpleValue },
21242128 ptr_decl: struct { data: *PtrDecl },
21252129 ptr_mut_decl: struct { data: *PtrMutDecl },
2130 ptr_anon_decl: struct { data: *PtrAnonDecl },
21262131 ptr_comptime_field: struct { data: *PtrComptimeField },
21272132 ptr_int: struct { data: *PtrBase },
21282133 ptr_eu_payload: struct { data: *PtrBase },
......@@ -2572,6 +2577,9 @@ pub const Tag = enum(u8) {
25722577 /// A pointer to a decl that can be mutated at comptime.
25732578 /// data is extra index of `PtrMutDecl`, which contains the type and address.
25742579 ptr_mut_decl,
2580 /// A pointer to an anonymous decl.
2581 /// data is extra index of `PtrAnonDecl`, which contains the type and decl value.
2582 ptr_anon_decl,
25752583 /// data is extra index of `PtrComptimeField`, which contains the pointer type and field value.
25762584 ptr_comptime_field,
25772585 /// A pointer with an integer value.
......@@ -2767,6 +2775,7 @@ pub const Tag = enum(u8) {
27672775 .simple_value => unreachable,
27682776 .ptr_decl => PtrDecl,
27692777 .ptr_mut_decl => PtrMutDecl,
2778 .ptr_anon_decl => PtrAnonDecl,
27702779 .ptr_comptime_field => PtrComptimeField,
27712780 .ptr_int => PtrBase,
27722781 .ptr_eu_payload => PtrBase,
......@@ -3364,6 +3373,11 @@ pub const PtrDecl = struct {
33643373 decl: Module.Decl.Index,
33653374};
33663375
3376pub const PtrAnonDecl = struct {
3377 ty: Index,
3378 val: Index,
3379};
3380
33673381pub const PtrMutDecl = struct {
33683382 ty: Index,
33693383 decl: Module.Decl.Index,
......@@ -3713,6 +3727,13 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
37133727 } },
37143728 } };
37153729 },
3730 .ptr_anon_decl => {
3731 const info = ip.extraData(PtrAnonDecl, data);
3732 return .{ .ptr = .{
3733 .ty = info.ty,
3734 .addr = .{ .anon_decl = info.val },
3735 } };
3736 },
37163737 .ptr_comptime_field => {
37173738 const info = ip.extraData(PtrComptimeField, data);
37183739 return .{ .ptr = .{
......@@ -3790,6 +3811,9 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
37903811 .runtime_index = sub_info.runtime_index,
37913812 } };
37923813 },
3814 .ptr_anon_decl => .{
3815 .anon_decl = ip.extraData(PtrAnonDecl, ptr_item.data).val,
3816 },
37933817 .ptr_comptime_field => .{
37943818 .comptime_field = ip.extraData(PtrComptimeField, ptr_item.data).field_val,
37953819 },
......@@ -4542,6 +4566,13 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
45424566 .runtime_index = mut_decl.runtime_index,
45434567 }),
45444568 }),
4569 .anon_decl => |anon_decl| ip.items.appendAssumeCapacity(.{
4570 .tag = .ptr_anon_decl,
4571 .data = try ip.addExtra(gpa, PtrAnonDecl{
4572 .ty = ptr.ty,
4573 .val = anon_decl,
4574 }),
4575 }),
45454576 .comptime_field => |field_val| {
45464577 assert(field_val != .none);
45474578 ip.items.appendAssumeCapacity(.{
......@@ -7147,6 +7178,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
71477178 .simple_value => 0,
71487179 .ptr_decl => @sizeOf(PtrDecl),
71497180 .ptr_mut_decl => @sizeOf(PtrMutDecl),
7181 .ptr_anon_decl => @sizeOf(PtrAnonDecl),
71507182 .ptr_comptime_field => @sizeOf(PtrComptimeField),
71517183 .ptr_int => @sizeOf(PtrBase),
71527184 .ptr_eu_payload => @sizeOf(PtrBase),
......@@ -7276,6 +7308,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
72767308 .runtime_value,
72777309 .ptr_decl,
72787310 .ptr_mut_decl,
7311 .ptr_anon_decl,
72797312 .ptr_comptime_field,
72807313 .ptr_int,
72817314 .ptr_eu_payload,
......@@ -7656,6 +7689,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
76567689
76577690 inline .ptr_decl,
76587691 .ptr_mut_decl,
7692 .ptr_anon_decl,
76597693 .ptr_comptime_field,
76607694 .ptr_int,
76617695 .ptr_eu_payload,
......@@ -7816,6 +7850,7 @@ pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.Addr.Tag {
78167850 switch (ip.items.items(.tag)[base]) {
78177851 .ptr_decl => return .decl,
78187852 .ptr_mut_decl => return .mut_decl,
7853 .ptr_anon_decl => return .anon_decl,
78197854 .ptr_comptime_field => return .comptime_field,
78207855 .ptr_int => return .int,
78217856 inline .ptr_eu_payload,
......@@ -7991,6 +8026,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
79918026 .simple_value,
79928027 .ptr_decl,
79938028 .ptr_mut_decl,
8029 .ptr_anon_decl,
79948030 .ptr_comptime_field,
79958031 .ptr_int,
79968032 .ptr_eu_payload,
src/Module.zig+1-4
......@@ -109,9 +109,6 @@ comptime_capture_scopes: std.AutoArrayHashMapUnmanaged(CaptureScope.Key, InternP
109109/// This memory lives until the Module is destroyed.
110110tmp_hack_arena: std.heap.ArenaAllocator,
111111
112/// This is currently only used for string literals.
113memoized_decls: std.AutoHashMapUnmanaged(InternPool.Index, Decl.Index) = .{},
114
115112/// We optimize memory usage for a compilation with no compile errors by storing the
116113/// error messages and mapping outside of `Decl`.
117114/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
......@@ -2627,7 +2624,6 @@ pub fn deinit(mod: *Module) void {
26272624 mod.global_assembly.deinit(gpa);
26282625 mod.reference_table.deinit(gpa);
26292626
2630 mod.memoized_decls.deinit(gpa);
26312627 mod.intern_pool.deinit(gpa);
26322628 mod.tmp_hack_arena.deinit();
26332629
......@@ -5814,6 +5810,7 @@ pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void {
58145810 .ptr => |ptr| {
58155811 switch (ptr.addr) {
58165812 .decl => |decl| try mod.markDeclIndexAlive(decl),
5813 .anon_decl => {},
58175814 .mut_decl => |mut_decl| try mod.markDeclIndexAlive(mut_decl.decl),
58185815 .int, .comptime_field => {},
58195816 .eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(parent.toValue()),
src/Sema.zig+57-40
......@@ -1091,7 +1091,7 @@ fn analyzeBodyInner(
10911091 .slice_sentinel => try sema.zirSliceSentinel(block, inst),
10921092 .slice_start => try sema.zirSliceStart(block, inst),
10931093 .slice_length => try sema.zirSliceLength(block, inst),
1094 .str => try sema.zirStr(block, inst),
1094 .str => try sema.zirStr(inst),
10951095 .switch_block => try sema.zirSwitchBlock(block, inst, false),
10961096 .switch_block_ref => try sema.zirSwitchBlock(block, inst, true),
10971097 .type_info => try sema.zirTypeInfo(block, inst),
......@@ -2185,7 +2185,7 @@ fn resolveMaybeUndefValIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Va
21852185 if (val.ip_index == .none) return val;
21862186 if (sema.mod.intern_pool.isVariable(val.toIntern())) return null;
21872187 if (sema.mod.intern_pool.getBackingAddrTag(val.toIntern())) |addr| switch (addr) {
2188 .decl, .mut_decl, .comptime_field => return null,
2188 .decl, .anon_decl, .mut_decl, .comptime_field => return null,
21892189 .int => {},
21902190 .eu_payload, .opt_payload, .elem, .field => unreachable,
21912191 };
......@@ -5501,38 +5501,40 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
55015501 return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag);
55025502}
55035503
5504fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
5505 const tracy = trace(@src());
5506 defer tracy.end();
5507
5504fn zirStr(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
55085505 const bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code);
5509 return sema.addStrLit(block, bytes);
5506 return sema.addStrLitNoAlias(bytes);
55105507}
55115508
5512fn addStrLit(sema: *Sema, block: *Block, bytes: []const u8) CompileError!Air.Inst.Ref {
5513 const mod = sema.mod;
5514 const gpa = sema.gpa;
5515 // TODO: write something like getCoercedInts to avoid needing to dupe
5509fn addStrLit(sema: *Sema, bytes: []const u8) CompileError!Air.Inst.Ref {
55165510 const duped_bytes = try sema.arena.dupe(u8, bytes);
5517 const ty = try mod.arrayType(.{
5511 return addStrLitNoAlias(sema, duped_bytes);
5512}
5513
5514/// Safe to call when `bytes` does not point into `InternPool`.
5515fn addStrLitNoAlias(sema: *Sema, bytes: []const u8) CompileError!Air.Inst.Ref {
5516 const mod = sema.mod;
5517 const array_ty = try mod.arrayType(.{
55185518 .len = bytes.len,
55195519 .sentinel = .zero_u8,
55205520 .child = .u8_type,
55215521 });
55225522 const val = try mod.intern(.{ .aggregate = .{
5523 .ty = ty.toIntern(),
5524 .storage = .{ .bytes = duped_bytes },
5523 .ty = array_ty.toIntern(),
5524 .storage = .{ .bytes = bytes },
55255525 } });
5526 const gop = try mod.memoized_decls.getOrPut(gpa, val);
5527 if (!gop.found_existing) {
5528 const new_decl_index = try mod.createAnonymousDecl(block, .{
5529 .ty = ty,
5530 .val = val.toValue(),
5531 });
5532 gop.value_ptr.* = new_decl_index;
5533 try mod.finalizeAnonDecl(new_decl_index);
5534 }
5535 return sema.analyzeDeclRef(gop.value_ptr.*);
5526 const ptr_ty = try sema.ptrType(.{
5527 .child = array_ty.toIntern(),
5528 .flags = .{
5529 .alignment = .none,
5530 .is_const = true,
5531 .address_space = .generic,
5532 },
5533 });
5534 return Air.internedToRef((try mod.intern(.{ .ptr = .{
5535 .ty = ptr_ty.toIntern(),
5536 .addr = .{ .anon_decl = val },
5537 } })));
55365538}
55375539
55385540fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -12907,7 +12909,7 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op
1290712909 try sema.zirSaveErrRetIndex(block, inst);
1290812910 continue;
1290912911 },
12910 .str => try sema.zirStr(block, inst),
12912 .str => try sema.zirStr(inst),
1291112913 .as_node => try sema.zirAsNode(block, inst),
1291212914 .field_val => try sema.zirFieldVal(block, inst),
1291312915 .@"unreachable" => {
......@@ -20170,7 +20172,7 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2017020172
2017120173 if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
2017220174 const err_name = sema.mod.intern_pool.indexToKey(val.toIntern()).err.name;
20173 return sema.addStrLit(block, sema.mod.intern_pool.stringToSlice(err_name));
20175 return sema.addStrLit(sema.mod.intern_pool.stringToSlice(err_name));
2017420176 }
2017520177
2017620178 // Similar to zirTagName, we have special AIR instruction for the error name in case an optimimzation pass
......@@ -20288,7 +20290,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
2028820290 .EnumLiteral => {
2028920291 const val = try sema.resolveConstValue(block, .unneeded, operand, undefined);
2029020292 const tag_name = ip.indexToKey(val.toIntern()).enum_literal;
20291 return sema.addStrLit(block, ip.stringToSlice(tag_name));
20293 return sema.addStrLit(ip.stringToSlice(tag_name));
2029220294 },
2029320295 .Enum => operand_ty,
2029420296 .Union => operand_ty.unionTagType(mod) orelse {
......@@ -20330,7 +20332,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
2033020332 };
2033120333 // TODO: write something like getCoercedInts to avoid needing to dupe
2033220334 const field_name = enum_ty.enumFieldName(field_index, mod);
20333 return sema.addStrLit(block, ip.stringToSlice(field_name));
20335 return sema.addStrLit(ip.stringToSlice(field_name));
2033420336 }
2033520337 try sema.requireRuntimeBlock(block, src, operand_src);
2033620338 if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) {
......@@ -29859,7 +29861,7 @@ fn beginComptimePtrMutation(
2985929861 const mod = sema.mod;
2986029862 const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
2986129863 switch (ptr.addr) {
29862 .decl, .int => unreachable, // isComptimeMutablePtr has been checked already
29864 .decl, .anon_decl, .int => unreachable, // isComptimeMutablePtr has been checked already
2986329865 .mut_decl => |mut_decl| {
2986429866 const decl = mod.declPtr(mut_decl.decl);
2986529867 return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl);
......@@ -30455,9 +30457,10 @@ fn beginComptimePtrLoad(
3045530457 maybe_array_ty: ?Type,
3045630458) ComptimePtrLoadError!ComptimePtrLoadKit {
3045730459 const mod = sema.mod;
30460 const ip = &mod.intern_pool;
3045830461 const target = mod.getTarget();
3045930462
30460 var deref: ComptimePtrLoadKit = switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
30463 var deref: ComptimePtrLoadKit = switch (ip.indexToKey(ptr_val.toIntern())) {
3046130464 .ptr => |ptr| switch (ptr.addr) {
3046230465 .decl, .mut_decl => blk: {
3046330466 const decl_index = switch (ptr.addr) {
......@@ -30478,9 +30481,21 @@ fn beginComptimePtrLoad(
3047830481 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
3047930482 };
3048030483 },
30484 .anon_decl => |decl_val| blk: {
30485 if (decl_val.toValue().getVariable(mod) != null) return error.RuntimeLoad;
30486 const decl_ty = ip.typeOf(decl_val).toType();
30487 const decl_tv: TypedValue = .{ .ty = decl_ty, .val = decl_val.toValue() };
30488 const layout_defined = decl_ty.hasWellDefinedLayout(mod);
30489 break :blk ComptimePtrLoadKit{
30490 .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,
30491 .pointee = decl_tv,
30492 .is_mutable = false,
30493 .ty_without_well_defined_layout = if (!layout_defined) decl_ty else null,
30494 };
30495 },
3048130496 .int => return error.RuntimeLoad,
3048230497 .eu_payload, .opt_payload => |container_ptr| blk: {
30483 const container_ty = mod.intern_pool.typeOf(container_ptr).toType().childType(mod);
30498 const container_ty = ip.typeOf(container_ptr).toType().childType(mod);
3048430499 const payload_ty = switch (ptr.addr) {
3048530500 .eu_payload => container_ty.errorUnionPayload(mod),
3048630501 .opt_payload => container_ty.optionalChild(mod),
......@@ -30502,13 +30517,13 @@ fn beginComptimePtrLoad(
3050230517 const payload_val = switch (tv.val.ip_index) {
3050330518 .none => tv.val.cast(Value.Payload.SubValue).?.data,
3050430519 .null_value => return sema.fail(block, src, "attempt to use null value", .{}),
30505 else => switch (mod.intern_pool.indexToKey(tv.val.toIntern())) {
30520 else => switch (ip.indexToKey(tv.val.toIntern())) {
3050630521 .error_union => |error_union| switch (error_union.val) {
3050730522 .err_name => |err_name| return sema.fail(
3050830523 block,
3050930524 src,
3051030525 "attempt to unwrap error: {}",
30511 .{err_name.fmt(&mod.intern_pool)},
30526 .{err_name.fmt(ip)},
3051230527 ),
3051330528 .payload => |payload| payload,
3051430529 },
......@@ -30527,7 +30542,7 @@ fn beginComptimePtrLoad(
3052730542 break :blk deref;
3052830543 },
3052930544 .comptime_field => |comptime_field| blk: {
30530 const field_ty = mod.intern_pool.typeOf(comptime_field).toType();
30545 const field_ty = ip.typeOf(comptime_field).toType();
3053130546 break :blk ComptimePtrLoadKit{
3053230547 .parent = null,
3053330548 .pointee = .{ .ty = field_ty, .val = comptime_field.toValue() },
......@@ -30536,15 +30551,15 @@ fn beginComptimePtrLoad(
3053630551 };
3053730552 },
3053830553 .elem => |elem_ptr| blk: {
30539 const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod);
30554 const elem_ty = ip.typeOf(elem_ptr.base).toType().elemType2(mod);
3054030555 var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.base.toValue(), null);
3054130556
3054230557 // This code assumes that elem_ptrs have been "flattened" in order for direct dereference
3054330558 // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that
3054430559 // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened"
30545 switch (mod.intern_pool.indexToKey(elem_ptr.base)) {
30560 switch (ip.indexToKey(elem_ptr.base)) {
3054630561 .ptr => |base_ptr| switch (base_ptr.addr) {
30547 .elem => |base_elem| assert(!mod.intern_pool.typeOf(base_elem.base).toType().elemType2(mod).eql(elem_ty, mod)),
30562 .elem => |base_elem| assert(!ip.typeOf(base_elem.base).toType().elemType2(mod).eql(elem_ty, mod)),
3054830563 else => {},
3054930564 },
3055030565 else => {},
......@@ -30616,7 +30631,7 @@ fn beginComptimePtrLoad(
3061630631 },
3061730632 .field => |field_ptr| blk: {
3061830633 const field_index: u32 = @intCast(field_ptr.index);
30619 const container_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod);
30634 const container_ty = ip.typeOf(field_ptr.base).toType().childType(mod);
3062030635 var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.base.toValue(), container_ty);
3062130636
3062230637 if (container_ty.hasWellDefinedLayout(mod)) {
......@@ -30655,7 +30670,7 @@ fn beginComptimePtrLoad(
3065530670 },
3065630671 Value.slice_len_index => TypedValue{
3065730672 .ty = Type.usize,
30658 .val = mod.intern_pool.indexToKey(try tv.val.intern(tv.ty, mod)).ptr.len.toValue(),
30673 .val = ip.indexToKey(try tv.val.intern(tv.ty, mod)).ptr.len.toValue(),
3065930674 },
3066030675 else => unreachable,
3066130676 };
......@@ -34529,7 +34544,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
3452934544 else => (try sema.resolveLazyValue(ptr.len.toValue())).toIntern(),
3453034545 };
3453134546 switch (ptr.addr) {
34532 .decl, .mut_decl => return if (resolved_len == ptr.len)
34547 .decl, .mut_decl, .anon_decl => return if (resolved_len == ptr.len)
3453334548 val
3453434549 else
3453534550 (try mod.intern(.{ .ptr = .{
......@@ -34537,6 +34552,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
3453734552 .addr = switch (ptr.addr) {
3453834553 .decl => |decl| .{ .decl = decl },
3453934554 .mut_decl => |mut_decl| .{ .mut_decl = mut_decl },
34555 .anon_decl => |anon_decl| .{ .anon_decl = anon_decl },
3454034556 else => unreachable,
3454134557 },
3454234558 .len = resolved_len,
......@@ -36568,6 +36584,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3656836584 .runtime_value,
3656936585 .simple_value,
3657036586 .ptr_decl,
36587 .ptr_anon_decl,
3657136588 .ptr_mut_decl,
3657236589 .ptr_comptime_field,
3657336590 .ptr_int,
src/TypedValue.zig+9
......@@ -321,6 +321,15 @@ pub fn print(
321321 .val = decl.val,
322322 }, writer, level - 1, mod);
323323 },
324 .anon_decl => |decl_val| {
325 if (level == 0) return writer.print("(anon decl '{d}')", .{
326 @intFromEnum(decl_val),
327 });
328 return print(.{
329 .ty = ip.typeOf(decl_val).toType(),
330 .val = decl_val.toValue(),
331 }, writer, level - 1, mod);
332 },
324333 .mut_decl => |mut_decl| {
325334 const decl = mod.declPtr(mut_decl.decl);
326335 if (level == 0) return writer.print("(mut decl '{}')", .{decl.name.fmt(ip)});
src/arch/wasm/CodeGen.zig+1
......@@ -3075,6 +3075,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue
30753075 .decl => |decl_index| {
30763076 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
30773077 },
3078 .anon_decl => @panic("TODO"),
30783079 .mut_decl => |mut_decl| {
30793080 const decl_index = mut_decl.decl;
30803081 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
src/codegen.zig+1
......@@ -655,6 +655,7 @@ fn lowerParentPtr(
655655 debug_output,
656656 reloc_info,
657657 ),
658 .anon_decl => @panic("TODO"),
658659 .int => |int| try generateSymbol(bin_file, src_loc, .{
659660 .ty = Type.usize,
660661 .val = int.toValue(),
src/codegen/c.zig+2
......@@ -604,6 +604,7 @@ pub const DeclGen = struct {
604604 },
605605 location,
606606 ),
607 .anon_decl => @panic("TODO"),
607608 .int => |int| {
608609 try writer.writeByte('(');
609610 try dg.renderCType(writer, ptr_cty);
......@@ -1155,6 +1156,7 @@ pub const DeclGen = struct {
11551156 },
11561157 ptr_location,
11571158 ),
1159 .anon_decl => @panic("TODO"),
11581160 .int => |int| {
11591161 try writer.writeAll("((");
11601162 try dg.renderType(writer, ptr_ty);
src/codegen/llvm.zig+83-7
......@@ -810,6 +810,8 @@ pub const Object = struct {
810810 /// * it works for functions not all globals.
811811 /// Therefore, this table keeps track of the mapping.
812812 decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, Builder.Global.Index),
813 /// Same deal as `decl_map` but for anonymous declarations, which are always global constants.
814 anon_decl_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Global.Index),
813815 /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction.
814816 named_enum_map: std.AutoHashMapUnmanaged(Module.Decl.Index, Builder.Function.Index),
815817 /// Maps Zig types to LLVM types. The table memory is backed by the GPA of
......@@ -993,6 +995,7 @@ pub const Object = struct {
993995 .target_data = target_data,
994996 .target = options.target,
995997 .decl_map = .{},
998 .anon_decl_map = .{},
996999 .named_enum_map = .{},
9971000 .type_map = .{},
9981001 .di_type_map = .{},
......@@ -1011,6 +1014,7 @@ pub const Object = struct {
10111014 self.target_machine.dispose();
10121015 }
10131016 self.decl_map.deinit(gpa);
1017 self.anon_decl_map.deinit(gpa);
10141018 self.named_enum_map.deinit(gpa);
10151019 self.type_map.deinit(gpa);
10161020 self.extern_collisions.deinit(gpa);
......@@ -3038,6 +3042,31 @@ pub const Object = struct {
30383042 }
30393043 }
30403044
3045 fn resolveGlobalAnonDecl(
3046 o: *Object,
3047 decl_val: InternPool.Index,
3048 llvm_addr_space: Builder.AddrSpace,
3049 ) Error!Builder.Variable.Index {
3050 const gop = try o.anon_decl_map.getOrPut(o.gpa, decl_val);
3051 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.variable;
3052 errdefer assert(o.anon_decl_map.remove(decl_val));
3053
3054 const mod = o.module;
3055 const decl_ty = mod.intern_pool.typeOf(decl_val);
3056
3057 const variable_index = try o.builder.addVariable(
3058 try o.builder.fmt("__anon_{d}", .{@intFromEnum(decl_val)}),
3059 try o.lowerType(decl_ty.toType()),
3060 llvm_addr_space,
3061 );
3062 gop.value_ptr.* = variable_index.ptrConst(&o.builder).global;
3063
3064 try variable_index.setInitializer(try o.lowerValue(decl_val), &o.builder);
3065 variable_index.setLinkage(.internal, &o.builder);
3066 variable_index.setUnnamedAddr(.unnamed_addr, &o.builder);
3067 return variable_index;
3068 }
3069
30413070 fn resolveGlobalDecl(
30423071 o: *Object,
30433072 decl_index: Module.Decl.Index,
......@@ -3764,6 +3793,7 @@ pub const Object = struct {
37643793 const ptr_val = switch (ptr.addr) {
37653794 .decl => |decl| try o.lowerDeclRefValue(ptr_ty, decl),
37663795 .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_ty, mut_decl.decl),
3796 .anon_decl => |anon_decl| try o.lowerAnonDeclRef(ptr_ty, anon_decl),
37673797 .int => |int| try o.lowerIntAsPtr(int),
37683798 .eu_payload,
37693799 .opt_payload,
......@@ -4216,10 +4246,12 @@ pub const Object = struct {
42164246 return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint);
42174247 }
42184248
4219 const ParentPtr = struct {
4220 ty: Type,
4221 llvm_ptr: Builder.Value,
4222 };
4249 fn lowerParentPtrAnonDecl(o: *Object, decl_val: InternPool.Index) Error!Builder.Constant {
4250 const mod = o.module;
4251 const decl_ty = mod.intern_pool.typeOf(decl_val).toType();
4252 const ptr_ty = try mod.singleMutPtrType(decl_ty);
4253 return o.lowerAnonDeclRef(ptr_ty, decl_val);
4254 }
42234255
42244256 fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {
42254257 const mod = o.module;
......@@ -4229,13 +4261,14 @@ pub const Object = struct {
42294261 return o.lowerDeclRefValue(ptr_ty, decl_index);
42304262 }
42314263
4232 fn lowerParentPtr(o: *Object, ptr_val: Value) Allocator.Error!Builder.Constant {
4264 fn lowerParentPtr(o: *Object, ptr_val: Value) Error!Builder.Constant {
42334265 const mod = o.module;
42344266 const ip = &mod.intern_pool;
42354267 const ptr = ip.indexToKey(ptr_val.toIntern()).ptr;
42364268 return switch (ptr.addr) {
4237 .decl => |decl| o.lowerParentPtrDecl(decl),
4238 .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl),
4269 .decl => |decl| try o.lowerParentPtrDecl(decl),
4270 .mut_decl => |mut_decl| try o.lowerParentPtrDecl(mut_decl.decl),
4271 .anon_decl => |anon_decl| try o.lowerParentPtrAnonDecl(anon_decl),
42394272 .int => |int| try o.lowerIntAsPtr(int),
42404273 .eu_payload => |eu_ptr| {
42414274 const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue());
......@@ -4349,6 +4382,49 @@ pub const Object = struct {
43494382 };
43504383 }
43514384
4385 /// This logic is very similar to `lowerDeclRefValue` but for anonymous declarations.
4386 /// Maybe the logic could be unified.
4387 fn lowerAnonDeclRef(
4388 o: *Object,
4389 ptr_ty: Type,
4390 decl_val: InternPool.Index,
4391 ) Error!Builder.Constant {
4392 const mod = o.module;
4393 const ip = &mod.intern_pool;
4394 const decl_ty = ip.typeOf(decl_val).toType();
4395 const target = mod.getTarget();
4396
4397 if (decl_val.toValue().getFunction(mod)) |func| {
4398 _ = func;
4399 @panic("TODO");
4400 } else if (decl_val.toValue().getExternFunc(mod)) |func| {
4401 _ = func;
4402 @panic("TODO");
4403 }
4404
4405 const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
4406 if ((!is_fn_body and !decl_ty.hasRuntimeBits(mod)) or
4407 (is_fn_body and mod.typeToFunc(decl_ty).?.is_generic)) return o.lowerPtrToVoid(ptr_ty);
4408
4409 if (is_fn_body)
4410 @panic("TODO");
4411
4412 const addr_space = target_util.defaultAddressSpace(target, .global_constant);
4413 const llvm_addr_space = toLlvmAddressSpace(addr_space, target);
4414 const llvm_global = (try o.resolveGlobalAnonDecl(decl_val, llvm_addr_space)).ptrConst(&o.builder).global;
4415
4416 const llvm_val = try o.builder.convConst(
4417 .unneeded,
4418 llvm_global.toConst(),
4419 try o.builder.ptrType(llvm_addr_space),
4420 );
4421
4422 return o.builder.convConst(if (ptr_ty.isAbiInt(mod)) switch (ptr_ty.intInfo(mod).signedness) {
4423 .signed => .signed,
4424 .unsigned => .unsigned,
4425 } else .unneeded, llvm_val, try o.lowerType(ptr_ty));
4426 }
4427
43524428 fn lowerDeclRefValue(o: *Object, ty: Type, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {
43534429 const mod = o.module;
43544430
src/codegen/spirv.zig+1
......@@ -818,6 +818,7 @@ pub const DeclGen = struct {
818818 const mod = self.module;
819819 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
820820 .decl => |decl| return try self.constructDeclRef(ptr_ty, decl),
821 .anon_decl => @panic("TODO"),
821822 .mut_decl => |decl_mut| return try self.constructDeclRef(ptr_ty, decl_mut.decl),
822823 .int => |int| {
823824 const ptr_id = self.spv.allocId();
src/value.zig+6-3
......@@ -1565,12 +1565,14 @@ pub const Value = struct {
15651565 }
15661566
15671567 pub fn sliceLen(val: Value, mod: *Module) u64 {
1568 const ptr = mod.intern_pool.indexToKey(val.toIntern()).ptr;
1568 const ip = &mod.intern_pool;
1569 const ptr = ip.indexToKey(val.toIntern()).ptr;
15691570 return switch (ptr.len) {
1570 .none => switch (mod.intern_pool.indexToKey(switch (ptr.addr) {
1571 .none => switch (ip.indexToKey(switch (ptr.addr) {
15711572 .decl => |decl| mod.declPtr(decl).ty.toIntern(),
15721573 .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).ty.toIntern(),
1573 .comptime_field => |comptime_field| mod.intern_pool.typeOf(comptime_field),
1574 .anon_decl => |anon_decl| ip.typeOf(anon_decl),
1575 .comptime_field => |comptime_field| ip.typeOf(comptime_field),
15741576 else => unreachable,
15751577 })) {
15761578 .array_type => |array_type| array_type.len,
......@@ -1602,6 +1604,7 @@ pub const Value = struct {
16021604 })).toValue(),
16031605 .ptr => |ptr| switch (ptr.addr) {
16041606 .decl => |decl| mod.declPtr(decl).val.maybeElemValue(mod, index),
1607 .anon_decl => |anon_decl| anon_decl.toValue().maybeElemValue(mod, index),
16051608 .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod))
16061609 .toValue().maybeElemValue(mod, index),
16071610 .int, .eu_payload => null,