authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-10-04 03:36:18-07:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2023-10-04 03:36:18-07:00
log398db54434dad366748d63f37dcfc5e770cfd278
treea94859a016a1de9f14e93b98adbdf43260c6d556
parentec0f76c5996e88f61d376640bf36ed7feb2b0ea6
parentd634e02d33e682c8db9d137175c01d1318e6ab80
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #17276 from ziglang/anon-decls

compiler: start handling anonymous decls differently

18 files changed, 995 insertions(+), 222 deletions(-)

src/Compilation.zig+1
...@@ -3499,6 +3499,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v...@@ -3499,6 +3499,7 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: *std.Progress.Node) !v
3499 .is_naked_fn = false,3499 .is_naked_fn = false,
3500 .fwd_decl = fwd_decl.toManaged(gpa),3500 .fwd_decl = fwd_decl.toManaged(gpa),
3501 .ctypes = .{},3501 .ctypes = .{},
3502 .anon_decl_deps = .{},
3502 };3503 };
3503 defer {3504 defer {
3504 dg.ctypes.deinit(gpa);3505 dg.ctypes.deinit(gpa);
src/InternPool.zig+40-4
...@@ -1074,6 +1074,7 @@ pub const Key = union(enum) {...@@ -1074,6 +1074,7 @@ pub const Key = union(enum) {
10741074
1075 decl: Module.Decl.Index,1075 decl: Module.Decl.Index,
1076 mut_decl: MutDecl,1076 mut_decl: MutDecl,
1077 anon_decl: Index,
1077 comptime_field: Index,1078 comptime_field: Index,
1078 int: Index,1079 int: Index,
1079 eu_payload: Index,1080 eu_payload: Index,
...@@ -1230,10 +1231,12 @@ pub const Key = union(enum) {...@@ -1230,10 +1231,12 @@ pub const Key = union(enum) {
1230 asBytes(&x.decl) ++ asBytes(&x.runtime_index),1231 asBytes(&x.decl) ++ asBytes(&x.runtime_index),
1231 ),1232 ),
12321233
1233 .int, .eu_payload, .opt_payload, .comptime_field => |int| Hash.hash(1234 .anon_decl,
1234 seed2,1235 .int,
1235 asBytes(&int),1236 .eu_payload,
1236 ),1237 .opt_payload,
1238 .comptime_field,
1239 => |int| Hash.hash(seed2, asBytes(&int)),
12371240
1238 .elem, .field => |x| Hash.hash(1241 .elem, .field => |x| Hash.hash(
1239 seed2,1242 seed2,
...@@ -1497,6 +1500,7 @@ pub const Key = union(enum) {...@@ -1497,6 +1500,7 @@ pub const Key = union(enum) {
1497 return switch (a_info.addr) {1500 return switch (a_info.addr) {
1498 .decl => |a_decl| a_decl == b_info.addr.decl,1501 .decl => |a_decl| a_decl == b_info.addr.decl,
1499 .mut_decl => |a_mut_decl| std.meta.eql(a_mut_decl, b_info.addr.mut_decl),1502 .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,
1500 .int => |a_int| a_int == b_info.addr.int,1504 .int => |a_int| a_int == b_info.addr.int,
1501 .eu_payload => |a_eu_payload| a_eu_payload == b_info.addr.eu_payload,1505 .eu_payload => |a_eu_payload| a_eu_payload == b_info.addr.eu_payload,
1502 .opt_payload => |a_opt_payload| a_opt_payload == b_info.addr.opt_payload,1506 .opt_payload => |a_opt_payload| a_opt_payload == b_info.addr.opt_payload,
...@@ -2123,6 +2127,7 @@ pub const Index = enum(u32) {...@@ -2123,6 +2127,7 @@ pub const Index = enum(u32) {
2123 simple_value: struct { data: SimpleValue },2127 simple_value: struct { data: SimpleValue },
2124 ptr_decl: struct { data: *PtrDecl },2128 ptr_decl: struct { data: *PtrDecl },
2125 ptr_mut_decl: struct { data: *PtrMutDecl },2129 ptr_mut_decl: struct { data: *PtrMutDecl },
2130 ptr_anon_decl: struct { data: *PtrAnonDecl },
2126 ptr_comptime_field: struct { data: *PtrComptimeField },2131 ptr_comptime_field: struct { data: *PtrComptimeField },
2127 ptr_int: struct { data: *PtrBase },2132 ptr_int: struct { data: *PtrBase },
2128 ptr_eu_payload: struct { data: *PtrBase },2133 ptr_eu_payload: struct { data: *PtrBase },
...@@ -2572,6 +2577,9 @@ pub const Tag = enum(u8) {...@@ -2572,6 +2577,9 @@ pub const Tag = enum(u8) {
2572 /// A pointer to a decl that can be mutated at comptime.2577 /// A pointer to a decl that can be mutated at comptime.
2573 /// data is extra index of `PtrMutDecl`, which contains the type and address.2578 /// data is extra index of `PtrMutDecl`, which contains the type and address.
2574 ptr_mut_decl,2579 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,
2575 /// data is extra index of `PtrComptimeField`, which contains the pointer type and field value.2583 /// data is extra index of `PtrComptimeField`, which contains the pointer type and field value.
2576 ptr_comptime_field,2584 ptr_comptime_field,
2577 /// A pointer with an integer value.2585 /// A pointer with an integer value.
...@@ -2767,6 +2775,7 @@ pub const Tag = enum(u8) {...@@ -2767,6 +2775,7 @@ pub const Tag = enum(u8) {
2767 .simple_value => unreachable,2775 .simple_value => unreachable,
2768 .ptr_decl => PtrDecl,2776 .ptr_decl => PtrDecl,
2769 .ptr_mut_decl => PtrMutDecl,2777 .ptr_mut_decl => PtrMutDecl,
2778 .ptr_anon_decl => PtrAnonDecl,
2770 .ptr_comptime_field => PtrComptimeField,2779 .ptr_comptime_field => PtrComptimeField,
2771 .ptr_int => PtrBase,2780 .ptr_int => PtrBase,
2772 .ptr_eu_payload => PtrBase,2781 .ptr_eu_payload => PtrBase,
...@@ -3364,6 +3373,11 @@ pub const PtrDecl = struct {...@@ -3364,6 +3373,11 @@ pub const PtrDecl = struct {
3364 decl: Module.Decl.Index,3373 decl: Module.Decl.Index,
3365};3374};
33663375
3376pub const PtrAnonDecl = struct {
3377 ty: Index,
3378 val: Index,
3379};
3380
3367pub const PtrMutDecl = struct {3381pub const PtrMutDecl = struct {
3368 ty: Index,3382 ty: Index,
3369 decl: Module.Decl.Index,3383 decl: Module.Decl.Index,
...@@ -3713,6 +3727,13 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -3713,6 +3727,13 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
3713 } },3727 } },
3714 } };3728 } };
3715 },3729 },
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 },
3716 .ptr_comptime_field => {3737 .ptr_comptime_field => {
3717 const info = ip.extraData(PtrComptimeField, data);3738 const info = ip.extraData(PtrComptimeField, data);
3718 return .{ .ptr = .{3739 return .{ .ptr = .{
...@@ -3790,6 +3811,9 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -3790,6 +3811,9 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
3790 .runtime_index = sub_info.runtime_index,3811 .runtime_index = sub_info.runtime_index,
3791 } };3812 } };
3792 },3813 },
3814 .ptr_anon_decl => .{
3815 .anon_decl = ip.extraData(PtrAnonDecl, ptr_item.data).val,
3816 },
3793 .ptr_comptime_field => .{3817 .ptr_comptime_field => .{
3794 .comptime_field = ip.extraData(PtrComptimeField, ptr_item.data).field_val,3818 .comptime_field = ip.extraData(PtrComptimeField, ptr_item.data).field_val,
3795 },3819 },
...@@ -4542,6 +4566,13 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {...@@ -4542,6 +4566,13 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index {
4542 .runtime_index = mut_decl.runtime_index,4566 .runtime_index = mut_decl.runtime_index,
4543 }),4567 }),
4544 }),4568 }),
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 }),
4545 .comptime_field => |field_val| {4576 .comptime_field => |field_val| {
4546 assert(field_val != .none);4577 assert(field_val != .none);
4547 ip.items.appendAssumeCapacity(.{4578 ip.items.appendAssumeCapacity(.{
...@@ -7147,6 +7178,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {...@@ -7147,6 +7178,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void {
7147 .simple_value => 0,7178 .simple_value => 0,
7148 .ptr_decl => @sizeOf(PtrDecl),7179 .ptr_decl => @sizeOf(PtrDecl),
7149 .ptr_mut_decl => @sizeOf(PtrMutDecl),7180 .ptr_mut_decl => @sizeOf(PtrMutDecl),
7181 .ptr_anon_decl => @sizeOf(PtrAnonDecl),
7150 .ptr_comptime_field => @sizeOf(PtrComptimeField),7182 .ptr_comptime_field => @sizeOf(PtrComptimeField),
7151 .ptr_int => @sizeOf(PtrBase),7183 .ptr_int => @sizeOf(PtrBase),
7152 .ptr_eu_payload => @sizeOf(PtrBase),7184 .ptr_eu_payload => @sizeOf(PtrBase),
...@@ -7276,6 +7308,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {...@@ -7276,6 +7308,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void {
7276 .runtime_value,7308 .runtime_value,
7277 .ptr_decl,7309 .ptr_decl,
7278 .ptr_mut_decl,7310 .ptr_mut_decl,
7311 .ptr_anon_decl,
7279 .ptr_comptime_field,7312 .ptr_comptime_field,
7280 .ptr_int,7313 .ptr_int,
7281 .ptr_eu_payload,7314 .ptr_eu_payload,
...@@ -7656,6 +7689,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -7656,6 +7689,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
76567689
7657 inline .ptr_decl,7690 inline .ptr_decl,
7658 .ptr_mut_decl,7691 .ptr_mut_decl,
7692 .ptr_anon_decl,
7659 .ptr_comptime_field,7693 .ptr_comptime_field,
7660 .ptr_int,7694 .ptr_int,
7661 .ptr_eu_payload,7695 .ptr_eu_payload,
...@@ -7816,6 +7850,7 @@ pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.Addr.Tag {...@@ -7816,6 +7850,7 @@ pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.Addr.Tag {
7816 switch (ip.items.items(.tag)[base]) {7850 switch (ip.items.items(.tag)[base]) {
7817 .ptr_decl => return .decl,7851 .ptr_decl => return .decl,
7818 .ptr_mut_decl => return .mut_decl,7852 .ptr_mut_decl => return .mut_decl,
7853 .ptr_anon_decl => return .anon_decl,
7819 .ptr_comptime_field => return .comptime_field,7854 .ptr_comptime_field => return .comptime_field,
7820 .ptr_int => return .int,7855 .ptr_int => return .int,
7821 inline .ptr_eu_payload,7856 inline .ptr_eu_payload,
...@@ -7991,6 +8026,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois...@@ -7991,6 +8026,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois
7991 .simple_value,8026 .simple_value,
7992 .ptr_decl,8027 .ptr_decl,
7993 .ptr_mut_decl,8028 .ptr_mut_decl,
8029 .ptr_anon_decl,
7994 .ptr_comptime_field,8030 .ptr_comptime_field,
7995 .ptr_int,8031 .ptr_int,
7996 .ptr_eu_payload,8032 .ptr_eu_payload,
src/Module.zig+1-4
...@@ -109,9 +109,6 @@ comptime_capture_scopes: std.AutoArrayHashMapUnmanaged(CaptureScope.Key, InternP...@@ -109,9 +109,6 @@ comptime_capture_scopes: std.AutoArrayHashMapUnmanaged(CaptureScope.Key, InternP
109/// This memory lives until the Module is destroyed.109/// This memory lives until the Module is destroyed.
110tmp_hack_arena: std.heap.ArenaAllocator,110tmp_hack_arena: std.heap.ArenaAllocator,
111111
112/// This is currently only used for string literals.
113memoized_decls: std.AutoHashMapUnmanaged(InternPool.Index, Decl.Index) = .{},
114
115/// We optimize memory usage for a compilation with no compile errors by storing the112/// We optimize memory usage for a compilation with no compile errors by storing the
116/// error messages and mapping outside of `Decl`.113/// error messages and mapping outside of `Decl`.
117/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.114/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
...@@ -2627,7 +2624,6 @@ pub fn deinit(mod: *Module) void {...@@ -2627,7 +2624,6 @@ pub fn deinit(mod: *Module) void {
2627 mod.global_assembly.deinit(gpa);2624 mod.global_assembly.deinit(gpa);
2628 mod.reference_table.deinit(gpa);2625 mod.reference_table.deinit(gpa);
26292626
2630 mod.memoized_decls.deinit(gpa);
2631 mod.intern_pool.deinit(gpa);2627 mod.intern_pool.deinit(gpa);
2632 mod.tmp_hack_arena.deinit();2628 mod.tmp_hack_arena.deinit();
26332629
...@@ -5814,6 +5810,7 @@ pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void {...@@ -5814,6 +5810,7 @@ pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void {
5814 .ptr => |ptr| {5810 .ptr => |ptr| {
5815 switch (ptr.addr) {5811 switch (ptr.addr) {
5816 .decl => |decl| try mod.markDeclIndexAlive(decl),5812 .decl => |decl| try mod.markDeclIndexAlive(decl),
5813 .anon_decl => {},
5817 .mut_decl => |mut_decl| try mod.markDeclIndexAlive(mut_decl.decl),5814 .mut_decl => |mut_decl| try mod.markDeclIndexAlive(mut_decl.decl),
5818 .int, .comptime_field => {},5815 .int, .comptime_field => {},
5819 .eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(parent.toValue()),5816 .eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(parent.toValue()),
src/Sema.zig+57-40
...@@ -1091,7 +1091,7 @@ fn analyzeBodyInner(...@@ -1091,7 +1091,7 @@ fn analyzeBodyInner(
1091 .slice_sentinel => try sema.zirSliceSentinel(block, inst),1091 .slice_sentinel => try sema.zirSliceSentinel(block, inst),
1092 .slice_start => try sema.zirSliceStart(block, inst),1092 .slice_start => try sema.zirSliceStart(block, inst),
1093 .slice_length => try sema.zirSliceLength(block, inst),1093 .slice_length => try sema.zirSliceLength(block, inst),
1094 .str => try sema.zirStr(block, inst),1094 .str => try sema.zirStr(inst),
1095 .switch_block => try sema.zirSwitchBlock(block, inst, false),1095 .switch_block => try sema.zirSwitchBlock(block, inst, false),
1096 .switch_block_ref => try sema.zirSwitchBlock(block, inst, true),1096 .switch_block_ref => try sema.zirSwitchBlock(block, inst, true),
1097 .type_info => try sema.zirTypeInfo(block, inst),1097 .type_info => try sema.zirTypeInfo(block, inst),
...@@ -2185,7 +2185,7 @@ fn resolveMaybeUndefValIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Va...@@ -2185,7 +2185,7 @@ fn resolveMaybeUndefValIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Va
2185 if (val.ip_index == .none) return val;2185 if (val.ip_index == .none) return val;
2186 if (sema.mod.intern_pool.isVariable(val.toIntern())) return null;2186 if (sema.mod.intern_pool.isVariable(val.toIntern())) return null;
2187 if (sema.mod.intern_pool.getBackingAddrTag(val.toIntern())) |addr| switch (addr) {2187 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,
2189 .int => {},2189 .int => {},
2190 .eu_payload, .opt_payload, .elem, .field => unreachable,2190 .eu_payload, .opt_payload, .elem, .field => unreachable,
2191 };2191 };
...@@ -5501,38 +5501,40 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v...@@ -5501,38 +5501,40 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
5501 return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag);5501 return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag);
5502}5502}
55035503
5504fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {5504fn zirStr(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
5505 const tracy = trace(@src());
5506 defer tracy.end();
5507
5508 const bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code);5505 const bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code);
5509 return sema.addStrLit(block, bytes);5506 return sema.addStrLitNoAlias(bytes);
5510}5507}
55115508
5512fn addStrLit(sema: *Sema, block: *Block, bytes: []const u8) CompileError!Air.Inst.Ref {5509fn addStrLit(sema: *Sema, 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
5516 const duped_bytes = try sema.arena.dupe(u8, bytes);5510 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(.{
5518 .len = bytes.len,5518 .len = bytes.len,
5519 .sentinel = .zero_u8,5519 .sentinel = .zero_u8,
5520 .child = .u8_type,5520 .child = .u8_type,
5521 });5521 });
5522 const val = try mod.intern(.{ .aggregate = .{5522 const val = try mod.intern(.{ .aggregate = .{
5523 .ty = ty.toIntern(),5523 .ty = array_ty.toIntern(),
5524 .storage = .{ .bytes = duped_bytes },5524 .storage = .{ .bytes = bytes },
5525 } });5525 } });
5526 const gop = try mod.memoized_decls.getOrPut(gpa, val);5526 const ptr_ty = try sema.ptrType(.{
5527 if (!gop.found_existing) {5527 .child = array_ty.toIntern(),
5528 const new_decl_index = try mod.createAnonymousDecl(block, .{5528 .flags = .{
5529 .ty = ty,5529 .alignment = .none,
5530 .val = val.toValue(),5530 .is_const = true,
5531 });5531 .address_space = .generic,
5532 gop.value_ptr.* = new_decl_index;5532 },
5533 try mod.finalizeAnonDecl(new_decl_index);5533 });
5534 }5534 return Air.internedToRef((try mod.intern(.{ .ptr = .{
5535 return sema.analyzeDeclRef(gop.value_ptr.*);5535 .ty = ptr_ty.toIntern(),
5536 .addr = .{ .anon_decl = val },
5537 } })));
5536}5538}
55375539
5538fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {5540fn 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...@@ -12907,7 +12909,7 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op
12907 try sema.zirSaveErrRetIndex(block, inst);12909 try sema.zirSaveErrRetIndex(block, inst);
12908 continue;12910 continue;
12909 },12911 },
12910 .str => try sema.zirStr(block, inst),12912 .str => try sema.zirStr(inst),
12911 .as_node => try sema.zirAsNode(block, inst),12913 .as_node => try sema.zirAsNode(block, inst),
12912 .field_val => try sema.zirFieldVal(block, inst),12914 .field_val => try sema.zirFieldVal(block, inst),
12913 .@"unreachable" => {12915 .@"unreachable" => {
...@@ -20170,7 +20172,7 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -20170,7 +20172,7 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2017020172
20171 if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {20173 if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
20172 const err_name = sema.mod.intern_pool.indexToKey(val.toIntern()).err.name;20174 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));
20174 }20176 }
2017520177
20176 // Similar to zirTagName, we have special AIR instruction for the error name in case an optimimzation pass20178 // 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...@@ -20288,7 +20290,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
20288 .EnumLiteral => {20290 .EnumLiteral => {
20289 const val = try sema.resolveConstValue(block, .unneeded, operand, undefined);20291 const val = try sema.resolveConstValue(block, .unneeded, operand, undefined);
20290 const tag_name = ip.indexToKey(val.toIntern()).enum_literal;20292 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));
20292 },20294 },
20293 .Enum => operand_ty,20295 .Enum => operand_ty,
20294 .Union => operand_ty.unionTagType(mod) orelse {20296 .Union => operand_ty.unionTagType(mod) orelse {
...@@ -20330,7 +20332,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -20330,7 +20332,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
20330 };20332 };
20331 // TODO: write something like getCoercedInts to avoid needing to dupe20333 // TODO: write something like getCoercedInts to avoid needing to dupe
20332 const field_name = enum_ty.enumFieldName(field_index, mod);20334 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));
20334 }20336 }
20335 try sema.requireRuntimeBlock(block, src, operand_src);20337 try sema.requireRuntimeBlock(block, src, operand_src);
20336 if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) {20338 if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) {
...@@ -29859,7 +29861,7 @@ fn beginComptimePtrMutation(...@@ -29859,7 +29861,7 @@ fn beginComptimePtrMutation(
29859 const mod = sema.mod;29861 const mod = sema.mod;
29860 const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;29862 const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
29861 switch (ptr.addr) {29863 switch (ptr.addr) {
29862 .decl, .int => unreachable, // isComptimeMutablePtr has been checked already29864 .decl, .anon_decl, .int => unreachable, // isComptimeMutablePtr has been checked already
29863 .mut_decl => |mut_decl| {29865 .mut_decl => |mut_decl| {
29864 const decl = mod.declPtr(mut_decl.decl);29866 const decl = mod.declPtr(mut_decl.decl);
29865 return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl);29867 return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl);
...@@ -30455,9 +30457,10 @@ fn beginComptimePtrLoad(...@@ -30455,9 +30457,10 @@ fn beginComptimePtrLoad(
30455 maybe_array_ty: ?Type,30457 maybe_array_ty: ?Type,
30456) ComptimePtrLoadError!ComptimePtrLoadKit {30458) ComptimePtrLoadError!ComptimePtrLoadKit {
30457 const mod = sema.mod;30459 const mod = sema.mod;
30460 const ip = &mod.intern_pool;
30458 const target = mod.getTarget();30461 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())) {
30461 .ptr => |ptr| switch (ptr.addr) {30464 .ptr => |ptr| switch (ptr.addr) {
30462 .decl, .mut_decl => blk: {30465 .decl, .mut_decl => blk: {
30463 const decl_index = switch (ptr.addr) {30466 const decl_index = switch (ptr.addr) {
...@@ -30478,9 +30481,21 @@ fn beginComptimePtrLoad(...@@ -30478,9 +30481,21 @@ fn beginComptimePtrLoad(
30478 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,30481 .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
30479 };30482 };
30480 },30483 },
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 },
30481 .int => return error.RuntimeLoad,30496 .int => return error.RuntimeLoad,
30482 .eu_payload, .opt_payload => |container_ptr| blk: {30497 .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);
30484 const payload_ty = switch (ptr.addr) {30499 const payload_ty = switch (ptr.addr) {
30485 .eu_payload => container_ty.errorUnionPayload(mod),30500 .eu_payload => container_ty.errorUnionPayload(mod),
30486 .opt_payload => container_ty.optionalChild(mod),30501 .opt_payload => container_ty.optionalChild(mod),
...@@ -30502,13 +30517,13 @@ fn beginComptimePtrLoad(...@@ -30502,13 +30517,13 @@ fn beginComptimePtrLoad(
30502 const payload_val = switch (tv.val.ip_index) {30517 const payload_val = switch (tv.val.ip_index) {
30503 .none => tv.val.cast(Value.Payload.SubValue).?.data,30518 .none => tv.val.cast(Value.Payload.SubValue).?.data,
30504 .null_value => return sema.fail(block, src, "attempt to use null value", .{}),30519 .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())) {
30506 .error_union => |error_union| switch (error_union.val) {30521 .error_union => |error_union| switch (error_union.val) {
30507 .err_name => |err_name| return sema.fail(30522 .err_name => |err_name| return sema.fail(
30508 block,30523 block,
30509 src,30524 src,
30510 "attempt to unwrap error: {}",30525 "attempt to unwrap error: {}",
30511 .{err_name.fmt(&mod.intern_pool)},30526 .{err_name.fmt(ip)},
30512 ),30527 ),
30513 .payload => |payload| payload,30528 .payload => |payload| payload,
30514 },30529 },
...@@ -30527,7 +30542,7 @@ fn beginComptimePtrLoad(...@@ -30527,7 +30542,7 @@ fn beginComptimePtrLoad(
30527 break :blk deref;30542 break :blk deref;
30528 },30543 },
30529 .comptime_field => |comptime_field| blk: {30544 .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();
30531 break :blk ComptimePtrLoadKit{30546 break :blk ComptimePtrLoadKit{
30532 .parent = null,30547 .parent = null,
30533 .pointee = .{ .ty = field_ty, .val = comptime_field.toValue() },30548 .pointee = .{ .ty = field_ty, .val = comptime_field.toValue() },
...@@ -30536,15 +30551,15 @@ fn beginComptimePtrLoad(...@@ -30536,15 +30551,15 @@ fn beginComptimePtrLoad(
30536 };30551 };
30537 },30552 },
30538 .elem => |elem_ptr| blk: {30553 .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);
30540 var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.base.toValue(), null);30555 var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.base.toValue(), null);
3054130556
30542 // This code assumes that elem_ptrs have been "flattened" in order for direct dereference30557 // This code assumes that elem_ptrs have been "flattened" in order for direct dereference
30543 // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that30558 // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that
30544 // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened"30559 // 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)) {
30546 .ptr => |base_ptr| switch (base_ptr.addr) {30561 .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)),
30548 else => {},30563 else => {},
30549 },30564 },
30550 else => {},30565 else => {},
...@@ -30616,7 +30631,7 @@ fn beginComptimePtrLoad(...@@ -30616,7 +30631,7 @@ fn beginComptimePtrLoad(
30616 },30631 },
30617 .field => |field_ptr| blk: {30632 .field => |field_ptr| blk: {
30618 const field_index: u32 = @intCast(field_ptr.index);30633 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);
30620 var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.base.toValue(), container_ty);30635 var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.base.toValue(), container_ty);
3062130636
30622 if (container_ty.hasWellDefinedLayout(mod)) {30637 if (container_ty.hasWellDefinedLayout(mod)) {
...@@ -30655,7 +30670,7 @@ fn beginComptimePtrLoad(...@@ -30655,7 +30670,7 @@ fn beginComptimePtrLoad(
30655 },30670 },
30656 Value.slice_len_index => TypedValue{30671 Value.slice_len_index => TypedValue{
30657 .ty = Type.usize,30672 .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(),
30659 },30674 },
30660 else => unreachable,30675 else => unreachable,
30661 };30676 };
...@@ -34529,7 +34544,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {...@@ -34529,7 +34544,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
34529 else => (try sema.resolveLazyValue(ptr.len.toValue())).toIntern(),34544 else => (try sema.resolveLazyValue(ptr.len.toValue())).toIntern(),
34530 };34545 };
34531 switch (ptr.addr) {34546 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)
34533 val34548 val
34534 else34549 else
34535 (try mod.intern(.{ .ptr = .{34550 (try mod.intern(.{ .ptr = .{
...@@ -34537,6 +34552,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {...@@ -34537,6 +34552,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
34537 .addr = switch (ptr.addr) {34552 .addr = switch (ptr.addr) {
34538 .decl => |decl| .{ .decl = decl },34553 .decl => |decl| .{ .decl = decl },
34539 .mut_decl => |mut_decl| .{ .mut_decl = mut_decl },34554 .mut_decl => |mut_decl| .{ .mut_decl = mut_decl },
34555 .anon_decl => |anon_decl| .{ .anon_decl = anon_decl },
34540 else => unreachable,34556 else => unreachable,
34541 },34557 },
34542 .len = resolved_len,34558 .len = resolved_len,
...@@ -36568,6 +36584,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {...@@ -36568,6 +36584,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
36568 .runtime_value,36584 .runtime_value,
36569 .simple_value,36585 .simple_value,
36570 .ptr_decl,36586 .ptr_decl,
36587 .ptr_anon_decl,
36571 .ptr_mut_decl,36588 .ptr_mut_decl,
36572 .ptr_comptime_field,36589 .ptr_comptime_field,
36573 .ptr_int,36590 .ptr_int,
src/TypedValue.zig+9
...@@ -321,6 +321,15 @@ pub fn print(...@@ -321,6 +321,15 @@ pub fn print(
321 .val = decl.val,321 .val = decl.val,
322 }, writer, level - 1, mod);322 }, writer, level - 1, mod);
323 },323 },
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 },
324 .mut_decl => |mut_decl| {333 .mut_decl => |mut_decl| {
325 const decl = mod.declPtr(mut_decl.decl);334 const decl = mod.declPtr(mut_decl.decl);
326 if (level == 0) return writer.print("(mut decl '{}')", .{decl.name.fmt(ip)});335 if (level == 0) return writer.print("(mut decl '{}')", .{decl.name.fmt(ip)});
src/arch/wasm/CodeGen.zig+28
...@@ -3075,6 +3075,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue...@@ -3075,6 +3075,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue
3075 .decl => |decl_index| {3075 .decl => |decl_index| {
3076 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);3076 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
3077 },3077 },
3078 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, offset),
3078 .mut_decl => |mut_decl| {3079 .mut_decl => |mut_decl| {
3079 const decl_index = mut_decl.decl;3080 const decl_index = mut_decl.decl;
3080 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);3081 return func.lowerParentPtrDecl(ptr_val, decl_index, offset);
...@@ -3138,6 +3139,32 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In...@@ -3138,6 +3139,32 @@ fn lowerParentPtrDecl(func: *CodeGen, ptr_val: Value, decl_index: Module.Decl.In
3138 return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset);3139 return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset);
3139}3140}
31403141
3142fn lowerAnonDeclRef(func: *CodeGen, anon_decl: InternPool.Index, offset: u32) InnerError!WValue {
3143 const mod = func.bin_file.base.options.module.?;
3144 const ty = mod.intern_pool.typeOf(anon_decl).toType();
3145
3146 const is_fn_body = ty.zigTypeTag(mod) == .Fn;
3147 if (!is_fn_body and !ty.hasRuntimeBitsIgnoreComptime(mod)) {
3148 return WValue{ .imm32 = 0xaaaaaaaa };
3149 }
3150
3151 const res = try func.bin_file.lowerAnonDecl(anon_decl, func.decl.srcLoc(mod));
3152 switch (res) {
3153 .ok => {},
3154 .fail => |em| {
3155 func.err_msg = em;
3156 return error.CodegenFail;
3157 },
3158 }
3159 const target_atom_index = func.bin_file.anon_decls.get(anon_decl).?;
3160 const target_sym_index = func.bin_file.getAtom(target_atom_index).getSymbolIndex().?;
3161 if (is_fn_body) {
3162 return WValue{ .function_index = target_sym_index };
3163 } else if (offset == 0) {
3164 return WValue{ .memory = target_sym_index };
3165 } else return WValue{ .memory_offset = .{ .pointer = target_sym_index, .offset = offset } };
3166}
3167
3141fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue {3168fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue {
3142 const mod = func.bin_file.base.options.module.?;3169 const mod = func.bin_file.base.options.module.?;
3143 if (tv.ty.isSlice(mod)) {3170 if (tv.ty.isSlice(mod)) {
...@@ -3305,6 +3332,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {...@@ -3305,6 +3332,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue {
3305 .mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0),3332 .mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0),
3306 .int => |int| return func.lowerConstant(int.toValue(), ip.typeOf(int).toType()),3333 .int => |int| return func.lowerConstant(int.toValue(), ip.typeOf(int).toType()),
3307 .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0),3334 .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0),
3335 .anon_decl => |ad| return func.lowerAnonDeclRef(ad, 0),
3308 else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}),3336 else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}),
3309 },3337 },
3310 .opt => if (ty.optionalReprIsPayload(mod)) {3338 .opt => if (ty.optionalReprIsPayload(mod)) {
src/codegen.zig+45-12
...@@ -643,18 +643,9 @@ fn lowerParentPtr(...@@ -643,18 +643,9 @@ fn lowerParentPtr(
643 const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr;643 const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr;
644 assert(ptr.len == .none);644 assert(ptr.len == .none);
645 return switch (ptr.addr) {645 return switch (ptr.addr) {
646 .decl, .mut_decl => try lowerDeclRef(646 .decl => |decl| try lowerDeclRef(bin_file, src_loc, decl, code, debug_output, reloc_info),
647 bin_file,647 .mut_decl => |md| try lowerDeclRef(bin_file, src_loc, md.decl, code, debug_output, reloc_info),
648 src_loc,648 .anon_decl => |ad| try lowerAnonDeclRef(bin_file, src_loc, ad, code, debug_output, reloc_info),
649 switch (ptr.addr) {
650 .decl => |decl| decl,
651 .mut_decl => |mut_decl| mut_decl.decl,
652 else => unreachable,
653 },
654 code,
655 debug_output,
656 reloc_info,
657 ),
658 .int => |int| try generateSymbol(bin_file, src_loc, .{649 .int => |int| try generateSymbol(bin_file, src_loc, .{
659 .ty = Type.usize,650 .ty = Type.usize,
660 .val = int.toValue(),651 .val = int.toValue(),
...@@ -740,6 +731,48 @@ const RelocInfo = struct {...@@ -740,6 +731,48 @@ const RelocInfo = struct {
740 }731 }
741};732};
742733
734fn lowerAnonDeclRef(
735 bin_file: *link.File,
736 src_loc: Module.SrcLoc,
737 decl_val: InternPool.Index,
738 code: *std.ArrayList(u8),
739 debug_output: DebugInfoOutput,
740 reloc_info: RelocInfo,
741) CodeGenError!Result {
742 _ = debug_output;
743 const target = bin_file.options.target;
744 const mod = bin_file.options.module.?;
745
746 const ptr_width_bytes = @divExact(target.ptrBitWidth(), 8);
747 const decl_ty = mod.intern_pool.typeOf(decl_val).toType();
748 const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn;
749 if (!is_fn_body and !decl_ty.hasRuntimeBits(mod)) {
750 try code.appendNTimes(0xaa, ptr_width_bytes);
751 return Result.ok;
752 }
753
754 const res = try bin_file.lowerAnonDecl(decl_val, src_loc);
755 switch (res) {
756 .ok => {},
757 .fail => |em| return .{ .fail = em },
758 }
759
760 const vaddr = try bin_file.getAnonDeclVAddr(decl_val, .{
761 .parent_atom_index = reloc_info.parent_atom_index,
762 .offset = code.items.len,
763 .addend = reloc_info.addend orelse 0,
764 });
765 const endian = target.cpu.arch.endian();
766 switch (ptr_width_bytes) {
767 2 => mem.writeInt(u16, try code.addManyAsArray(2), @intCast(vaddr), endian),
768 4 => mem.writeInt(u32, try code.addManyAsArray(4), @intCast(vaddr), endian),
769 8 => mem.writeInt(u64, try code.addManyAsArray(8), vaddr, endian),
770 else => unreachable,
771 }
772
773 return Result.ok;
774}
775
743fn lowerDeclRef(776fn lowerDeclRef(
744 bin_file: *link.File,777 bin_file: *link.File,
745 src_loc: Module.SrcLoc,778 src_loc: Module.SrcLoc,
src/codegen/c.zig+94-38
...@@ -528,6 +528,9 @@ pub const DeclGen = struct {...@@ -528,6 +528,9 @@ pub const DeclGen = struct {
528 fwd_decl: std.ArrayList(u8),528 fwd_decl: std.ArrayList(u8),
529 error_msg: ?*Module.ErrorMsg,529 error_msg: ?*Module.ErrorMsg,
530 ctypes: CType.Store,530 ctypes: CType.Store,
531 /// Keeps track of anonymous decls that need to be rendered before this
532 /// (named) Decl in the output C code.
533 anon_decl_deps: std.AutoArrayHashMapUnmanaged(InternPool.Index, C.DeclBlock),
531534
532 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {535 fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } {
533 @setCold(true);536 @setCold(true);
...@@ -540,6 +543,58 @@ pub const DeclGen = struct {...@@ -540,6 +543,58 @@ pub const DeclGen = struct {
540 return error.AnalysisFail;543 return error.AnalysisFail;
541 }544 }
542545
546 fn renderAnonDeclValue(
547 dg: *DeclGen,
548 writer: anytype,
549 ty: Type,
550 ptr_val: Value,
551 decl_val: InternPool.Index,
552 location: ValueRenderLocation,
553 ) error{ OutOfMemory, AnalysisFail }!void {
554 const mod = dg.module;
555 const ip = &mod.intern_pool;
556 const decl_ty = ip.typeOf(decl_val).toType();
557
558 // Render an undefined pointer if we have a pointer to a zero-bit or comptime type.
559 if (ty.isPtrAtRuntime(mod) and !decl_ty.isFnOrHasRuntimeBits(mod)) {
560 return dg.writeCValue(writer, .{ .undef = ty });
561 }
562
563 // Chase function values in order to be able to reference the original function.
564 if (decl_val.toValue().getFunction(mod)) |func| {
565 _ = func;
566 _ = ptr_val;
567 _ = location;
568 @panic("TODO");
569 }
570 if (decl_val.toValue().getExternFunc(mod)) |extern_func| {
571 _ = extern_func;
572 _ = ptr_val;
573 _ = location;
574 @panic("TODO");
575 }
576
577 assert(decl_val.toValue().getVariable(mod) == null);
578
579 // We shouldn't cast C function pointers as this is UB (when you call
580 // them). The analysis until now should ensure that the C function
581 // pointers are compatible. If they are not, then there is a bug
582 // somewhere and we should let the C compiler tell us about it.
583 const need_typecast = if (ty.castPtrToFn(mod)) |_| false else !ty.childType(mod).eql(decl_ty, mod);
584 if (need_typecast) {
585 try writer.writeAll("((");
586 try dg.renderType(writer, ty);
587 try writer.writeByte(')');
588 }
589 try writer.writeByte('&');
590 try renderAnonDeclName(writer, decl_val);
591 if (need_typecast) try writer.writeByte(')');
592
593 // Indicate that the anon decl should be rendered to the output so that
594 // our reference above is not undefined.
595 _ = try dg.anon_decl_deps.getOrPut(dg.gpa, decl_val);
596 }
597
543 fn renderDeclValue(598 fn renderDeclValue(
544 dg: *DeclGen,599 dg: *DeclGen,
545 writer: anytype,600 writer: anytype,
...@@ -593,17 +648,9 @@ pub const DeclGen = struct {...@@ -593,17 +648,9 @@ pub const DeclGen = struct {
593 const ptr_cty = try dg.typeToIndex(ptr_ty, .complete);648 const ptr_cty = try dg.typeToIndex(ptr_ty, .complete);
594 const ptr = mod.intern_pool.indexToKey(ptr_val).ptr;649 const ptr = mod.intern_pool.indexToKey(ptr_val).ptr;
595 switch (ptr.addr) {650 switch (ptr.addr) {
596 .decl, .mut_decl => try dg.renderDeclValue(651 .decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), d, location),
597 writer,652 .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), md.decl, location),
598 ptr_ty,653 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val.toValue(), decl_val, location),
599 ptr_val.toValue(),
600 switch (ptr.addr) {
601 .decl => |decl| decl,
602 .mut_decl => |mut_decl| mut_decl.decl,
603 else => unreachable,
604 },
605 location,
606 ),
607 .int => |int| {654 .int => |int| {
608 try writer.writeByte('(');655 try writer.writeByte('(');
609 try dg.renderCType(writer, ptr_cty);656 try dg.renderCType(writer, ptr_cty);
...@@ -1144,17 +1191,9 @@ pub const DeclGen = struct {...@@ -1144,17 +1191,9 @@ pub const DeclGen = struct {
1144 else => val.slicePtr(mod),1191 else => val.slicePtr(mod),
1145 };1192 };
1146 switch (ptr.addr) {1193 switch (ptr.addr) {
1147 .decl, .mut_decl => try dg.renderDeclValue(1194 .decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val, d, ptr_location),
1148 writer,1195 .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val, md.decl, ptr_location),
1149 ptr_ty,1196 .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val, decl_val, ptr_location),
1150 ptr_val,
1151 switch (ptr.addr) {
1152 .decl => |decl| decl,
1153 .mut_decl => |mut_decl| mut_decl.decl,
1154 else => unreachable,
1155 },
1156 ptr_location,
1157 ),
1158 .int => |int| {1197 .int => |int| {
1159 try writer.writeAll("((");1198 try writer.writeAll("((");
1160 try dg.renderType(writer, ptr_ty);1199 try dg.renderType(writer, ptr_ty);
...@@ -1768,7 +1807,7 @@ pub const DeclGen = struct {...@@ -1768,7 +1807,7 @@ pub const DeclGen = struct {
1768 .none => unreachable,1807 .none => unreachable,
1769 .local, .new_local => |i| return w.print("t{d}", .{i}),1808 .local, .new_local => |i| return w.print("t{d}", .{i}),
1770 .local_ref => |i| return w.print("&t{d}", .{i}),1809 .local_ref => |i| return w.print("&t{d}", .{i}),
1771 .constant => unreachable,1810 .constant => |val| return renderAnonDeclName(w, val),
1772 .arg => |i| return w.print("a{d}", .{i}),1811 .arg => |i| return w.print("a{d}", .{i}),
1773 .arg_array => |i| return dg.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" }),1812 .arg_array => |i| return dg.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" }),
1774 .field => |i| return w.print("f{d}", .{i}),1813 .field => |i| return w.print("f{d}", .{i}),
...@@ -1886,6 +1925,10 @@ pub const DeclGen = struct {...@@ -1886,6 +1925,10 @@ pub const DeclGen = struct {
1886 }1925 }
1887 }1926 }
18881927
1928 fn renderAnonDeclName(writer: anytype, anon_decl_val: InternPool.Index) !void {
1929 return writer.print("__anon_{d}", .{@intFromEnum(anon_decl_val)});
1930 }
1931
1889 fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void {1932 fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void {
1890 try dg.renderCTypeForBuiltinFnName(writer, try dg.typeToCType(ty, .complete));1933 try dg.renderCTypeForBuiltinFnName(writer, try dg.typeToCType(ty, .complete));
1891 }1934 }
...@@ -2723,7 +2766,6 @@ pub fn genDecl(o: *Object) !void {...@@ -2723,7 +2766,6 @@ pub fn genDecl(o: *Object) !void {
27232766
2724 const mod = o.dg.module;2767 const mod = o.dg.module;
2725 const decl_index = o.dg.decl_index.unwrap().?;2768 const decl_index = o.dg.decl_index.unwrap().?;
2726 const decl_c_value = .{ .decl = decl_index };
2727 const decl = mod.declPtr(decl_index);2769 const decl = mod.declPtr(decl_index);
2728 const tv: TypedValue = .{ .ty = decl.ty, .val = (try decl.internValue(mod)).toValue() };2770 const tv: TypedValue = .{ .ty = decl.ty, .val = (try decl.internValue(mod)).toValue() };
27292771
...@@ -2747,6 +2789,7 @@ pub fn genDecl(o: *Object) !void {...@@ -2747,6 +2789,7 @@ pub fn genDecl(o: *Object) !void {
2747 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");2789 if (variable.is_threadlocal) try w.writeAll("zig_threadlocal ");
2748 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|2790 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|
2749 try w.print("zig_linksection(\"{s}\", ", .{s});2791 try w.print("zig_linksection(\"{s}\", ", .{s});
2792 const decl_c_value = .{ .decl = decl_index };
2750 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.alignment, .complete);2793 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.alignment, .complete);
2751 if (decl.@"linksection" != .none) try w.writeAll(", read, write)");2794 if (decl.@"linksection" != .none) try w.writeAll(", read, write)");
2752 try w.writeAll(" = ");2795 try w.writeAll(" = ");
...@@ -2755,22 +2798,35 @@ pub fn genDecl(o: *Object) !void {...@@ -2755,22 +2798,35 @@ pub fn genDecl(o: *Object) !void {
2755 try o.indent_writer.insertNewline();2798 try o.indent_writer.insertNewline();
2756 } else {2799 } else {
2757 const is_global = o.dg.module.decl_exports.contains(decl_index);2800 const is_global = o.dg.module.decl_exports.contains(decl_index);
2758 const fwd_decl_writer = o.dg.fwd_decl.writer();2801 const decl_c_value = .{ .decl = decl_index };
2802 return genDeclValue(o, tv, is_global, decl_c_value, decl.alignment, decl.@"linksection");
2803 }
2804}
27592805
2760 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");2806pub fn genDeclValue(
2761 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, decl.alignment, .complete);2807 o: *Object,
2762 try fwd_decl_writer.writeAll(";\n");2808 tv: TypedValue,
2809 is_global: bool,
2810 decl_c_value: CValue,
2811 alignment: Alignment,
2812 link_section: InternPool.OptionalNullTerminatedString,
2813) !void {
2814 const fwd_decl_writer = o.dg.fwd_decl.writer();
27632815
2764 const w = o.writer();2816 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2765 if (!is_global) try w.writeAll("static ");2817 try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, alignment, .complete);
2766 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|2818 try fwd_decl_writer.writeAll(";\n");
2767 try w.print("zig_linksection(\"{s}\", ", .{s});2819
2768 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.alignment, .complete);2820 const mod = o.dg.module;
2769 if (decl.@"linksection" != .none) try w.writeAll(", read)");2821 const w = o.writer();
2770 try w.writeAll(" = ");2822 if (!is_global) try w.writeAll("static ");
2771 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);2823 if (mod.intern_pool.stringToSliceUnwrap(link_section)) |s|
2772 try w.writeAll(";\n");2824 try w.print("zig_linksection(\"{s}\", ", .{s});
2773 }2825 try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, alignment, .complete);
2826 if (link_section != .none) try w.writeAll(", read)");
2827 try w.writeAll(" = ");
2828 try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer);
2829 try w.writeAll(";\n");
2774}2830}
27752831
2776pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {2832pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
src/codegen/llvm.zig+83-7
...@@ -810,6 +810,8 @@ pub const Object = struct {...@@ -810,6 +810,8 @@ pub const Object = struct {
810 /// * it works for functions not all globals.810 /// * it works for functions not all globals.
811 /// Therefore, this table keeps track of the mapping.811 /// Therefore, this table keeps track of the mapping.
812 decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, Builder.Global.Index),812 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),
813 /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction.815 /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction.
814 named_enum_map: std.AutoHashMapUnmanaged(Module.Decl.Index, Builder.Function.Index),816 named_enum_map: std.AutoHashMapUnmanaged(Module.Decl.Index, Builder.Function.Index),
815 /// Maps Zig types to LLVM types. The table memory is backed by the GPA of817 /// Maps Zig types to LLVM types. The table memory is backed by the GPA of
...@@ -993,6 +995,7 @@ pub const Object = struct {...@@ -993,6 +995,7 @@ pub const Object = struct {
993 .target_data = target_data,995 .target_data = target_data,
994 .target = options.target,996 .target = options.target,
995 .decl_map = .{},997 .decl_map = .{},
998 .anon_decl_map = .{},
996 .named_enum_map = .{},999 .named_enum_map = .{},
997 .type_map = .{},1000 .type_map = .{},
998 .di_type_map = .{},1001 .di_type_map = .{},
...@@ -1011,6 +1014,7 @@ pub const Object = struct {...@@ -1011,6 +1014,7 @@ pub const Object = struct {
1011 self.target_machine.dispose();1014 self.target_machine.dispose();
1012 }1015 }
1013 self.decl_map.deinit(gpa);1016 self.decl_map.deinit(gpa);
1017 self.anon_decl_map.deinit(gpa);
1014 self.named_enum_map.deinit(gpa);1018 self.named_enum_map.deinit(gpa);
1015 self.type_map.deinit(gpa);1019 self.type_map.deinit(gpa);
1016 self.extern_collisions.deinit(gpa);1020 self.extern_collisions.deinit(gpa);
...@@ -3038,6 +3042,31 @@ pub const Object = struct {...@@ -3038,6 +3042,31 @@ pub const Object = struct {
3038 }3042 }
3039 }3043 }
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
3041 fn resolveGlobalDecl(3070 fn resolveGlobalDecl(
3042 o: *Object,3071 o: *Object,
3043 decl_index: Module.Decl.Index,3072 decl_index: Module.Decl.Index,
...@@ -3764,6 +3793,7 @@ pub const Object = struct {...@@ -3764,6 +3793,7 @@ pub const Object = struct {
3764 const ptr_val = switch (ptr.addr) {3793 const ptr_val = switch (ptr.addr) {
3765 .decl => |decl| try o.lowerDeclRefValue(ptr_ty, decl),3794 .decl => |decl| try o.lowerDeclRefValue(ptr_ty, decl),
3766 .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_ty, mut_decl.decl),3795 .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_ty, mut_decl.decl),
3796 .anon_decl => |anon_decl| try o.lowerAnonDeclRef(ptr_ty, anon_decl),
3767 .int => |int| try o.lowerIntAsPtr(int),3797 .int => |int| try o.lowerIntAsPtr(int),
3768 .eu_payload,3798 .eu_payload,
3769 .opt_payload,3799 .opt_payload,
...@@ -4216,10 +4246,12 @@ pub const Object = struct {...@@ -4216,10 +4246,12 @@ pub const Object = struct {
4216 return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint);4246 return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint);
4217 }4247 }
42184248
4219 const ParentPtr = struct {4249 fn lowerParentPtrAnonDecl(o: *Object, decl_val: InternPool.Index) Error!Builder.Constant {
4220 ty: Type,4250 const mod = o.module;
4221 llvm_ptr: Builder.Value,4251 const decl_ty = mod.intern_pool.typeOf(decl_val).toType();
4222 };4252 const ptr_ty = try mod.singleMutPtrType(decl_ty);
4253 return o.lowerAnonDeclRef(ptr_ty, decl_val);
4254 }
42234255
4224 fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {4256 fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {
4225 const mod = o.module;4257 const mod = o.module;
...@@ -4229,13 +4261,14 @@ pub const Object = struct {...@@ -4229,13 +4261,14 @@ pub const Object = struct {
4229 return o.lowerDeclRefValue(ptr_ty, decl_index);4261 return o.lowerDeclRefValue(ptr_ty, decl_index);
4230 }4262 }
42314263
4232 fn lowerParentPtr(o: *Object, ptr_val: Value) Allocator.Error!Builder.Constant {4264 fn lowerParentPtr(o: *Object, ptr_val: Value) Error!Builder.Constant {
4233 const mod = o.module;4265 const mod = o.module;
4234 const ip = &mod.intern_pool;4266 const ip = &mod.intern_pool;
4235 const ptr = ip.indexToKey(ptr_val.toIntern()).ptr;4267 const ptr = ip.indexToKey(ptr_val.toIntern()).ptr;
4236 return switch (ptr.addr) {4268 return switch (ptr.addr) {
4237 .decl => |decl| o.lowerParentPtrDecl(decl),4269 .decl => |decl| try o.lowerParentPtrDecl(decl),
4238 .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl),4270 .mut_decl => |mut_decl| try o.lowerParentPtrDecl(mut_decl.decl),
4271 .anon_decl => |anon_decl| try o.lowerParentPtrAnonDecl(anon_decl),
4239 .int => |int| try o.lowerIntAsPtr(int),4272 .int => |int| try o.lowerIntAsPtr(int),
4240 .eu_payload => |eu_ptr| {4273 .eu_payload => |eu_ptr| {
4241 const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue());4274 const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue());
...@@ -4349,6 +4382,49 @@ pub const Object = struct {...@@ -4349,6 +4382,49 @@ pub const Object = struct {
4349 };4382 };
4350 }4383 }
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
4352 fn lowerDeclRefValue(o: *Object, ty: Type, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {4428 fn lowerDeclRefValue(o: *Object, ty: Type, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {
4353 const mod = o.module;4429 const mod = o.module;
43544430
src/codegen/spirv.zig+1
...@@ -818,6 +818,7 @@ pub const DeclGen = struct {...@@ -818,6 +818,7 @@ pub const DeclGen = struct {
818 const mod = self.module;818 const mod = self.module;
819 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {819 switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
820 .decl => |decl| return try self.constructDeclRef(ptr_ty, decl),820 .decl => |decl| return try self.constructDeclRef(ptr_ty, decl),
821 .anon_decl => @panic("TODO"),
821 .mut_decl => |decl_mut| return try self.constructDeclRef(ptr_ty, decl_mut.decl),822 .mut_decl => |decl_mut| return try self.constructDeclRef(ptr_ty, decl_mut.decl),
822 .int => |int| {823 .int => |int| {
823 const ptr_id = self.spv.allocId();824 const ptr_id = self.spv.allocId();
src/link.zig+30
...@@ -937,6 +937,36 @@ pub const File = struct {...@@ -937,6 +937,36 @@ pub const File = struct {
937 }937 }
938 }938 }
939939
940 pub const LowerResult = @import("codegen.zig").Result;
941
942 pub fn lowerAnonDecl(base: *File, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !LowerResult {
943 if (build_options.only_c) unreachable;
944 switch (base.tag) {
945 .coff => return @fieldParentPtr(Coff, "base", base).lowerAnonDecl(decl_val, src_loc),
946 .elf => return @fieldParentPtr(Elf, "base", base).lowerAnonDecl(decl_val, src_loc),
947 .macho => return @fieldParentPtr(MachO, "base", base).lowerAnonDecl(decl_val, src_loc),
948 .plan9 => return @fieldParentPtr(Plan9, "base", base).lowerAnonDecl(decl_val, src_loc),
949 .c => unreachable,
950 .wasm => return @fieldParentPtr(Wasm, "base", base).lowerAnonDecl(decl_val, src_loc),
951 .spirv => unreachable,
952 .nvptx => unreachable,
953 }
954 }
955
956 pub fn getAnonDeclVAddr(base: *File, decl_val: InternPool.Index, reloc_info: RelocInfo) !u64 {
957 if (build_options.only_c) unreachable;
958 switch (base.tag) {
959 .coff => return @fieldParentPtr(Coff, "base", base).getAnonDeclVAddr(decl_val, reloc_info),
960 .elf => return @fieldParentPtr(Elf, "base", base).getAnonDeclVAddr(decl_val, reloc_info),
961 .macho => return @fieldParentPtr(MachO, "base", base).getAnonDeclVAddr(decl_val, reloc_info),
962 .plan9 => return @fieldParentPtr(Plan9, "base", base).getAnonDeclVAddr(decl_val, reloc_info),
963 .c => unreachable,
964 .wasm => return @fieldParentPtr(Wasm, "base", base).getAnonDeclVAddr(decl_val, reloc_info),
965 .spirv => unreachable,
966 .nvptx => unreachable,
967 }
968 }
969
940 /// This function is called by the frontend before flush(). It communicates that970 /// This function is called by the frontend before flush(). It communicates that
941 /// `options.bin_file.emit` directory needs to be renamed from971 /// `options.bin_file.emit` directory needs to be renamed from
942 /// `[zig-cache]/tmp/[random]` to `[zig-cache]/o/[digest]`.972 /// `[zig-cache]/tmp/[random]` to `[zig-cache]/o/[digest]`.
src/link/C.zig+122-23
...@@ -27,6 +27,9 @@ decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclBlock) = .{},...@@ -27,6 +27,9 @@ decl_table: std.AutoArrayHashMapUnmanaged(Module.Decl.Index, DeclBlock) = .{},
27/// While in progress, a separate buffer is used, and then when finished, the27/// While in progress, a separate buffer is used, and then when finished, the
28/// buffer is copied into this one.28/// buffer is copied into this one.
29string_bytes: std.ArrayListUnmanaged(u8) = .{},29string_bytes: std.ArrayListUnmanaged(u8) = .{},
30/// Tracks all the anonymous decls that are used by all the decls so they can
31/// be rendered during flush().
32anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, DeclBlock) = .{},
3033
31/// Optimization, `updateDecl` reuses this buffer rather than creating a new34/// Optimization, `updateDecl` reuses this buffer rather than creating a new
32/// one with every call.35/// one with every call.
...@@ -42,7 +45,7 @@ lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},...@@ -42,7 +45,7 @@ lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},
42lazy_code_buf: std.ArrayListUnmanaged(u8) = .{},45lazy_code_buf: std.ArrayListUnmanaged(u8) = .{},
4346
44/// A reference into `string_bytes`.47/// A reference into `string_bytes`.
45const String = struct {48const String = extern struct {
46 start: u32,49 start: u32,
47 len: u32,50 len: u32,
4851
...@@ -53,7 +56,7 @@ const String = struct {...@@ -53,7 +56,7 @@ const String = struct {
53};56};
5457
55/// Per-declaration data.58/// Per-declaration data.
56const DeclBlock = struct {59pub const DeclBlock = struct {
57 code: String = String.empty,60 code: String = String.empty,
58 fwd_decl: String = String.empty,61 fwd_decl: String = String.empty,
59 /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate62 /// Each `Decl` stores a set of used `CType`s. In `flush()`, we iterate
...@@ -98,7 +101,7 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C...@@ -98,7 +101,7 @@ pub fn openPath(gpa: Allocator, sub_path: []const u8, options: link.Options) !*C
98 var c_file = try gpa.create(C);101 var c_file = try gpa.create(C);
99 errdefer gpa.destroy(c_file);102 errdefer gpa.destroy(c_file);
100103
101 c_file.* = C{104 c_file.* = .{
102 .base = .{105 .base = .{
103 .tag = .c,106 .tag = .c,
104 .options = options,107 .options = options,
...@@ -118,6 +121,11 @@ pub fn deinit(self: *C) void {...@@ -118,6 +121,11 @@ pub fn deinit(self: *C) void {
118 }121 }
119 self.decl_table.deinit(gpa);122 self.decl_table.deinit(gpa);
120123
124 for (self.anon_decls.values()) |*db| {
125 db.deinit(gpa);
126 }
127 self.anon_decls.deinit(gpa);
128
121 self.string_bytes.deinit(gpa);129 self.string_bytes.deinit(gpa);
122 self.fwd_decl_buf.deinit(gpa);130 self.fwd_decl_buf.deinit(gpa);
123 self.code_buf.deinit(gpa);131 self.code_buf.deinit(gpa);
...@@ -131,10 +139,13 @@ pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void {...@@ -131,10 +139,13 @@ pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void {
131 }139 }
132}140}
133141
134pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void {142pub fn updateFunc(
135 const tracy = trace(@src());143 self: *C,
136 defer tracy.end();144 module: *Module,
137145 func_index: InternPool.Index,
146 air: Air,
147 liveness: Liveness,
148) !void {
138 const gpa = self.base.allocator;149 const gpa = self.base.allocator;
139150
140 const func = module.funcInfo(func_index);151 const func = module.funcInfo(func_index);
...@@ -167,6 +178,7 @@ pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air:...@@ -167,6 +178,7 @@ pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air:
167 .is_naked_fn = decl.ty.fnCallingConvention(module) == .Naked,178 .is_naked_fn = decl.ty.fnCallingConvention(module) == .Naked,
168 .fwd_decl = fwd_decl.toManaged(gpa),179 .fwd_decl = fwd_decl.toManaged(gpa),
169 .ctypes = ctypes.*,180 .ctypes = ctypes.*,
181 .anon_decl_deps = self.anon_decls,
170 },182 },
171 .code = code.toManaged(gpa),183 .code = code.toManaged(gpa),
172 .indent_writer = undefined, // set later so we can get a pointer to object.code184 .indent_writer = undefined, // set later so we can get a pointer to object.code
...@@ -176,6 +188,7 @@ pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air:...@@ -176,6 +188,7 @@ pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air:
176188
177 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };189 function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() };
178 defer {190 defer {
191 self.anon_decls = function.object.dg.anon_decl_deps;
179 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();192 fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged();
180 code.* = function.object.code.moveToUnmanaged();193 code.* = function.object.code.moveToUnmanaged();
181 function.deinit();194 function.deinit();
...@@ -200,6 +213,62 @@ pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air:...@@ -200,6 +213,62 @@ pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air:
200 gop.value_ptr.fwd_decl = try self.addString(function.object.dg.fwd_decl.items);213 gop.value_ptr.fwd_decl = try self.addString(function.object.dg.fwd_decl.items);
201}214}
202215
216fn updateAnonDecl(self: *C, module: *Module, i: usize) !void {
217 const gpa = self.base.allocator;
218 const anon_decl = self.anon_decls.keys()[i];
219
220 const fwd_decl = &self.fwd_decl_buf;
221 const code = &self.code_buf;
222 fwd_decl.clearRetainingCapacity();
223 code.clearRetainingCapacity();
224
225 var object: codegen.Object = .{
226 .dg = .{
227 .gpa = gpa,
228 .module = module,
229 .error_msg = null,
230 .decl_index = .none,
231 .is_naked_fn = false,
232 .fwd_decl = fwd_decl.toManaged(gpa),
233 .ctypes = .{},
234 .anon_decl_deps = self.anon_decls,
235 },
236 .code = code.toManaged(gpa),
237 .indent_writer = undefined, // set later so we can get a pointer to object.code
238 };
239 object.indent_writer = .{ .underlying_writer = object.code.writer() };
240
241 defer {
242 self.anon_decls = object.dg.anon_decl_deps;
243 object.dg.ctypes.deinit(object.dg.gpa);
244 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
245 code.* = object.code.moveToUnmanaged();
246 }
247
248 const tv: @import("../TypedValue.zig") = .{
249 .ty = module.intern_pool.typeOf(anon_decl).toType(),
250 .val = anon_decl.toValue(),
251 };
252 const c_value: codegen.CValue = .{ .constant = anon_decl };
253 codegen.genDeclValue(&object, tv, false, c_value, .none, .none) catch |err| switch (err) {
254 error.AnalysisFail => {
255 @panic("TODO: C backend AnalysisFail on anonymous decl");
256 //try module.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
257 //return;
258 },
259 else => |e| return e,
260 };
261
262 // Free excess allocated memory for this Decl.
263 object.dg.ctypes.shrinkAndFree(gpa, object.dg.ctypes.count());
264
265 object.dg.anon_decl_deps.values()[i] = .{
266 .code = try self.addString(object.code.items),
267 .fwd_decl = try self.addString(object.dg.fwd_decl.items),
268 .ctypes = object.dg.ctypes.move(),
269 };
270}
271
203pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {272pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !void {
204 const tracy = trace(@src());273 const tracy = trace(@src());
205 defer tracy.end();274 defer tracy.end();
...@@ -226,12 +295,14 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi...@@ -226,12 +295,14 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi
226 .is_naked_fn = false,295 .is_naked_fn = false,
227 .fwd_decl = fwd_decl.toManaged(gpa),296 .fwd_decl = fwd_decl.toManaged(gpa),
228 .ctypes = ctypes.*,297 .ctypes = ctypes.*,
298 .anon_decl_deps = self.anon_decls,
229 },299 },
230 .code = code.toManaged(gpa),300 .code = code.toManaged(gpa),
231 .indent_writer = undefined, // set later so we can get a pointer to object.code301 .indent_writer = undefined, // set later so we can get a pointer to object.code
232 };302 };
233 object.indent_writer = .{ .underlying_writer = object.code.writer() };303 object.indent_writer = .{ .underlying_writer = object.code.writer() };
234 defer {304 defer {
305 self.anon_decls = object.dg.anon_decl_deps;
235 object.dg.ctypes.deinit(object.dg.gpa);306 object.dg.ctypes.deinit(object.dg.gpa);
236 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();307 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
237 code.* = object.code.moveToUnmanaged();308 code.* = object.code.moveToUnmanaged();
...@@ -289,6 +360,13 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo...@@ -289,6 +360,13 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
289 const gpa = self.base.allocator;360 const gpa = self.base.allocator;
290 const module = self.base.options.module.?;361 const module = self.base.options.module.?;
291362
363 {
364 var i: usize = 0;
365 while (i < self.anon_decls.count()) : (i += 1) {
366 try updateAnonDecl(self, module, i);
367 }
368 }
369
292 // This code path happens exclusively with -ofmt=c. The flush logic for370 // This code path happens exclusively with -ofmt=c. The flush logic for
293 // emit-h is in `flushEmitH` below.371 // emit-h is in `flushEmitH` below.
294372
...@@ -331,10 +409,15 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo...@@ -331,10 +409,15 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
331 for (module.decl_exports.values()) |exports| for (exports.items) |@"export"|409 for (module.decl_exports.values()) |exports| for (exports.items) |@"export"|
332 try export_names.put(gpa, @"export".opts.name, {});410 try export_names.put(gpa, @"export".opts.name, {});
333411
334 const decl_keys = self.decl_table.keys();412 for (self.anon_decls.values()) |*decl_block| {
335 for (decl_keys) |decl_index| {413 try self.flushDeclBlock(&f, decl_block, export_names, .none);
414 }
415
416 for (self.decl_table.keys(), self.decl_table.values()) |decl_index, *decl_block| {
336 assert(module.declPtr(decl_index).has_tv);417 assert(module.declPtr(decl_index).has_tv);
337 try self.flushDecl(&f, decl_index, export_names);418 const decl = module.declPtr(decl_index);
419 const extern_symbol_name = if (decl.isExtern(module)) decl.name.toOptional() else .none;
420 try self.flushDeclBlock(&f, decl_block, export_names, extern_symbol_name);
338 }421 }
339 }422 }
340423
...@@ -344,8 +427,12 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo...@@ -344,8 +427,12 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
344 assert(f.ctypes.count() == 0);427 assert(f.ctypes.count() == 0);
345 try self.flushCTypes(&f, .none, f.lazy_ctypes);428 try self.flushCTypes(&f, .none, f.lazy_ctypes);
346429
347 for (self.decl_table.keys(), self.decl_table.values()) |decl_index, db| {430 for (self.anon_decls.values()) |decl_block| {
348 try self.flushCTypes(&f, decl_index.toOptional(), db.ctypes);431 try self.flushCTypes(&f, .none, decl_block.ctypes);
432 }
433
434 for (self.decl_table.keys(), self.decl_table.values()) |decl_index, decl_block| {
435 try self.flushCTypes(&f, decl_index.toOptional(), decl_block.ctypes);
349 }436 }
350 }437 }
351438
...@@ -363,10 +450,12 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo...@@ -363,10 +450,12 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo
363 f.file_size += lazy_fwd_decl_len;450 f.file_size += lazy_fwd_decl_len;
364451
365 // Now the code.452 // Now the code.
453 const anon_decl_values = self.anon_decls.values();
366 const decl_values = self.decl_table.values();454 const decl_values = self.decl_table.values();
367 try f.all_buffers.ensureUnusedCapacity(gpa, 1 + decl_values.len);455 try f.all_buffers.ensureUnusedCapacity(gpa, 1 + anon_decl_values.len + decl_values.len);
368 f.appendBufAssumeCapacity(self.lazy_code_buf.items);456 f.appendBufAssumeCapacity(self.lazy_code_buf.items);
369 for (decl_values) |decl| f.appendBufAssumeCapacity(self.getString(decl.code));457 for (anon_decl_values) |db| f.appendBufAssumeCapacity(self.getString(db.code));
458 for (decl_values) |db| f.appendBufAssumeCapacity(self.getString(db.code));
370459
371 const file = self.base.file.?;460 const file = self.base.file.?;
372 try file.setEndPos(f.file_size);461 try file.setEndPos(f.file_size);
...@@ -512,12 +601,14 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {...@@ -512,12 +601,14 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
512 .is_naked_fn = false,601 .is_naked_fn = false,
513 .fwd_decl = fwd_decl.toManaged(gpa),602 .fwd_decl = fwd_decl.toManaged(gpa),
514 .ctypes = ctypes.*,603 .ctypes = ctypes.*,
604 .anon_decl_deps = self.anon_decls,
515 },605 },
516 .code = code.toManaged(gpa),606 .code = code.toManaged(gpa),
517 .indent_writer = undefined, // set later so we can get a pointer to object.code607 .indent_writer = undefined, // set later so we can get a pointer to object.code
518 };608 };
519 object.indent_writer = .{ .underlying_writer = object.code.writer() };609 object.indent_writer = .{ .underlying_writer = object.code.writer() };
520 defer {610 defer {
611 self.anon_decls = object.dg.anon_decl_deps;
521 object.dg.ctypes.deinit(gpa);612 object.dg.ctypes.deinit(gpa);
522 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();613 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
523 code.* = object.code.moveToUnmanaged();614 code.* = object.code.moveToUnmanaged();
...@@ -531,7 +622,11 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {...@@ -531,7 +622,11 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void {
531 ctypes.* = object.dg.ctypes.move();622 ctypes.* = object.dg.ctypes.move();
532}623}
533624
534fn flushLazyFn(self: *C, ctypes: *codegen.CType.Store, lazy_fn: codegen.LazyFnMap.Entry) FlushDeclError!void {625fn flushLazyFn(
626 self: *C,
627 ctypes: *codegen.CType.Store,
628 lazy_fn: codegen.LazyFnMap.Entry,
629) FlushDeclError!void {
535 const gpa = self.base.allocator;630 const gpa = self.base.allocator;
536631
537 const fwd_decl = &self.lazy_fwd_decl_buf;632 const fwd_decl = &self.lazy_fwd_decl_buf;
...@@ -546,12 +641,16 @@ fn flushLazyFn(self: *C, ctypes: *codegen.CType.Store, lazy_fn: codegen.LazyFnMa...@@ -546,12 +641,16 @@ fn flushLazyFn(self: *C, ctypes: *codegen.CType.Store, lazy_fn: codegen.LazyFnMa
546 .is_naked_fn = false,641 .is_naked_fn = false,
547 .fwd_decl = fwd_decl.toManaged(gpa),642 .fwd_decl = fwd_decl.toManaged(gpa),
548 .ctypes = ctypes.*,643 .ctypes = ctypes.*,
644 .anon_decl_deps = .{},
549 },645 },
550 .code = code.toManaged(gpa),646 .code = code.toManaged(gpa),
551 .indent_writer = undefined, // set later so we can get a pointer to object.code647 .indent_writer = undefined, // set later so we can get a pointer to object.code
552 };648 };
553 object.indent_writer = .{ .underlying_writer = object.code.writer() };649 object.indent_writer = .{ .underlying_writer = object.code.writer() };
554 defer {650 defer {
651 // If this assert trips just handle the anon_decl_deps the same as
652 // `updateFunc()` does.
653 assert(object.dg.anon_decl_deps.count() == 0);
555 object.dg.ctypes.deinit(gpa);654 object.dg.ctypes.deinit(gpa);
556 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();655 fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged();
557 code.* = object.code.moveToUnmanaged();656 code.* = object.code.moveToUnmanaged();
...@@ -578,22 +677,22 @@ fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError...@@ -578,22 +677,22 @@ fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError
578 }677 }
579}678}
580679
581fn flushDecl(680fn flushDeclBlock(
582 self: *C,681 self: *C,
583 f: *Flush,682 f: *Flush,
584 decl_index: Module.Decl.Index,683 decl_block: *DeclBlock,
585 export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),684 export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),
685 extern_symbol_name: InternPool.OptionalNullTerminatedString,
586) FlushDeclError!void {686) FlushDeclError!void {
587 const gpa = self.base.allocator;687 const gpa = self.base.allocator;
588 const mod = self.base.options.module.?;
589 const decl = mod.declPtr(decl_index);
590
591 const decl_block = self.decl_table.getPtr(decl_index).?;
592
593 try self.flushLazyFns(f, decl_block.lazy_fns);688 try self.flushLazyFns(f, decl_block.lazy_fns);
594 try f.all_buffers.ensureUnusedCapacity(gpa, 1);689 try f.all_buffers.ensureUnusedCapacity(gpa, 1);
595 if (!(decl.isExtern(mod) and export_names.contains(decl.name)))690 fwd_decl: {
691 if (extern_symbol_name.unwrap()) |name| {
692 if (export_names.contains(name)) break :fwd_decl;
693 }
596 f.appendBufAssumeCapacity(self.getString(decl_block.fwd_decl));694 f.appendBufAssumeCapacity(self.getString(decl_block.fwd_decl));
695 }
597}696}
598697
599pub fn flushEmitH(module: *Module) !void {698pub fn flushEmitH(module: *Module) !void {
src/link/Coff.zig+94-28
...@@ -82,6 +82,7 @@ atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},...@@ -82,6 +82,7 @@ atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},
82/// value assigned to label `foo` is an unnamed constant belonging/associated82/// value assigned to label `foo` is an unnamed constant belonging/associated
83/// with `Decl` `main`, and lives as long as that `Decl`.83/// with `Decl` `main`, and lives as long as that `Decl`.
84unnamed_const_atoms: UnnamedConstTable = .{},84unnamed_const_atoms: UnnamedConstTable = .{},
85anon_decls: AnonDeclTable = .{},
8586
86/// A table of relocations indexed by the owning them `Atom`.87/// A table of relocations indexed by the owning them `Atom`.
87/// Note that once we refactor `Atom`'s lifetime and ownership rules,88/// Note that once we refactor `Atom`'s lifetime and ownership rules,
...@@ -107,6 +108,7 @@ const HotUpdateState = struct {...@@ -107,6 +108,7 @@ const HotUpdateState = struct {
107 loaded_base_address: ?std.os.windows.HMODULE = null,108 loaded_base_address: ?std.os.windows.HMODULE = null,
108};109};
109110
111const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index);
110const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));112const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation));
111const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));113const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
112const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));114const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
...@@ -323,6 +325,7 @@ pub fn deinit(self: *Coff) void {...@@ -323,6 +325,7 @@ pub fn deinit(self: *Coff) void {
323 atoms.deinit(gpa);325 atoms.deinit(gpa);
324 }326 }
325 self.unnamed_const_atoms.deinit(gpa);327 self.unnamed_const_atoms.deinit(gpa);
328 self.anon_decls.deinit(gpa);
326329
327 for (self.relocs.values()) |*relocs| {330 for (self.relocs.values()) |*relocs| {
328 relocs.deinit(gpa);331 relocs.deinit(gpa);
...@@ -1077,45 +1080,53 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:...@@ -1077,45 +1080,53 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:
10771080
1078pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.Index) !u32 {1081pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.Index) !u32 {
1079 const gpa = self.base.allocator;1082 const gpa = self.base.allocator;
1080 var code_buffer = std.ArrayList(u8).init(gpa);
1081 defer code_buffer.deinit();
1082
1083 const mod = self.base.options.module.?;1083 const mod = self.base.options.module.?;
1084 const decl = mod.declPtr(decl_index);1084 const decl = mod.declPtr(decl_index);
1085
1086 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);1085 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);
1087 if (!gop.found_existing) {1086 if (!gop.found_existing) {
1088 gop.value_ptr.* = .{};1087 gop.value_ptr.* = .{};
1089 }1088 }
1090 const unnamed_consts = gop.value_ptr;1089 const unnamed_consts = gop.value_ptr;
1090 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
1091 const index = unnamed_consts.items.len;
1092 const sym_name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
1093 defer gpa.free(sym_name);
1094 const atom_index = switch (try self.lowerConst(sym_name, tv, self.rdata_section_index.?, decl.srcLoc(mod))) {
1095 .ok => |atom_index| atom_index,
1096 .fail => |em| {
1097 decl.analysis = .codegen_failure;
1098 try mod.failed_decls.put(mod.gpa, decl_index, em);
1099 log.err("{s}", .{em.msg});
1100 return error.CodegenFail;
1101 },
1102 };
1103 try unnamed_consts.append(gpa, atom_index);
1104 return self.getAtom(atom_index).getSymbolIndex().?;
1105}
10911106
1092 const atom_index = try self.createAtom();1107const LowerConstResult = union(enum) {
1108 ok: Atom.Index,
1109 fail: *Module.ErrorMsg,
1110};
10931111
1094 const sym_name = blk: {1112fn lowerConst(self: *Coff, name: []const u8, tv: TypedValue, sect_id: u16, src_loc: Module.SrcLoc) !LowerConstResult {
1095 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));1113 const gpa = self.base.allocator;
10961114
1097 const index = unnamed_consts.items.len;1115 var code_buffer = std.ArrayList(u8).init(gpa);
1098 break :blk try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });1116 defer code_buffer.deinit();
1099 };1117
1100 defer gpa.free(sym_name);1118 const mod = self.base.options.module.?;
1101 {1119 const atom_index = try self.createAtom();
1102 const atom = self.getAtom(atom_index);1120 const sym = self.getAtom(atom_index).getSymbolPtr(self);
1103 const sym = atom.getSymbolPtr(self);1121 try self.setSymbolName(sym, name);
1104 try self.setSymbolName(sym, sym_name);1122 sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_id + 1));
1105 sym.section_number = @as(coff.SectionNumber, @enumFromInt(self.rdata_section_index.? + 1));
1106 }
11071123
1108 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), tv, &code_buffer, .none, .{1124 const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .none, .{
1109 .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,1125 .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,
1110 });1126 });
1111 var code = switch (res) {1127 var code = switch (res) {
1112 .ok => code_buffer.items,1128 .ok => code_buffer.items,
1113 .fail => |em| {1129 .fail => |em| return .{ .fail = em },
1114 decl.analysis = .codegen_failure;
1115 try mod.failed_decls.put(mod.gpa, decl_index, em);
1116 log.err("{s}", .{em.msg});
1117 return error.CodegenFail;
1118 },
1119 };1130 };
11201131
1121 const required_alignment: u32 = @intCast(tv.ty.abiAlignment(mod).toByteUnits(0));1132 const required_alignment: u32 = @intCast(tv.ty.abiAlignment(mod).toByteUnits(0));
...@@ -1124,14 +1135,12 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In...@@ -1124,14 +1135,12 @@ pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.In
1124 atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment);1135 atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment);
1125 errdefer self.freeAtom(atom_index);1136 errdefer self.freeAtom(atom_index);
11261137
1127 try unnamed_consts.append(gpa, atom_index);1138 log.debug("allocated atom for {s} at 0x{x}", .{ name, atom.getSymbol(self).value });
1128
1129 log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, atom.getSymbol(self).value });
1130 log.debug(" (required alignment 0x{x})", .{required_alignment});1139 log.debug(" (required alignment 0x{x})", .{required_alignment});
11311140
1132 try self.writeAtom(atom_index, code);1141 try self.writeAtom(atom_index, code);
11331142
1134 return atom.getSymbolIndex().?;1143 return .{ .ok = atom_index };
1135}1144}
11361145
1137pub fn updateDecl(1146pub fn updateDecl(
...@@ -1727,6 +1736,63 @@ pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link...@@ -1727,6 +1736,63 @@ pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link
1727 return 0;1736 return 0;
1728}1737}
17291738
1739pub fn lowerAnonDecl(self: *Coff, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
1740 // This is basically the same as lowerUnnamedConst.
1741 // example:
1742 // const ty = mod.intern_pool.typeOf(decl_val).toType();
1743 // const val = decl_val.toValue();
1744 // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`.
1745 // It doesn't have an owner decl because it's just an unnamed constant that might
1746 // be used by more than one function, however, its address is being used so we need
1747 // to put it in some location.
1748 // ...
1749 const gpa = self.base.allocator;
1750 const gop = try self.anon_decls.getOrPut(gpa, decl_val);
1751 if (!gop.found_existing) {
1752 const mod = self.base.options.module.?;
1753 const ty = mod.intern_pool.typeOf(decl_val).toType();
1754 const val = decl_val.toValue();
1755 const tv = TypedValue{ .ty = ty, .val = val };
1756 const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)});
1757 defer gpa.free(name);
1758 const res = self.lowerConst(name, tv, self.rdata_section_index.?, src_loc) catch |err| switch (err) {
1759 else => {
1760 // TODO improve error message
1761 const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{
1762 @errorName(err),
1763 });
1764 return .{ .fail = em };
1765 },
1766 };
1767 const atom_index = switch (res) {
1768 .ok => |atom_index| atom_index,
1769 .fail => |em| return .{ .fail = em },
1770 };
1771 gop.value_ptr.* = atom_index;
1772 }
1773 return .ok;
1774}
1775
1776pub fn getAnonDeclVAddr(self: *Coff, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
1777 assert(self.llvm_object == null);
1778
1779 const this_atom_index = self.anon_decls.get(decl_val).?;
1780 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
1781 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index, .file = null }).?;
1782 const target = SymbolWithLoc{ .sym_index = sym_index, .file = null };
1783 try Atom.addRelocation(self, atom_index, .{
1784 .type = .direct,
1785 .target = target,
1786 .offset = @as(u32, @intCast(reloc_info.offset)),
1787 .addend = reloc_info.addend,
1788 .pcrel = false,
1789 .length = 3,
1790 });
1791 try Atom.addBaseRelocation(self, atom_index, @as(u32, @intCast(reloc_info.offset)));
1792
1793 return 0;
1794}
1795
1730pub fn getGlobalSymbol(self: *Coff, name: []const u8, lib_name_name: ?[]const u8) !u32 {1796pub fn getGlobalSymbol(self: *Coff, name: []const u8, lib_name_name: ?[]const u8) !u32 {
1731 const gop = try self.getOrPutGlobalPtr(name);1797 const gop = try self.getOrPutGlobalPtr(name);
1732 const global_index = self.getGlobalIndex(name).?;1798 const global_index = self.getGlobalIndex(name).?;
src/link/Elf.zig+97-28
...@@ -155,12 +155,14 @@ last_atom_and_free_list_table: std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFre...@@ -155,12 +155,14 @@ last_atom_and_free_list_table: std.AutoArrayHashMapUnmanaged(u16, LastAtomAndFre
155/// value assigned to label `foo` is an unnamed constant belonging/associated155/// value assigned to label `foo` is an unnamed constant belonging/associated
156/// with `Decl` `main`, and lives as long as that `Decl`.156/// with `Decl` `main`, and lives as long as that `Decl`.
157unnamed_consts: UnnamedConstTable = .{},157unnamed_consts: UnnamedConstTable = .{},
158anon_decls: AnonDeclTable = .{},
158159
159comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},160comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{},
160comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},161comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{},
161comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},162comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{},
162163
163const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));164const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index));
165const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Symbol.Index);
164const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);166const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata);
165167
166/// When allocating, the ideal_capacity is calculated by168/// When allocating, the ideal_capacity is calculated by
...@@ -321,6 +323,7 @@ pub fn deinit(self: *Elf) void {...@@ -321,6 +323,7 @@ pub fn deinit(self: *Elf) void {
321 }323 }
322 self.unnamed_consts.deinit(gpa);324 self.unnamed_consts.deinit(gpa);
323 }325 }
326 self.anon_decls.deinit(gpa);
324327
325 if (self.dwarf) |*dw| {328 if (self.dwarf) |*dw| {
326 dw.deinit();329 dw.deinit();
...@@ -334,7 +337,6 @@ pub fn deinit(self: *Elf) void {...@@ -334,7 +337,6 @@ pub fn deinit(self: *Elf) void {
334337
335pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {338pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 {
336 assert(self.llvm_object == null);339 assert(self.llvm_object == null);
337
338 const this_sym_index = try self.getOrCreateMetadataForDecl(decl_index);340 const this_sym_index = try self.getOrCreateMetadataForDecl(decl_index);
339 const this_sym = self.symbol(this_sym_index);341 const this_sym = self.symbol(this_sym_index);
340 const vaddr = this_sym.value;342 const vaddr = this_sym.value;
...@@ -344,7 +346,57 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link....@@ -344,7 +346,57 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.
344 .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | elf.R_X86_64_64,346 .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | elf.R_X86_64_64,
345 .r_addend = reloc_info.addend,347 .r_addend = reloc_info.addend,
346 });348 });
349 return vaddr;
350}
347351
352pub fn lowerAnonDecl(self: *Elf, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
353 // This is basically the same as lowerUnnamedConst.
354 // example:
355 // const ty = mod.intern_pool.typeOf(decl_val).toType();
356 // const val = decl_val.toValue();
357 // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`.
358 // It doesn't have an owner decl because it's just an unnamed constant that might
359 // be used by more than one function, however, its address is being used so we need
360 // to put it in some location.
361 // ...
362 const gpa = self.base.allocator;
363 const gop = try self.anon_decls.getOrPut(gpa, decl_val);
364 if (!gop.found_existing) {
365 const mod = self.base.options.module.?;
366 const ty = mod.intern_pool.typeOf(decl_val).toType();
367 const val = decl_val.toValue();
368 const tv = TypedValue{ .ty = ty, .val = val };
369 const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)});
370 defer gpa.free(name);
371 const res = self.lowerConst(name, tv, self.rodata_section_index.?, src_loc) catch |err| switch (err) {
372 else => {
373 // TODO improve error message
374 const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{
375 @errorName(err),
376 });
377 return .{ .fail = em };
378 },
379 };
380 const sym_index = switch (res) {
381 .ok => |sym_index| sym_index,
382 .fail => |em| return .{ .fail = em },
383 };
384 gop.value_ptr.* = sym_index;
385 }
386 return .ok;
387}
388
389pub fn getAnonDeclVAddr(self: *Elf, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
390 assert(self.llvm_object == null);
391 const sym_index = self.anon_decls.get(decl_val).?;
392 const sym = self.symbol(sym_index);
393 const vaddr = sym.value;
394 const parent_atom = self.symbol(reloc_info.parent_atom_index).atom(self).?;
395 try parent_atom.addReloc(self, .{
396 .r_offset = reloc_info.offset,
397 .r_info = (@as(u64, @intCast(sym.esym_index)) << 32) | elf.R_X86_64_64,
398 .r_addend = reloc_info.addend,
399 });
348 return vaddr;400 return vaddr;
349}401}
350402
...@@ -3105,50 +3157,68 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol....@@ -3105,50 +3157,68 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol.
31053157
3106pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {3158pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
3107 const gpa = self.base.allocator;3159 const gpa = self.base.allocator;
3108
3109 var code_buffer = std.ArrayList(u8).init(gpa);
3110 defer code_buffer.deinit();
3111
3112 const mod = self.base.options.module.?;3160 const mod = self.base.options.module.?;
3113 const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);3161 const gop = try self.unnamed_consts.getOrPut(gpa, decl_index);
3114 if (!gop.found_existing) {3162 if (!gop.found_existing) {
3115 gop.value_ptr.* = .{};3163 gop.value_ptr.* = .{};
3116 }3164 }
3117 const unnamed_consts = gop.value_ptr;3165 const unnamed_consts = gop.value_ptr;
3118
3119 const decl = mod.declPtr(decl_index);3166 const decl = mod.declPtr(decl_index);
3120 const name_str_index = blk: {3167 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
3121 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));3168 const index = unnamed_consts.items.len;
3122 const index = unnamed_consts.items.len;3169 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });
3123 const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index });3170 defer gpa.free(name);
3124 defer gpa.free(name);3171 const sym_index = switch (try self.lowerConst(name, typed_value, self.rodata_section_index.?, decl.srcLoc(mod))) {
3125 break :blk try self.strtab.insert(gpa, name);3172 .ok => |sym_index| sym_index,
3173 .fail => |em| {
3174 decl.analysis = .codegen_failure;
3175 try mod.failed_decls.put(mod.gpa, decl_index, em);
3176 log.err("{s}", .{em.msg});
3177 return error.CodegenFail;
3178 },
3126 };3179 };
3180 const sym = self.symbol(sym_index);
3181 try unnamed_consts.append(gpa, sym.atom_index);
3182 return sym_index;
3183}
3184
3185const LowerConstResult = union(enum) {
3186 ok: Symbol.Index,
3187 fail: *Module.ErrorMsg,
3188};
3189
3190fn lowerConst(
3191 self: *Elf,
3192 name: []const u8,
3193 tv: TypedValue,
3194 output_section_index: u16,
3195 src_loc: Module.SrcLoc,
3196) !LowerConstResult {
3197 const gpa = self.base.allocator;
3198
3199 var code_buffer = std.ArrayList(u8).init(gpa);
3200 defer code_buffer.deinit();
31273201
3202 const mod = self.base.options.module.?;
3128 const zig_module = self.file(self.zig_module_index.?).?.zig_module;3203 const zig_module = self.file(self.zig_module_index.?).?.zig_module;
3129 const sym_index = try zig_module.addAtom(self);3204 const sym_index = try zig_module.addAtom(self);
31303205
3131 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), typed_value, &code_buffer, .{3206 const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .{
3132 .none = {},3207 .none = {},
3133 }, .{3208 }, .{
3134 .parent_atom_index = sym_index,3209 .parent_atom_index = sym_index,
3135 });3210 });
3136 const code = switch (res) {3211 const code = switch (res) {
3137 .ok => code_buffer.items,3212 .ok => code_buffer.items,
3138 .fail => |em| {3213 .fail => |em| return .{ .fail = em },
3139 decl.analysis = .codegen_failure;
3140 try mod.failed_decls.put(mod.gpa, decl_index, em);
3141 log.err("{s}", .{em.msg});
3142 return error.CodegenFail;
3143 },
3144 };3214 };
31453215
3146 const required_alignment = typed_value.ty.abiAlignment(mod);3216 const required_alignment = tv.ty.abiAlignment(mod);
3147 const shdr_index = self.rodata_section_index.?;3217 const phdr_index = self.phdr_to_shdr_table.get(output_section_index).?;
3148 const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?;
3149 const local_sym = self.symbol(sym_index);3218 const local_sym = self.symbol(sym_index);
3219 const name_str_index = try self.strtab.insert(gpa, name);
3150 local_sym.name_offset = name_str_index;3220 local_sym.name_offset = name_str_index;
3151 local_sym.output_section_index = self.rodata_section_index.?;3221 local_sym.output_section_index = output_section_index;
3152 const local_esym = &zig_module.local_esyms.items[local_sym.esym_index];3222 const local_esym = &zig_module.local_esyms.items[local_sym.esym_index];
3153 local_esym.st_name = name_str_index;3223 local_esym.st_name = name_str_index;
3154 local_esym.st_info |= elf.STT_OBJECT;3224 local_esym.st_info |= elf.STT_OBJECT;
...@@ -3158,21 +3228,20 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module...@@ -3158,21 +3228,20 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module
3158 atom_ptr.name_offset = name_str_index;3228 atom_ptr.name_offset = name_str_index;
3159 atom_ptr.alignment = required_alignment;3229 atom_ptr.alignment = required_alignment;
3160 atom_ptr.size = code.len;3230 atom_ptr.size = code.len;
3161 atom_ptr.output_section_index = self.rodata_section_index.?;3231 atom_ptr.output_section_index = output_section_index;
31623232
3163 try atom_ptr.allocate(self);3233 try atom_ptr.allocate(self);
3234 // TODO rename and re-audit this method
3164 errdefer self.freeDeclMetadata(sym_index);3235 errdefer self.freeDeclMetadata(sym_index);
31653236
3166 local_sym.value = atom_ptr.value;3237 local_sym.value = atom_ptr.value;
3167 local_esym.st_value = atom_ptr.value;3238 local_esym.st_value = atom_ptr.value;
31683239
3169 try unnamed_consts.append(gpa, atom_ptr.atom_index);
3170
3171 const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;3240 const section_offset = atom_ptr.value - self.phdrs.items[phdr_index].p_vaddr;
3172 const file_offset = self.shdrs.items[shdr_index].sh_offset + section_offset;3241 const file_offset = self.shdrs.items[output_section_index].sh_offset + section_offset;
3173 try self.base.file.?.pwriteAll(code, file_offset);3242 try self.base.file.?.pwriteAll(code, file_offset);
31743243
3175 return sym_index;3244 return .{ .ok = sym_index };
3176}3245}
31773246
3178pub fn updateDeclExports(3247pub fn updateDeclExports(
src/link/MachO.zig+98-24
...@@ -109,6 +109,7 @@ atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},...@@ -109,6 +109,7 @@ atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{},
109/// value assigned to label `foo` is an unnamed constant belonging/associated109/// value assigned to label `foo` is an unnamed constant belonging/associated
110/// with `Decl` `main`, and lives as long as that `Decl`.110/// with `Decl` `main`, and lives as long as that `Decl`.
111unnamed_const_atoms: UnnamedConstTable = .{},111unnamed_const_atoms: UnnamedConstTable = .{},
112anon_decls: AnonDeclTable = .{},
112113
113/// A table of relocations indexed by the owning them `Atom`.114/// A table of relocations indexed by the owning them `Atom`.
114/// Note that once we refactor `Atom`'s lifetime and ownership rules,115/// Note that once we refactor `Atom`'s lifetime and ownership rules,
...@@ -1899,6 +1900,7 @@ pub fn deinit(self: *MachO) void {...@@ -1899,6 +1900,7 @@ pub fn deinit(self: *MachO) void {
1899 atoms.deinit(gpa);1900 atoms.deinit(gpa);
1900 }1901 }
1901 self.unnamed_const_atoms.deinit(gpa);1902 self.unnamed_const_atoms.deinit(gpa);
1903 self.anon_decls.deinit(gpa);
19021904
1903 self.atom_by_index_table.deinit(gpa);1905 self.atom_by_index_table.deinit(gpa);
19041906
...@@ -2172,27 +2174,49 @@ pub fn updateFunc(self: *MachO, mod: *Module, func_index: InternPool.Index, air:...@@ -2172,27 +2174,49 @@ pub fn updateFunc(self: *MachO, mod: *Module, func_index: InternPool.Index, air:
21722174
2173pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {2175pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 {
2174 const gpa = self.base.allocator;2176 const gpa = self.base.allocator;
2175
2176 var code_buffer = std.ArrayList(u8).init(gpa);
2177 defer code_buffer.deinit();
2178
2179 const mod = self.base.options.module.?;2177 const mod = self.base.options.module.?;
2180 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);2178 const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index);
2181 if (!gop.found_existing) {2179 if (!gop.found_existing) {
2182 gop.value_ptr.* = .{};2180 gop.value_ptr.* = .{};
2183 }2181 }
2184 const unnamed_consts = gop.value_ptr;2182 const unnamed_consts = gop.value_ptr;
2185
2186 const decl = mod.declPtr(decl_index);2183 const decl = mod.declPtr(decl_index);
2187 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));2184 const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
21882185 const index = unnamed_consts.items.len;
2189 const name_str_index = blk: {2186 const name = try std.fmt.allocPrint(gpa, "___unnamed_{s}_{d}", .{ decl_name, index });
2190 const index = unnamed_consts.items.len;2187 defer gpa.free(name);
2191 const name = try std.fmt.allocPrint(gpa, "___unnamed_{s}_{d}", .{ decl_name, index });2188 const atom_index = switch (try self.lowerConst(name, typed_value, self.data_const_section_index.?, decl.srcLoc(mod))) {
2192 defer gpa.free(name);2189 .ok => |atom_index| atom_index,
2193 break :blk try self.strtab.insert(gpa, name);2190 .fail => |em| {
2191 decl.analysis = .codegen_failure;
2192 try mod.failed_decls.put(mod.gpa, decl_index, em);
2193 log.debug("{s}", .{em.msg});
2194 return error.CodegenFail;
2195 },
2194 };2196 };
2195 const name = self.strtab.get(name_str_index).?;2197 try unnamed_consts.append(gpa, atom_index);
2198 const atom = self.getAtomPtr(atom_index);
2199 return atom.getSymbolIndex().?;
2200}
2201
2202const LowerConstResult = union(enum) {
2203 ok: Atom.Index,
2204 fail: *Module.ErrorMsg,
2205};
2206
2207fn lowerConst(
2208 self: *MachO,
2209 name: []const u8,
2210 tv: TypedValue,
2211 sect_id: u8,
2212 src_loc: Module.SrcLoc,
2213) !LowerConstResult {
2214 const gpa = self.base.allocator;
2215
2216 var code_buffer = std.ArrayList(u8).init(gpa);
2217 defer code_buffer.deinit();
2218
2219 const mod = self.base.options.module.?;
21962220
2197 log.debug("allocating symbol indexes for {s}", .{name});2221 log.debug("allocating symbol indexes for {s}", .{name});
21982222
...@@ -2200,40 +2224,33 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu...@@ -2200,40 +2224,33 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu
2200 const atom_index = try self.createAtom(sym_index, .{});2224 const atom_index = try self.createAtom(sym_index, .{});
2201 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index);2225 try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index);
22022226
2203 const res = try codegen.generateSymbol(&self.base, decl.srcLoc(mod), typed_value, &code_buffer, .none, .{2227 const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .none, .{
2204 .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,2228 .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?,
2205 });2229 });
2206 var code = switch (res) {2230 var code = switch (res) {
2207 .ok => code_buffer.items,2231 .ok => code_buffer.items,
2208 .fail => |em| {2232 .fail => |em| return .{ .fail = em },
2209 decl.analysis = .codegen_failure;
2210 try mod.failed_decls.put(mod.gpa, decl_index, em);
2211 log.debug("{s}", .{em.msg});
2212 return error.CodegenFail;
2213 },
2214 };2233 };
22152234
2216 const required_alignment = typed_value.ty.abiAlignment(mod);2235 const required_alignment = tv.ty.abiAlignment(mod);
2217 const atom = self.getAtomPtr(atom_index);2236 const atom = self.getAtomPtr(atom_index);
2218 atom.size = code.len;2237 atom.size = code.len;
2219 // TODO: work out logic for disambiguating functions from function pointers2238 // TODO: work out logic for disambiguating functions from function pointers
2220 // const sect_id = self.getDeclOutputSection(decl_index);2239 // const sect_id = self.getDeclOutputSection(decl_index);
2221 const sect_id = self.data_const_section_index.?;
2222 const symbol = atom.getSymbolPtr(self);2240 const symbol = atom.getSymbolPtr(self);
2241 const name_str_index = try self.strtab.insert(gpa, name);
2223 symbol.n_strx = name_str_index;2242 symbol.n_strx = name_str_index;
2224 symbol.n_type = macho.N_SECT;2243 symbol.n_type = macho.N_SECT;
2225 symbol.n_sect = sect_id + 1;2244 symbol.n_sect = sect_id + 1;
2226 symbol.n_value = try self.allocateAtom(atom_index, code.len, required_alignment);2245 symbol.n_value = try self.allocateAtom(atom_index, code.len, required_alignment);
2227 errdefer self.freeAtom(atom_index);2246 errdefer self.freeAtom(atom_index);
22282247
2229 try unnamed_consts.append(gpa, atom_index);
2230
2231 log.debug("allocated atom for {s} at 0x{x}", .{ name, symbol.n_value });2248 log.debug("allocated atom for {s} at 0x{x}", .{ name, symbol.n_value });
2232 log.debug(" (required alignment 0x{x})", .{required_alignment});2249 log.debug(" (required alignment 0x{x})", .{required_alignment});
22332250
2234 try self.writeAtom(atom_index, code);2251 try self.writeAtom(atom_index, code);
22352252
2236 return atom.getSymbolIndex().?;2253 return .{ .ok = atom_index };
2237}2254}
22382255
2239pub fn updateDecl(self: *MachO, mod: *Module, decl_index: Module.Decl.Index) !void {2256pub fn updateDecl(self: *MachO, mod: *Module, decl_index: Module.Decl.Index) !void {
...@@ -2840,6 +2857,62 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil...@@ -2840,6 +2857,62 @@ pub fn getDeclVAddr(self: *MachO, decl_index: Module.Decl.Index, reloc_info: Fil
2840 return 0;2857 return 0;
2841}2858}
28422859
2860pub fn lowerAnonDecl(self: *MachO, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
2861 // This is basically the same as lowerUnnamedConst.
2862 // example:
2863 // const ty = mod.intern_pool.typeOf(decl_val).toType();
2864 // const val = decl_val.toValue();
2865 // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`.
2866 // It doesn't have an owner decl because it's just an unnamed constant that might
2867 // be used by more than one function, however, its address is being used so we need
2868 // to put it in some location.
2869 // ...
2870 const gpa = self.base.allocator;
2871 const gop = try self.anon_decls.getOrPut(gpa, decl_val);
2872 if (!gop.found_existing) {
2873 const mod = self.base.options.module.?;
2874 const ty = mod.intern_pool.typeOf(decl_val).toType();
2875 const val = decl_val.toValue();
2876 const tv = TypedValue{ .ty = ty, .val = val };
2877 const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)});
2878 defer gpa.free(name);
2879 const res = self.lowerConst(name, tv, self.data_const_section_index.?, src_loc) catch |err| switch (err) {
2880 else => {
2881 // TODO improve error message
2882 const em = try Module.ErrorMsg.create(gpa, src_loc, "lowerAnonDecl failed with error: {s}", .{
2883 @errorName(err),
2884 });
2885 return .{ .fail = em };
2886 },
2887 };
2888 const atom_index = switch (res) {
2889 .ok => |atom_index| atom_index,
2890 .fail => |em| return .{ .fail = em },
2891 };
2892 gop.value_ptr.* = atom_index;
2893 }
2894 return .ok;
2895}
2896
2897pub fn getAnonDeclVAddr(self: *MachO, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
2898 assert(self.llvm_object == null);
2899
2900 const this_atom_index = self.anon_decls.get(decl_val).?;
2901 const sym_index = self.getAtom(this_atom_index).getSymbolIndex().?;
2902 const atom_index = self.getAtomIndexForSymbol(.{ .sym_index = reloc_info.parent_atom_index }).?;
2903 try Atom.addRelocation(self, atom_index, .{
2904 .type = .unsigned,
2905 .target = .{ .sym_index = sym_index },
2906 .offset = @as(u32, @intCast(reloc_info.offset)),
2907 .addend = reloc_info.addend,
2908 .pcrel = false,
2909 .length = 3,
2910 });
2911 try Atom.addRebase(self, atom_index, @as(u32, @intCast(reloc_info.offset)));
2912
2913 return 0;
2914}
2915
2843fn populateMissingMetadata(self: *MachO) !void {2916fn populateMissingMetadata(self: *MachO) !void {
2844 assert(self.mode == .incremental);2917 assert(self.mode == .incremental);
28452918
...@@ -5389,6 +5462,7 @@ const DeclMetadata = struct {...@@ -5389,6 +5462,7 @@ const DeclMetadata = struct {
5389 }5462 }
5390};5463};
53915464
5465const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index);
5392const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding));5466const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding));
5393const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));5467const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index));
5394const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));5468const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32));
src/link/Plan9.zig+90-1
...@@ -82,6 +82,8 @@ unnamed_const_atoms: UnnamedConstTable = .{},...@@ -82,6 +82,8 @@ unnamed_const_atoms: UnnamedConstTable = .{},
8282
83lazy_syms: LazySymbolTable = .{},83lazy_syms: LazySymbolTable = .{},
8484
85anon_decls: std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index) = .{},
86
85relocs: std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Reloc)) = .{},87relocs: std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Reloc)) = .{},
86hdr: aout.ExecHdr = undefined,88hdr: aout.ExecHdr = undefined,
8789
...@@ -166,6 +168,9 @@ pub const Atom = struct {...@@ -166,6 +168,9 @@ pub const Atom = struct {
166 code_len: usize,168 code_len: usize,
167 decl_index: Module.Decl.Index,169 decl_index: Module.Decl.Index,
168 },170 },
171 fn fromSlice(slice: []u8) CodePtr {
172 return .{ .code_ptr = slice.ptr, .other = .{ .code_len = slice.len } };
173 }
169 fn getCode(self: CodePtr, plan9: *const Plan9) []u8 {174 fn getCode(self: CodePtr, plan9: *const Plan9) []u8 {
170 const mod = plan9.base.options.module.?;175 const mod = plan9.base.options.module.?;
171 return if (self.code_ptr) |p| p[0..self.other.code_len] else blk: {176 return if (self.code_ptr) |p| p[0..self.other.code_len] else blk: {
...@@ -608,8 +613,9 @@ fn atomCount(self: *Plan9) usize {...@@ -608,8 +613,9 @@ fn atomCount(self: *Plan9) usize {
608 while (it_lazy.next()) |kv| {613 while (it_lazy.next()) |kv| {
609 lazy_atom_count += kv.value_ptr.numberOfAtoms();614 lazy_atom_count += kv.value_ptr.numberOfAtoms();
610 }615 }
616 const anon_atom_count = self.anon_decls.count();
611 const extern_atom_count = self.externCount();617 const extern_atom_count = self.externCount();
612 return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count + extern_atom_count;618 return data_decl_count + fn_decl_count + unnamed_const_count + lazy_atom_count + extern_atom_count + anon_atom_count;
613}619}
614620
615pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {621pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.Node) link.File.FlushError!void {
...@@ -804,6 +810,27 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No...@@ -804,6 +810,27 @@ pub fn flushModule(self: *Plan9, comp: *Compilation, prog_node: *std.Progress.No
804 self.syms.items[atom.sym_index.?].value = off;810 self.syms.items[atom.sym_index.?].value = off;
805 }811 }
806 }812 }
813 // the anon decls
814 {
815 var it_anon = self.anon_decls.iterator();
816 while (it_anon.next()) |kv| {
817 const atom = self.getAtomPtr(kv.value_ptr.*);
818 const code = atom.code.getOwnedCode().?;
819 log.debug("write anon decl: {s}", .{self.syms.items[atom.sym_index.?].name});
820 foff += code.len;
821 iovecs[iovecs_i] = .{ .iov_base = code.ptr, .iov_len = code.len };
822 iovecs_i += 1;
823 const off = self.getAddr(data_i, .d);
824 data_i += code.len;
825 atom.offset = off;
826 if (!self.sixtyfour_bit) {
827 mem.writeInt(u32, got_table[atom.got_index.? * 4 ..][0..4], @as(u32, @intCast(off)), self.base.options.target.cpu.arch.endian());
828 } else {
829 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, self.base.options.target.cpu.arch.endian());
830 }
831 self.syms.items[atom.sym_index.?].value = off;
832 }
833 }
807 // the lazy data symbols834 // the lazy data symbols
808 var it_lazy = self.lazy_syms.iterator();835 var it_lazy = self.lazy_syms.iterator();
809 while (it_lazy.next()) |kv| {836 while (it_lazy.next()) |kv| {
...@@ -1196,6 +1223,11 @@ pub fn deinit(self: *Plan9) void {...@@ -1196,6 +1223,11 @@ pub fn deinit(self: *Plan9) void {
1196 while (itd.next()) |entry| {1223 while (itd.next()) |entry| {
1197 gpa.free(entry.value_ptr.*);1224 gpa.free(entry.value_ptr.*);
1198 }1225 }
1226 var it_anon = self.anon_decls.iterator();
1227 while (it_anon.next()) |entry| {
1228 const sym_index = self.getAtom(entry.value_ptr.*).sym_index.?;
1229 gpa.free(self.syms.items[sym_index].name);
1230 }
1199 self.data_decl_table.deinit(gpa);1231 self.data_decl_table.deinit(gpa);
1200 self.syms.deinit(gpa);1232 self.syms.deinit(gpa);
1201 self.got_index_free_list.deinit(gpa);1233 self.got_index_free_list.deinit(gpa);
...@@ -1418,6 +1450,63 @@ pub fn getDeclVAddr(...@@ -1418,6 +1450,63 @@ pub fn getDeclVAddr(
1418 return undefined;1450 return undefined;
1419}1451}
14201452
1453pub fn lowerAnonDecl(self: *Plan9, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
1454 // This is basically the same as lowerUnnamedConst.
1455 // example:
1456 // const ty = mod.intern_pool.typeOf(decl_val).toType();
1457 // const val = decl_val.toValue();
1458 // The symbol name can be something like `__anon_{d}` with `@intFromEnum(decl_val)`.
1459 // It doesn't have an owner decl because it's just an unnamed constant that might
1460 // be used by more than one function, however, its address is being used so we need
1461 // to put it in some location.
1462 // ...
1463 const gpa = self.base.allocator;
1464 var gop = try self.anon_decls.getOrPut(gpa, decl_val);
1465 const mod = self.base.options.module.?;
1466 if (!gop.found_existing) {
1467 const ty = mod.intern_pool.typeOf(decl_val).toType();
1468 const val = decl_val.toValue();
1469 const tv = TypedValue{ .ty = ty, .val = val };
1470 const name = try std.fmt.allocPrint(gpa, "__anon_{d}", .{@intFromEnum(decl_val)});
1471
1472 const index = try self.createAtom();
1473 const got_index = self.allocateGotIndex();
1474 gop.value_ptr.* = index;
1475 // we need to free name latex
1476 var code_buffer = std.ArrayList(u8).init(gpa);
1477 const res = try codegen.generateSymbol(&self.base, src_loc, tv, &code_buffer, .{ .none = {} }, .{ .parent_atom_index = index });
1478 const code = switch (res) {
1479 .ok => code_buffer.items,
1480 .fail => |em| return .{ .fail = em },
1481 };
1482 const atom_ptr = self.getAtomPtr(index);
1483 atom_ptr.* = .{
1484 .type = .d,
1485 .offset = undefined,
1486 .sym_index = null,
1487 .got_index = got_index,
1488 .code = Atom.CodePtr.fromSlice(code),
1489 };
1490 _ = try atom_ptr.getOrCreateSymbolTableEntry(self);
1491 self.syms.items[atom_ptr.sym_index.?] = .{
1492 .type = .d,
1493 .value = undefined,
1494 .name = name,
1495 };
1496 }
1497 return .ok;
1498}
1499
1500pub fn getAnonDeclVAddr(self: *Plan9, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
1501 const atom_index = self.anon_decls.get(decl_val).?;
1502 try self.addReloc(reloc_info.parent_atom_index, .{
1503 .target = atom_index,
1504 .offset = reloc_info.offset,
1505 .addend = reloc_info.addend,
1506 });
1507 return undefined;
1508}
1509
1421pub fn addReloc(self: *Plan9, parent_index: Atom.Index, reloc: Reloc) !void {1510pub fn addReloc(self: *Plan9, parent_index: Atom.Index, reloc: Reloc) !void {
1422 const gop = try self.relocs.getOrPut(self.base.allocator, parent_index);1511 const gop = try self.relocs.getOrPut(self.base.allocator, parent_index);
1423 if (!gop.found_existing) {1512 if (!gop.found_existing) {
src/link/Wasm.zig+99-10
...@@ -187,6 +187,9 @@ debug_pubtypes_atom: ?Atom.Index = null,...@@ -187,6 +187,9 @@ debug_pubtypes_atom: ?Atom.Index = null,
187/// rather than by the linker.187/// rather than by the linker.
188synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},188synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{},
189189
190/// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index.
191anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{},
192
190pub const Alignment = types.Alignment;193pub const Alignment = types.Alignment;
191194
192pub const Segment = struct {195pub const Segment = struct {
...@@ -1291,6 +1294,7 @@ pub fn deinit(wasm: *Wasm) void {...@@ -1291,6 +1294,7 @@ pub fn deinit(wasm: *Wasm) void {
1291 }1294 }
12921295
1293 wasm.decls.deinit(gpa);1296 wasm.decls.deinit(gpa);
1297 wasm.anon_decls.deinit(gpa);
1294 wasm.atom_types.deinit(gpa);1298 wasm.atom_types.deinit(gpa);
1295 wasm.symbols.deinit(gpa);1299 wasm.symbols.deinit(gpa);
1296 wasm.symbols_free_list.deinit(gpa);1300 wasm.symbols_free_list.deinit(gpa);
...@@ -1548,17 +1552,38 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In...@@ -1548,17 +1552,38 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
1548 assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions1552 assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions
1549 const decl = mod.declPtr(decl_index);1553 const decl = mod.declPtr(decl_index);
15501554
1551 // Create and initialize a new local symbol and atom
1552 const atom_index = try wasm.createAtom();
1553 const parent_atom_index = try wasm.getOrCreateAtomForDecl(decl_index);1555 const parent_atom_index = try wasm.getOrCreateAtomForDecl(decl_index);
1554 const parent_atom = wasm.getAtomPtr(parent_atom_index);1556 const parent_atom = wasm.getAtom(parent_atom_index);
1555 const local_index = parent_atom.locals.items.len;1557 const local_index = parent_atom.locals.items.len;
1556 try parent_atom.locals.append(wasm.base.allocator, atom_index);
1557 const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));1558 const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod));
1558 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{1559 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{
1559 fqn, local_index,1560 fqn, local_index,
1560 });1561 });
1561 defer wasm.base.allocator.free(name);1562 defer wasm.base.allocator.free(name);
1563
1564 switch (try wasm.lowerConst(name, tv, decl.srcLoc(mod))) {
1565 .ok => |atom_index| {
1566 try wasm.getAtomPtr(parent_atom_index).locals.append(wasm.base.allocator, atom_index);
1567 return wasm.getAtom(atom_index).getSymbolIndex().?;
1568 },
1569 .fail => |em| {
1570 decl.analysis = .codegen_failure;
1571 try mod.failed_decls.put(mod.gpa, decl_index, em);
1572 return error.CodegenFail;
1573 },
1574 }
1575}
1576
1577const LowerConstResult = union(enum) {
1578 ok: Atom.Index,
1579 fail: *Module.ErrorMsg,
1580};
1581
1582fn lowerConst(wasm: *Wasm, name: []const u8, tv: TypedValue, src_loc: Module.SrcLoc) !LowerConstResult {
1583 const mod = wasm.base.options.module.?;
1584
1585 // Create and initialize a new local symbol and atom
1586 const atom_index = try wasm.createAtom();
1562 var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);1587 var value_bytes = std.ArrayList(u8).init(wasm.base.allocator);
1563 defer value_bytes.deinit();1588 defer value_bytes.deinit();
15641589
...@@ -1576,7 +1601,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In...@@ -1576,7 +1601,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
15761601
1577 const result = try codegen.generateSymbol(1602 const result = try codegen.generateSymbol(
1578 &wasm.base,1603 &wasm.base,
1579 decl.srcLoc(mod),1604 src_loc,
1580 tv,1605 tv,
1581 &value_bytes,1606 &value_bytes,
1582 .none,1607 .none,
...@@ -1588,17 +1613,15 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In...@@ -1588,17 +1613,15 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In
1588 break :code switch (result) {1613 break :code switch (result) {
1589 .ok => value_bytes.items,1614 .ok => value_bytes.items,
1590 .fail => |em| {1615 .fail => |em| {
1591 decl.analysis = .codegen_failure;1616 return .{ .fail = em };
1592 try mod.failed_decls.put(mod.gpa, decl_index, em);
1593 return error.CodegenFail;
1594 },1617 },
1595 };1618 };
1596 };1619 };
15971620
1598 const atom = wasm.getAtomPtr(atom_index);1621 const atom = wasm.getAtomPtr(atom_index);
1599 atom.size = @as(u32, @intCast(code.len));1622 atom.size = @intCast(code.len);
1600 try atom.code.appendSlice(wasm.base.allocator, code);1623 try atom.code.appendSlice(wasm.base.allocator, code);
1601 return atom.sym_index;1624 return .{ .ok = atom_index };
1602}1625}
16031626
1604/// Returns the symbol index from a symbol of which its flag is set global,1627/// Returns the symbol index from a symbol of which its flag is set global,
...@@ -1679,6 +1702,63 @@ pub fn getDeclVAddr(...@@ -1679,6 +1702,63 @@ pub fn getDeclVAddr(
1679 return target_symbol_index;1702 return target_symbol_index;
1680}1703}
16811704
1705pub fn lowerAnonDecl(wasm: *Wasm, decl_val: InternPool.Index, src_loc: Module.SrcLoc) !codegen.Result {
1706 const gop = try wasm.anon_decls.getOrPut(wasm.base.allocator, decl_val);
1707 if (gop.found_existing) {
1708 return .ok;
1709 }
1710
1711 const mod = wasm.base.options.module.?;
1712 const ty = mod.intern_pool.typeOf(decl_val).toType();
1713 const tv: TypedValue = .{ .ty = ty, .val = decl_val.toValue() };
1714 const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__anon_{d}", .{@intFromEnum(decl_val)});
1715 defer wasm.base.allocator.free(name);
1716
1717 switch (try wasm.lowerConst(name, tv, src_loc)) {
1718 .ok => |atom_index| {
1719 gop.value_ptr.* = atom_index;
1720 return .ok;
1721 },
1722 .fail => |em| return .{ .fail = em },
1723 }
1724}
1725
1726pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: link.File.RelocInfo) !u64 {
1727 const atom_index = wasm.anon_decls.get(decl_val).?;
1728 const target_symbol_index = wasm.getAtom(atom_index).getSymbolIndex().?;
1729
1730 const parent_atom_index = wasm.symbol_atom.get(.{ .file = null, .index = reloc_info.parent_atom_index }).?;
1731 const parent_atom = wasm.getAtomPtr(parent_atom_index);
1732 const is_wasm32 = wasm.base.options.target.cpu.arch == .wasm32;
1733 const mod = wasm.base.options.module.?;
1734 const ty = mod.intern_pool.typeOf(decl_val).toType();
1735 if (ty.zigTypeTag(mod) == .Fn) {
1736 assert(reloc_info.addend == 0); // addend not allowed for function relocations
1737 // We found a function pointer, so add it to our table,
1738 // as function pointers are not allowed to be stored inside the data section.
1739 // They are instead stored in a function table which are called by index.
1740 try wasm.addTableFunction(target_symbol_index);
1741 try parent_atom.relocs.append(wasm.base.allocator, .{
1742 .index = target_symbol_index,
1743 .offset = @as(u32, @intCast(reloc_info.offset)),
1744 .relocation_type = if (is_wasm32) .R_WASM_TABLE_INDEX_I32 else .R_WASM_TABLE_INDEX_I64,
1745 });
1746 } else {
1747 try parent_atom.relocs.append(wasm.base.allocator, .{
1748 .index = target_symbol_index,
1749 .offset = @as(u32, @intCast(reloc_info.offset)),
1750 .relocation_type = if (is_wasm32) .R_WASM_MEMORY_ADDR_I32 else .R_WASM_MEMORY_ADDR_I64,
1751 .addend = @as(i32, @intCast(reloc_info.addend)),
1752 });
1753 }
1754
1755 // we do not know the final address at this point,
1756 // as atom allocation will determine the address and relocations
1757 // will calculate and rewrite this. Therefore, we simply return the symbol index
1758 // that was targeted.
1759 return target_symbol_index;
1760}
1761
1682pub fn deleteDeclExport(wasm: *Wasm, decl_index: Module.Decl.Index) void {1762pub fn deleteDeclExport(wasm: *Wasm, decl_index: Module.Decl.Index) void {
1683 if (wasm.llvm_object) |_| return;1763 if (wasm.llvm_object) |_| return;
1684 const atom_index = wasm.decls.get(decl_index) orelse return;1764 const atom_index = wasm.decls.get(decl_index) orelse return;
...@@ -3442,6 +3522,15 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod...@@ -3442,6 +3522,15 @@ pub fn flushModule(wasm: *Wasm, comp: *Compilation, prog_node: *std.Progress.Nod
3442 try wasm.parseAtom(local_atom_index, .{ .data = .read_only });3522 try wasm.parseAtom(local_atom_index, .{ .data = .read_only });
3443 }3523 }
3444 }3524 }
3525 // parse anonymous declarations
3526 for (wasm.anon_decls.keys(), wasm.anon_decls.values()) |decl_val, atom_index| {
3527 const ty = mod.intern_pool.typeOf(decl_val).toType();
3528 if (ty.zigTypeTag(mod) == .Fn) {
3529 try wasm.parseAtom(atom_index, .function);
3530 } else {
3531 try wasm.parseAtom(atom_index, .{ .data = .read_only });
3532 }
3533 }
34453534
3446 // also parse any backend-generated functions3535 // also parse any backend-generated functions
3447 for (wasm.synthetic_functions.items) |atom_index| {3536 for (wasm.synthetic_functions.items) |atom_index| {
src/value.zig+6-3
...@@ -1565,12 +1565,14 @@ pub const Value = struct {...@@ -1565,12 +1565,14 @@ pub const Value = struct {
1565 }1565 }
15661566
1567 pub fn sliceLen(val: Value, mod: *Module) u64 {1567 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;
1569 return switch (ptr.len) {1570 return switch (ptr.len) {
1570 .none => switch (mod.intern_pool.indexToKey(switch (ptr.addr) {1571 .none => switch (ip.indexToKey(switch (ptr.addr) {
1571 .decl => |decl| mod.declPtr(decl).ty.toIntern(),1572 .decl => |decl| mod.declPtr(decl).ty.toIntern(),
1572 .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).ty.toIntern(),1573 .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),
1574 else => unreachable,1576 else => unreachable,
1575 })) {1577 })) {
1576 .array_type => |array_type| array_type.len,1578 .array_type => |array_type| array_type.len,
...@@ -1602,6 +1604,7 @@ pub const Value = struct {...@@ -1602,6 +1604,7 @@ pub const Value = struct {
1602 })).toValue(),1604 })).toValue(),
1603 .ptr => |ptr| switch (ptr.addr) {1605 .ptr => |ptr| switch (ptr.addr) {
1604 .decl => |decl| mod.declPtr(decl).val.maybeElemValue(mod, index),1606 .decl => |decl| mod.declPtr(decl).val.maybeElemValue(mod, index),
1607 .anon_decl => |anon_decl| anon_decl.toValue().maybeElemValue(mod, index),
1605 .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod))1608 .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod))
1606 .toValue().maybeElemValue(mod, index),1609 .toValue().maybeElemValue(mod, index),
1607 .int, .eu_payload => null,1610 .int, .eu_payload => null,