| author | |
| committer | |
| log | 398db54434dad366748d63f37dcfc5e770cfd278 |
| tree | a94859a016a1de9f14e93b98adbdf43260c6d556 |
| parent | ec0f76c5996e88f61d376640bf36ed7feb2b0ea6 |
| parent | d634e02d33e682c8db9d137175c01d1318e6ab80 |
| signature |
compiler: start handling anonymous decls differently18 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 | 3499 | .is_naked_fn = false, |
| 3500 | 3500 | .fwd_decl = fwd_decl.toManaged(gpa), |
| 3501 | 3501 | .ctypes = .{}, |
| 3502 | .anon_decl_deps = .{}, | |
| 3502 | 3503 | }; |
| 3503 | 3504 | defer { |
| 3504 | 3505 | dg.ctypes.deinit(gpa); |
src/InternPool.zig+40-4| ... | ... | @@ -1074,6 +1074,7 @@ pub const Key = union(enum) { |
| 1074 | 1074 | |
| 1075 | 1075 | decl: Module.Decl.Index, |
| 1076 | 1076 | mut_decl: MutDecl, |
| 1077 | anon_decl: Index, | |
| 1077 | 1078 | comptime_field: Index, |
| 1078 | 1079 | int: Index, |
| 1079 | 1080 | eu_payload: Index, |
| ... | ... | @@ -1230,10 +1231,12 @@ pub const Key = union(enum) { |
| 1230 | 1231 | asBytes(&x.decl) ++ asBytes(&x.runtime_index), |
| 1231 | 1232 | ), |
| 1232 | 1233 | |
| 1233 | .int, .eu_payload, .opt_payload, .comptime_field => |int| Hash.hash( | |
| 1234 | seed2, | |
| 1235 | asBytes(&int), | |
| 1236 | ), | |
| 1234 | .anon_decl, | |
| 1235 | .int, | |
| 1236 | .eu_payload, | |
| 1237 | .opt_payload, | |
| 1238 | .comptime_field, | |
| 1239 | => |int| Hash.hash(seed2, asBytes(&int)), | |
| 1237 | 1240 | |
| 1238 | 1241 | .elem, .field => |x| Hash.hash( |
| 1239 | 1242 | seed2, |
| ... | ... | @@ -1497,6 +1500,7 @@ pub const Key = union(enum) { |
| 1497 | 1500 | return switch (a_info.addr) { |
| 1498 | 1501 | .decl => |a_decl| a_decl == b_info.addr.decl, |
| 1499 | 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 | 1504 | .int => |a_int| a_int == b_info.addr.int, |
| 1501 | 1505 | .eu_payload => |a_eu_payload| a_eu_payload == b_info.addr.eu_payload, |
| 1502 | 1506 | .opt_payload => |a_opt_payload| a_opt_payload == b_info.addr.opt_payload, |
| ... | ... | @@ -2123,6 +2127,7 @@ pub const Index = enum(u32) { |
| 2123 | 2127 | simple_value: struct { data: SimpleValue }, |
| 2124 | 2128 | ptr_decl: struct { data: *PtrDecl }, |
| 2125 | 2129 | ptr_mut_decl: struct { data: *PtrMutDecl }, |
| 2130 | ptr_anon_decl: struct { data: *PtrAnonDecl }, | |
| 2126 | 2131 | ptr_comptime_field: struct { data: *PtrComptimeField }, |
| 2127 | 2132 | ptr_int: struct { data: *PtrBase }, |
| 2128 | 2133 | ptr_eu_payload: struct { data: *PtrBase }, |
| ... | ... | @@ -2572,6 +2577,9 @@ pub const Tag = enum(u8) { |
| 2572 | 2577 | /// A pointer to a decl that can be mutated at comptime. |
| 2573 | 2578 | /// data is extra index of `PtrMutDecl`, which contains the type and address. |
| 2574 | 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 | 2583 | /// data is extra index of `PtrComptimeField`, which contains the pointer type and field value. |
| 2576 | 2584 | ptr_comptime_field, |
| 2577 | 2585 | /// A pointer with an integer value. |
| ... | ... | @@ -2767,6 +2775,7 @@ pub const Tag = enum(u8) { |
| 2767 | 2775 | .simple_value => unreachable, |
| 2768 | 2776 | .ptr_decl => PtrDecl, |
| 2769 | 2777 | .ptr_mut_decl => PtrMutDecl, |
| 2778 | .ptr_anon_decl => PtrAnonDecl, | |
| 2770 | 2779 | .ptr_comptime_field => PtrComptimeField, |
| 2771 | 2780 | .ptr_int => PtrBase, |
| 2772 | 2781 | .ptr_eu_payload => PtrBase, |
| ... | ... | @@ -3364,6 +3373,11 @@ pub const PtrDecl = struct { |
| 3364 | 3373 | decl: Module.Decl.Index, |
| 3365 | 3374 | }; |
| 3366 | 3375 | |
| 3376 | pub const PtrAnonDecl = struct { | |
| 3377 | ty: Index, | |
| 3378 | val: Index, | |
| 3379 | }; | |
| 3380 | ||
| 3367 | 3381 | pub const PtrMutDecl = struct { |
| 3368 | 3382 | ty: Index, |
| 3369 | 3383 | decl: Module.Decl.Index, |
| ... | ... | @@ -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 | 3737 | .ptr_comptime_field => { |
| 3717 | 3738 | const info = ip.extraData(PtrComptimeField, data); |
| 3718 | 3739 | return .{ .ptr = .{ |
| ... | ... | @@ -3790,6 +3811,9 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { |
| 3790 | 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 | 3817 | .ptr_comptime_field => .{ |
| 3794 | 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 | 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 | 4576 | .comptime_field => |field_val| { |
| 4546 | 4577 | assert(field_val != .none); |
| 4547 | 4578 | ip.items.appendAssumeCapacity(.{ |
| ... | ... | @@ -7147,6 +7178,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { |
| 7147 | 7178 | .simple_value => 0, |
| 7148 | 7179 | .ptr_decl => @sizeOf(PtrDecl), |
| 7149 | 7180 | .ptr_mut_decl => @sizeOf(PtrMutDecl), |
| 7181 | .ptr_anon_decl => @sizeOf(PtrAnonDecl), | |
| 7150 | 7182 | .ptr_comptime_field => @sizeOf(PtrComptimeField), |
| 7151 | 7183 | .ptr_int => @sizeOf(PtrBase), |
| 7152 | 7184 | .ptr_eu_payload => @sizeOf(PtrBase), |
| ... | ... | @@ -7276,6 +7308,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void { |
| 7276 | 7308 | .runtime_value, |
| 7277 | 7309 | .ptr_decl, |
| 7278 | 7310 | .ptr_mut_decl, |
| 7311 | .ptr_anon_decl, | |
| 7279 | 7312 | .ptr_comptime_field, |
| 7280 | 7313 | .ptr_int, |
| 7281 | 7314 | .ptr_eu_payload, |
| ... | ... | @@ -7656,6 +7689,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { |
| 7656 | 7689 | |
| 7657 | 7690 | inline .ptr_decl, |
| 7658 | 7691 | .ptr_mut_decl, |
| 7692 | .ptr_anon_decl, | |
| 7659 | 7693 | .ptr_comptime_field, |
| 7660 | 7694 | .ptr_int, |
| 7661 | 7695 | .ptr_eu_payload, |
| ... | ... | @@ -7816,6 +7850,7 @@ pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.Addr.Tag { |
| 7816 | 7850 | switch (ip.items.items(.tag)[base]) { |
| 7817 | 7851 | .ptr_decl => return .decl, |
| 7818 | 7852 | .ptr_mut_decl => return .mut_decl, |
| 7853 | .ptr_anon_decl => return .anon_decl, | |
| 7819 | 7854 | .ptr_comptime_field => return .comptime_field, |
| 7820 | 7855 | .ptr_int => return .int, |
| 7821 | 7856 | inline .ptr_eu_payload, |
| ... | ... | @@ -7991,6 +8026,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois |
| 7991 | 8026 | .simple_value, |
| 7992 | 8027 | .ptr_decl, |
| 7993 | 8028 | .ptr_mut_decl, |
| 8029 | .ptr_anon_decl, | |
| 7994 | 8030 | .ptr_comptime_field, |
| 7995 | 8031 | .ptr_int, |
| 7996 | 8032 | .ptr_eu_payload, |
src/Module.zig+1-4| ... | ... | @@ -109,9 +109,6 @@ comptime_capture_scopes: std.AutoArrayHashMapUnmanaged(CaptureScope.Key, InternP |
| 109 | 109 | /// This memory lives until the Module is destroyed. |
| 110 | 110 | tmp_hack_arena: std.heap.ArenaAllocator, |
| 111 | 111 | |
| 112 | /// This is currently only used for string literals. | |
| 113 | memoized_decls: std.AutoHashMapUnmanaged(InternPool.Index, Decl.Index) = .{}, | |
| 114 | ||
| 115 | 112 | /// We optimize memory usage for a compilation with no compile errors by storing the |
| 116 | 113 | /// error messages and mapping outside of `Decl`. |
| 117 | 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 | 2624 | mod.global_assembly.deinit(gpa); |
| 2628 | 2625 | mod.reference_table.deinit(gpa); |
| 2629 | 2626 | |
| 2630 | mod.memoized_decls.deinit(gpa); | |
| 2631 | 2627 | mod.intern_pool.deinit(gpa); |
| 2632 | 2628 | mod.tmp_hack_arena.deinit(); |
| 2633 | 2629 | |
| ... | ... | @@ -5814,6 +5810,7 @@ pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void { |
| 5814 | 5810 | .ptr => |ptr| { |
| 5815 | 5811 | switch (ptr.addr) { |
| 5816 | 5812 | .decl => |decl| try mod.markDeclIndexAlive(decl), |
| 5813 | .anon_decl => {}, | |
| 5817 | 5814 | .mut_decl => |mut_decl| try mod.markDeclIndexAlive(mut_decl.decl), |
| 5818 | 5815 | .int, .comptime_field => {}, |
| 5819 | 5816 | .eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(parent.toValue()), |
src/Sema.zig+57-40| ... | ... | @@ -1091,7 +1091,7 @@ fn analyzeBodyInner( |
| 1091 | 1091 | .slice_sentinel => try sema.zirSliceSentinel(block, inst), |
| 1092 | 1092 | .slice_start => try sema.zirSliceStart(block, inst), |
| 1093 | 1093 | .slice_length => try sema.zirSliceLength(block, inst), |
| 1094 | .str => try sema.zirStr(block, inst), | |
| 1094 | .str => try sema.zirStr(inst), | |
| 1095 | 1095 | .switch_block => try sema.zirSwitchBlock(block, inst, false), |
| 1096 | 1096 | .switch_block_ref => try sema.zirSwitchBlock(block, inst, true), |
| 1097 | 1097 | .type_info => try sema.zirTypeInfo(block, inst), |
| ... | ... | @@ -2185,7 +2185,7 @@ fn resolveMaybeUndefValIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Va |
| 2185 | 2185 | if (val.ip_index == .none) return val; |
| 2186 | 2186 | if (sema.mod.intern_pool.isVariable(val.toIntern())) return null; |
| 2187 | 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 | 2189 | .int => {}, |
| 2190 | 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 | 5501 | return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag); |
| 5502 | 5502 | } |
| 5503 | 5503 | |
| 5504 | fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 5505 | const tracy = trace(@src()); | |
| 5506 | defer tracy.end(); | |
| 5507 | ||
| 5504 | fn zirStr(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | |
| 5508 | 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 | } |
| 5511 | 5508 | |
| 5512 | fn addStrLit(sema: *Sema, block: *Block, bytes: []const u8) CompileError!Air.Inst.Ref { | |
| 5513 | const mod = sema.mod; | |
| 5514 | const gpa = sema.gpa; | |
| 5515 | // TODO: write something like getCoercedInts to avoid needing to dupe | |
| 5509 | fn addStrLit(sema: *Sema, bytes: []const u8) CompileError!Air.Inst.Ref { | |
| 5516 | 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`. | |
| 5515 | fn addStrLitNoAlias(sema: *Sema, bytes: []const u8) CompileError!Air.Inst.Ref { | |
| 5516 | const mod = sema.mod; | |
| 5517 | const array_ty = try mod.arrayType(.{ | |
| 5518 | 5518 | .len = bytes.len, |
| 5519 | 5519 | .sentinel = .zero_u8, |
| 5520 | 5520 | .child = .u8_type, |
| 5521 | 5521 | }); |
| 5522 | 5522 | const val = try mod.intern(.{ .aggregate = .{ |
| 5523 | .ty = ty.toIntern(), | |
| 5524 | .storage = .{ .bytes = duped_bytes }, | |
| 5523 | .ty = array_ty.toIntern(), | |
| 5524 | .storage = .{ .bytes = bytes }, | |
| 5525 | 5525 | } }); |
| 5526 | const gop = try mod.memoized_decls.getOrPut(gpa, val); | |
| 5527 | if (!gop.found_existing) { | |
| 5528 | const new_decl_index = try mod.createAnonymousDecl(block, .{ | |
| 5529 | .ty = ty, | |
| 5530 | .val = val.toValue(), | |
| 5531 | }); | |
| 5532 | gop.value_ptr.* = new_decl_index; | |
| 5533 | try mod.finalizeAnonDecl(new_decl_index); | |
| 5534 | } | |
| 5535 | return sema.analyzeDeclRef(gop.value_ptr.*); | |
| 5526 | const ptr_ty = try sema.ptrType(.{ | |
| 5527 | .child = array_ty.toIntern(), | |
| 5528 | .flags = .{ | |
| 5529 | .alignment = .none, | |
| 5530 | .is_const = true, | |
| 5531 | .address_space = .generic, | |
| 5532 | }, | |
| 5533 | }); | |
| 5534 | return Air.internedToRef((try mod.intern(.{ .ptr = .{ | |
| 5535 | .ty = ptr_ty.toIntern(), | |
| 5536 | .addr = .{ .anon_decl = val }, | |
| 5537 | } }))); | |
| 5536 | 5538 | } |
| 5537 | 5539 | |
| 5538 | 5540 | fn 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 | 12909 | try sema.zirSaveErrRetIndex(block, inst); |
| 12908 | 12910 | continue; |
| 12909 | 12911 | }, |
| 12910 | .str => try sema.zirStr(block, inst), | |
| 12912 | .str => try sema.zirStr(inst), | |
| 12911 | 12913 | .as_node => try sema.zirAsNode(block, inst), |
| 12912 | 12914 | .field_val => try sema.zirFieldVal(block, inst), |
| 12913 | 12915 | .@"unreachable" => { |
| ... | ... | @@ -20170,7 +20172,7 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A |
| 20170 | 20172 | |
| 20171 | 20173 | if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { |
| 20172 | 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 | } |
| 20175 | 20177 | |
| 20176 | 20178 | // 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 | 20290 | .EnumLiteral => { |
| 20289 | 20291 | const val = try sema.resolveConstValue(block, .unneeded, operand, undefined); |
| 20290 | 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 | 20295 | .Enum => operand_ty, |
| 20294 | 20296 | .Union => operand_ty.unionTagType(mod) orelse { |
| ... | ... | @@ -20330,7 +20332,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 20330 | 20332 | }; |
| 20331 | 20333 | // TODO: write something like getCoercedInts to avoid needing to dupe |
| 20332 | 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 | 20337 | try sema.requireRuntimeBlock(block, src, operand_src); |
| 20336 | 20338 | if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) { |
| ... | ... | @@ -29859,7 +29861,7 @@ fn beginComptimePtrMutation( |
| 29859 | 29861 | const mod = sema.mod; |
| 29860 | 29862 | const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr; |
| 29861 | 29863 | switch (ptr.addr) { |
| 29862 | .decl, .int => unreachable, // isComptimeMutablePtr has been checked already | |
| 29864 | .decl, .anon_decl, .int => unreachable, // isComptimeMutablePtr has been checked already | |
| 29863 | 29865 | .mut_decl => |mut_decl| { |
| 29864 | 29866 | const decl = mod.declPtr(mut_decl.decl); |
| 29865 | 29867 | return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl); |
| ... | ... | @@ -30455,9 +30457,10 @@ fn beginComptimePtrLoad( |
| 30455 | 30457 | maybe_array_ty: ?Type, |
| 30456 | 30458 | ) ComptimePtrLoadError!ComptimePtrLoadKit { |
| 30457 | 30459 | const mod = sema.mod; |
| 30460 | const ip = &mod.intern_pool; | |
| 30458 | 30461 | const target = mod.getTarget(); |
| 30459 | 30462 | |
| 30460 | var deref: ComptimePtrLoadKit = switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) { | |
| 30463 | var deref: ComptimePtrLoadKit = switch (ip.indexToKey(ptr_val.toIntern())) { | |
| 30461 | 30464 | .ptr => |ptr| switch (ptr.addr) { |
| 30462 | 30465 | .decl, .mut_decl => blk: { |
| 30463 | 30466 | const decl_index = switch (ptr.addr) { |
| ... | ... | @@ -30478,9 +30481,21 @@ fn beginComptimePtrLoad( |
| 30478 | 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 | 30496 | .int => return error.RuntimeLoad, |
| 30482 | 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 | 30499 | const payload_ty = switch (ptr.addr) { |
| 30485 | 30500 | .eu_payload => container_ty.errorUnionPayload(mod), |
| 30486 | 30501 | .opt_payload => container_ty.optionalChild(mod), |
| ... | ... | @@ -30502,13 +30517,13 @@ fn beginComptimePtrLoad( |
| 30502 | 30517 | const payload_val = switch (tv.val.ip_index) { |
| 30503 | 30518 | .none => tv.val.cast(Value.Payload.SubValue).?.data, |
| 30504 | 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 | 30521 | .error_union => |error_union| switch (error_union.val) { |
| 30507 | 30522 | .err_name => |err_name| return sema.fail( |
| 30508 | 30523 | block, |
| 30509 | 30524 | src, |
| 30510 | 30525 | "attempt to unwrap error: {}", |
| 30511 | .{err_name.fmt(&mod.intern_pool)}, | |
| 30526 | .{err_name.fmt(ip)}, | |
| 30512 | 30527 | ), |
| 30513 | 30528 | .payload => |payload| payload, |
| 30514 | 30529 | }, |
| ... | ... | @@ -30527,7 +30542,7 @@ fn beginComptimePtrLoad( |
| 30527 | 30542 | break :blk deref; |
| 30528 | 30543 | }, |
| 30529 | 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 | 30546 | break :blk ComptimePtrLoadKit{ |
| 30532 | 30547 | .parent = null, |
| 30533 | 30548 | .pointee = .{ .ty = field_ty, .val = comptime_field.toValue() }, |
| ... | ... | @@ -30536,15 +30551,15 @@ fn beginComptimePtrLoad( |
| 30536 | 30551 | }; |
| 30537 | 30552 | }, |
| 30538 | 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 | 30555 | var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.base.toValue(), null); |
| 30541 | 30556 | |
| 30542 | 30557 | // This code assumes that elem_ptrs have been "flattened" in order for direct dereference |
| 30543 | 30558 | // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that |
| 30544 | 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 | 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 | 30563 | else => {}, |
| 30549 | 30564 | }, |
| 30550 | 30565 | else => {}, |
| ... | ... | @@ -30616,7 +30631,7 @@ fn beginComptimePtrLoad( |
| 30616 | 30631 | }, |
| 30617 | 30632 | .field => |field_ptr| blk: { |
| 30618 | 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 | 30635 | var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.base.toValue(), container_ty); |
| 30621 | 30636 | |
| 30622 | 30637 | if (container_ty.hasWellDefinedLayout(mod)) { |
| ... | ... | @@ -30655,7 +30670,7 @@ fn beginComptimePtrLoad( |
| 30655 | 30670 | }, |
| 30656 | 30671 | Value.slice_len_index => TypedValue{ |
| 30657 | 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 | 30675 | else => unreachable, |
| 30661 | 30676 | }; |
| ... | ... | @@ -34529,7 +34544,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value { |
| 34529 | 34544 | else => (try sema.resolveLazyValue(ptr.len.toValue())).toIntern(), |
| 34530 | 34545 | }; |
| 34531 | 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 | 34548 | val |
| 34534 | 34549 | else |
| 34535 | 34550 | (try mod.intern(.{ .ptr = .{ |
| ... | ... | @@ -34537,6 +34552,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value { |
| 34537 | 34552 | .addr = switch (ptr.addr) { |
| 34538 | 34553 | .decl => |decl| .{ .decl = decl }, |
| 34539 | 34554 | .mut_decl => |mut_decl| .{ .mut_decl = mut_decl }, |
| 34555 | .anon_decl => |anon_decl| .{ .anon_decl = anon_decl }, | |
| 34540 | 34556 | else => unreachable, |
| 34541 | 34557 | }, |
| 34542 | 34558 | .len = resolved_len, |
| ... | ... | @@ -36568,6 +36584,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { |
| 36568 | 36584 | .runtime_value, |
| 36569 | 36585 | .simple_value, |
| 36570 | 36586 | .ptr_decl, |
| 36587 | .ptr_anon_decl, | |
| 36571 | 36588 | .ptr_mut_decl, |
| 36572 | 36589 | .ptr_comptime_field, |
| 36573 | 36590 | .ptr_int, |
src/TypedValue.zig+9| ... | ... | @@ -321,6 +321,15 @@ pub fn print( |
| 321 | 321 | .val = decl.val, |
| 322 | 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 | 333 | .mut_decl => |mut_decl| { |
| 325 | 334 | const decl = mod.declPtr(mut_decl.decl); |
| 326 | 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 | 3075 | .decl => |decl_index| { |
| 3076 | 3076 | return func.lowerParentPtrDecl(ptr_val, decl_index, offset); |
| 3077 | 3077 | }, |
| 3078 | .anon_decl => |ad| return func.lowerAnonDeclRef(ad, offset), | |
| 3078 | 3079 | .mut_decl => |mut_decl| { |
| 3079 | 3080 | const decl_index = mut_decl.decl; |
| 3080 | 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 | 3139 | return func.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index, offset); |
| 3139 | 3140 | } |
| 3140 | 3141 | |
| 3142 | fn 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 | ||
| 3141 | 3168 | fn lowerDeclRefValue(func: *CodeGen, tv: TypedValue, decl_index: Module.Decl.Index, offset: u32) InnerError!WValue { |
| 3142 | 3169 | const mod = func.bin_file.base.options.module.?; |
| 3143 | 3170 | if (tv.ty.isSlice(mod)) { |
| ... | ... | @@ -3305,6 +3332,7 @@ fn lowerConstant(func: *CodeGen, arg_val: Value, ty: Type) InnerError!WValue { |
| 3305 | 3332 | .mut_decl => |mut_decl| return func.lowerDeclRefValue(.{ .ty = ty, .val = val }, mut_decl.decl, 0), |
| 3306 | 3333 | .int => |int| return func.lowerConstant(int.toValue(), ip.typeOf(int).toType()), |
| 3307 | 3334 | .opt_payload, .elem, .field => return func.lowerParentPtr(val, 0), |
| 3335 | .anon_decl => |ad| return func.lowerAnonDeclRef(ad, 0), | |
| 3308 | 3336 | else => return func.fail("Wasm TODO: lowerConstant for other const addr tag {}", .{ptr.addr}), |
| 3309 | 3337 | }, |
| 3310 | 3338 | .opt => if (ty.optionalReprIsPayload(mod)) { |
src/codegen.zig+45-12| ... | ... | @@ -643,18 +643,9 @@ fn lowerParentPtr( |
| 643 | 643 | const ptr = mod.intern_pool.indexToKey(parent_ptr).ptr; |
| 644 | 644 | assert(ptr.len == .none); |
| 645 | 645 | return switch (ptr.addr) { |
| 646 | .decl, .mut_decl => try lowerDeclRef( | |
| 647 | bin_file, | |
| 648 | src_loc, | |
| 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 | ), | |
| 646 | .decl => |decl| try lowerDeclRef(bin_file, src_loc, decl, code, debug_output, reloc_info), | |
| 647 | .mut_decl => |md| try lowerDeclRef(bin_file, src_loc, md.decl, code, debug_output, reloc_info), | |
| 648 | .anon_decl => |ad| try lowerAnonDeclRef(bin_file, src_loc, ad, code, debug_output, reloc_info), | |
| 658 | 649 | .int => |int| try generateSymbol(bin_file, src_loc, .{ |
| 659 | 650 | .ty = Type.usize, |
| 660 | 651 | .val = int.toValue(), |
| ... | ... | @@ -740,6 +731,48 @@ const RelocInfo = struct { |
| 740 | 731 | } |
| 741 | 732 | }; |
| 742 | 733 | |
| 734 | fn 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 | ||
| 743 | 776 | fn lowerDeclRef( |
| 744 | 777 | bin_file: *link.File, |
| 745 | 778 | src_loc: Module.SrcLoc, |
src/codegen/c.zig+94-38| ... | ... | @@ -528,6 +528,9 @@ pub const DeclGen = struct { |
| 528 | 528 | fwd_decl: std.ArrayList(u8), |
| 529 | 529 | error_msg: ?*Module.ErrorMsg, |
| 530 | 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), | |
| 531 | 534 | |
| 532 | 535 | fn fail(dg: *DeclGen, comptime format: []const u8, args: anytype) error{ AnalysisFail, OutOfMemory } { |
| 533 | 536 | @setCold(true); |
| ... | ... | @@ -540,6 +543,58 @@ pub const DeclGen = struct { |
| 540 | 543 | return error.AnalysisFail; |
| 541 | 544 | } |
| 542 | 545 | |
| 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 | 598 | fn renderDeclValue( |
| 544 | 599 | dg: *DeclGen, |
| 545 | 600 | writer: anytype, |
| ... | ... | @@ -593,17 +648,9 @@ pub const DeclGen = struct { |
| 593 | 648 | const ptr_cty = try dg.typeToIndex(ptr_ty, .complete); |
| 594 | 649 | const ptr = mod.intern_pool.indexToKey(ptr_val).ptr; |
| 595 | 650 | switch (ptr.addr) { |
| 596 | .decl, .mut_decl => try dg.renderDeclValue( | |
| 597 | writer, | |
| 598 | ptr_ty, | |
| 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 | ), | |
| 651 | .decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), d, location), | |
| 652 | .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val.toValue(), md.decl, location), | |
| 653 | .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val.toValue(), decl_val, location), | |
| 607 | 654 | .int => |int| { |
| 608 | 655 | try writer.writeByte('('); |
| 609 | 656 | try dg.renderCType(writer, ptr_cty); |
| ... | ... | @@ -1144,17 +1191,9 @@ pub const DeclGen = struct { |
| 1144 | 1191 | else => val.slicePtr(mod), |
| 1145 | 1192 | }; |
| 1146 | 1193 | switch (ptr.addr) { |
| 1147 | .decl, .mut_decl => try dg.renderDeclValue( | |
| 1148 | writer, | |
| 1149 | ptr_ty, | |
| 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 | ), | |
| 1194 | .decl => |d| try dg.renderDeclValue(writer, ptr_ty, ptr_val, d, ptr_location), | |
| 1195 | .mut_decl => |md| try dg.renderDeclValue(writer, ptr_ty, ptr_val, md.decl, ptr_location), | |
| 1196 | .anon_decl => |decl_val| try dg.renderAnonDeclValue(writer, ptr_ty, ptr_val, decl_val, ptr_location), | |
| 1158 | 1197 | .int => |int| { |
| 1159 | 1198 | try writer.writeAll("(("); |
| 1160 | 1199 | try dg.renderType(writer, ptr_ty); |
| ... | ... | @@ -1768,7 +1807,7 @@ pub const DeclGen = struct { |
| 1768 | 1807 | .none => unreachable, |
| 1769 | 1808 | .local, .new_local => |i| return w.print("t{d}", .{i}), |
| 1770 | 1809 | .local_ref => |i| return w.print("&t{d}", .{i}), |
| 1771 | .constant => unreachable, | |
| 1810 | .constant => |val| return renderAnonDeclName(w, val), | |
| 1772 | 1811 | .arg => |i| return w.print("a{d}", .{i}), |
| 1773 | 1812 | .arg_array => |i| return dg.writeCValueMember(w, .{ .arg = i }, .{ .identifier = "array" }), |
| 1774 | 1813 | .field => |i| return w.print("f{d}", .{i}), |
| ... | ... | @@ -1886,6 +1925,10 @@ pub const DeclGen = struct { |
| 1886 | 1925 | } |
| 1887 | 1926 | } |
| 1888 | 1927 | |
| 1928 | fn renderAnonDeclName(writer: anytype, anon_decl_val: InternPool.Index) !void { | |
| 1929 | return writer.print("__anon_{d}", .{@intFromEnum(anon_decl_val)}); | |
| 1930 | } | |
| 1931 | ||
| 1889 | 1932 | fn renderTypeForBuiltinFnName(dg: *DeclGen, writer: anytype, ty: Type) !void { |
| 1890 | 1933 | try dg.renderCTypeForBuiltinFnName(writer, try dg.typeToCType(ty, .complete)); |
| 1891 | 1934 | } |
| ... | ... | @@ -2723,7 +2766,6 @@ pub fn genDecl(o: *Object) !void { |
| 2723 | 2766 | |
| 2724 | 2767 | const mod = o.dg.module; |
| 2725 | 2768 | const decl_index = o.dg.decl_index.unwrap().?; |
| 2726 | const decl_c_value = .{ .decl = decl_index }; | |
| 2727 | 2769 | const decl = mod.declPtr(decl_index); |
| 2728 | 2770 | const tv: TypedValue = .{ .ty = decl.ty, .val = (try decl.internValue(mod)).toValue() }; |
| 2729 | 2771 | |
| ... | ... | @@ -2747,6 +2789,7 @@ pub fn genDecl(o: *Object) !void { |
| 2747 | 2789 | if (variable.is_threadlocal) try w.writeAll("zig_threadlocal "); |
| 2748 | 2790 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| |
| 2749 | 2791 | try w.print("zig_linksection(\"{s}\", ", .{s}); |
| 2792 | const decl_c_value = .{ .decl = decl_index }; | |
| 2750 | 2793 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, .{}, decl.alignment, .complete); |
| 2751 | 2794 | if (decl.@"linksection" != .none) try w.writeAll(", read, write)"); |
| 2752 | 2795 | try w.writeAll(" = "); |
| ... | ... | @@ -2755,22 +2798,35 @@ pub fn genDecl(o: *Object) !void { |
| 2755 | 2798 | try o.indent_writer.insertNewline(); |
| 2756 | 2799 | } else { |
| 2757 | 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 | } | |
| 2759 | 2805 | |
| 2760 | try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); | |
| 2761 | try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, decl.alignment, .complete); | |
| 2762 | try fwd_decl_writer.writeAll(";\n"); | |
| 2806 | pub fn genDeclValue( | |
| 2807 | o: *Object, | |
| 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(); | |
| 2763 | 2815 | |
| 2764 | const w = o.writer(); | |
| 2765 | if (!is_global) try w.writeAll("static "); | |
| 2766 | if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| | |
| 2767 | try w.print("zig_linksection(\"{s}\", ", .{s}); | |
| 2768 | try o.dg.renderTypeAndName(w, tv.ty, decl_c_value, Const, decl.alignment, .complete); | |
| 2769 | if (decl.@"linksection" != .none) try w.writeAll(", read)"); | |
| 2770 | try w.writeAll(" = "); | |
| 2771 | try o.dg.renderValue(w, tv.ty, tv.val, .StaticInitializer); | |
| 2772 | try w.writeAll(";\n"); | |
| 2773 | } | |
| 2816 | try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static "); | |
| 2817 | try o.dg.renderTypeAndName(fwd_decl_writer, tv.ty, decl_c_value, Const, alignment, .complete); | |
| 2818 | try fwd_decl_writer.writeAll(";\n"); | |
| 2819 | ||
| 2820 | const mod = o.dg.module; | |
| 2821 | const w = o.writer(); | |
| 2822 | if (!is_global) try w.writeAll("static "); | |
| 2823 | if (mod.intern_pool.stringToSliceUnwrap(link_section)) |s| | |
| 2824 | try w.print("zig_linksection(\"{s}\", ", .{s}); | |
| 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 | } |
| 2775 | 2831 | |
| 2776 | 2832 | pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void { |
src/codegen/llvm.zig+83-7| ... | ... | @@ -810,6 +810,8 @@ pub const Object = struct { |
| 810 | 810 | /// * it works for functions not all globals. |
| 811 | 811 | /// Therefore, this table keeps track of the mapping. |
| 812 | 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 | 815 | /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction. |
| 814 | 816 | named_enum_map: std.AutoHashMapUnmanaged(Module.Decl.Index, Builder.Function.Index), |
| 815 | 817 | /// Maps Zig types to LLVM types. The table memory is backed by the GPA of |
| ... | ... | @@ -993,6 +995,7 @@ pub const Object = struct { |
| 993 | 995 | .target_data = target_data, |
| 994 | 996 | .target = options.target, |
| 995 | 997 | .decl_map = .{}, |
| 998 | .anon_decl_map = .{}, | |
| 996 | 999 | .named_enum_map = .{}, |
| 997 | 1000 | .type_map = .{}, |
| 998 | 1001 | .di_type_map = .{}, |
| ... | ... | @@ -1011,6 +1014,7 @@ pub const Object = struct { |
| 1011 | 1014 | self.target_machine.dispose(); |
| 1012 | 1015 | } |
| 1013 | 1016 | self.decl_map.deinit(gpa); |
| 1017 | self.anon_decl_map.deinit(gpa); | |
| 1014 | 1018 | self.named_enum_map.deinit(gpa); |
| 1015 | 1019 | self.type_map.deinit(gpa); |
| 1016 | 1020 | self.extern_collisions.deinit(gpa); |
| ... | ... | @@ -3038,6 +3042,31 @@ pub const Object = struct { |
| 3038 | 3042 | } |
| 3039 | 3043 | } |
| 3040 | 3044 | |
| 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 | 3070 | fn resolveGlobalDecl( |
| 3042 | 3071 | o: *Object, |
| 3043 | 3072 | decl_index: Module.Decl.Index, |
| ... | ... | @@ -3764,6 +3793,7 @@ pub const Object = struct { |
| 3764 | 3793 | const ptr_val = switch (ptr.addr) { |
| 3765 | 3794 | .decl => |decl| try o.lowerDeclRefValue(ptr_ty, decl), |
| 3766 | 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 | 3797 | .int => |int| try o.lowerIntAsPtr(int), |
| 3768 | 3798 | .eu_payload, |
| 3769 | 3799 | .opt_payload, |
| ... | ... | @@ -4216,10 +4246,12 @@ pub const Object = struct { |
| 4216 | 4246 | return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint); |
| 4217 | 4247 | } |
| 4218 | 4248 | |
| 4219 | const ParentPtr = struct { | |
| 4220 | ty: Type, | |
| 4221 | llvm_ptr: Builder.Value, | |
| 4222 | }; | |
| 4249 | fn lowerParentPtrAnonDecl(o: *Object, decl_val: InternPool.Index) Error!Builder.Constant { | |
| 4250 | const mod = o.module; | |
| 4251 | const decl_ty = mod.intern_pool.typeOf(decl_val).toType(); | |
| 4252 | const ptr_ty = try mod.singleMutPtrType(decl_ty); | |
| 4253 | return o.lowerAnonDeclRef(ptr_ty, decl_val); | |
| 4254 | } | |
| 4223 | 4255 | |
| 4224 | 4256 | fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant { |
| 4225 | 4257 | const mod = o.module; |
| ... | ... | @@ -4229,13 +4261,14 @@ pub const Object = struct { |
| 4229 | 4261 | return o.lowerDeclRefValue(ptr_ty, decl_index); |
| 4230 | 4262 | } |
| 4231 | 4263 | |
| 4232 | fn lowerParentPtr(o: *Object, ptr_val: Value) Allocator.Error!Builder.Constant { | |
| 4264 | fn lowerParentPtr(o: *Object, ptr_val: Value) Error!Builder.Constant { | |
| 4233 | 4265 | const mod = o.module; |
| 4234 | 4266 | const ip = &mod.intern_pool; |
| 4235 | 4267 | const ptr = ip.indexToKey(ptr_val.toIntern()).ptr; |
| 4236 | 4268 | return switch (ptr.addr) { |
| 4237 | .decl => |decl| o.lowerParentPtrDecl(decl), | |
| 4238 | .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl), | |
| 4269 | .decl => |decl| try o.lowerParentPtrDecl(decl), | |
| 4270 | .mut_decl => |mut_decl| try o.lowerParentPtrDecl(mut_decl.decl), | |
| 4271 | .anon_decl => |anon_decl| try o.lowerParentPtrAnonDecl(anon_decl), | |
| 4239 | 4272 | .int => |int| try o.lowerIntAsPtr(int), |
| 4240 | 4273 | .eu_payload => |eu_ptr| { |
| 4241 | 4274 | const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue()); |
| ... | ... | @@ -4349,6 +4382,49 @@ pub const Object = struct { |
| 4349 | 4382 | }; |
| 4350 | 4383 | } |
| 4351 | 4384 | |
| 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 | 4428 | fn lowerDeclRefValue(o: *Object, ty: Type, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant { |
| 4353 | 4429 | const mod = o.module; |
| 4354 | 4430 |
src/codegen/spirv.zig+1| ... | ... | @@ -818,6 +818,7 @@ pub const DeclGen = struct { |
| 818 | 818 | const mod = self.module; |
| 819 | 819 | switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { |
| 820 | 820 | .decl => |decl| return try self.constructDeclRef(ptr_ty, decl), |
| 821 | .anon_decl => @panic("TODO"), | |
| 821 | 822 | .mut_decl => |decl_mut| return try self.constructDeclRef(ptr_ty, decl_mut.decl), |
| 822 | 823 | .int => |int| { |
| 823 | 824 | const ptr_id = self.spv.allocId(); |
src/link.zig+30| ... | ... | @@ -937,6 +937,36 @@ pub const File = struct { |
| 937 | 937 | } |
| 938 | 938 | } |
| 939 | 939 | |
| 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 | 970 | /// This function is called by the frontend before flush(). It communicates that |
| 941 | 971 | /// `options.bin_file.emit` directory needs to be renamed from |
| 942 | 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 | 27 | /// While in progress, a separate buffer is used, and then when finished, the |
| 28 | 28 | /// buffer is copied into this one. |
| 29 | 29 | string_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(). | |
| 32 | anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, DeclBlock) = .{}, | |
| 30 | 33 | |
| 31 | 34 | /// Optimization, `updateDecl` reuses this buffer rather than creating a new |
| 32 | 35 | /// one with every call. |
| ... | ... | @@ -42,7 +45,7 @@ lazy_fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 42 | 45 | lazy_code_buf: std.ArrayListUnmanaged(u8) = .{}, |
| 43 | 46 | |
| 44 | 47 | /// A reference into `string_bytes`. |
| 45 | const String = struct { | |
| 48 | const String = extern struct { | |
| 46 | 49 | start: u32, |
| 47 | 50 | len: u32, |
| 48 | 51 | |
| ... | ... | @@ -53,7 +56,7 @@ const String = struct { |
| 53 | 56 | }; |
| 54 | 57 | |
| 55 | 58 | /// Per-declaration data. |
| 56 | const DeclBlock = struct { | |
| 59 | pub const DeclBlock = struct { | |
| 57 | 60 | code: String = String.empty, |
| 58 | 61 | fwd_decl: String = String.empty, |
| 59 | 62 | /// 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 | 101 | var c_file = try gpa.create(C); |
| 99 | 102 | errdefer gpa.destroy(c_file); |
| 100 | 103 | |
| 101 | c_file.* = C{ | |
| 104 | c_file.* = .{ | |
| 102 | 105 | .base = .{ |
| 103 | 106 | .tag = .c, |
| 104 | 107 | .options = options, |
| ... | ... | @@ -118,6 +121,11 @@ pub fn deinit(self: *C) void { |
| 118 | 121 | } |
| 119 | 122 | self.decl_table.deinit(gpa); |
| 120 | 123 | |
| 124 | for (self.anon_decls.values()) |*db| { | |
| 125 | db.deinit(gpa); | |
| 126 | } | |
| 127 | self.anon_decls.deinit(gpa); | |
| 128 | ||
| 121 | 129 | self.string_bytes.deinit(gpa); |
| 122 | 130 | self.fwd_decl_buf.deinit(gpa); |
| 123 | 131 | self.code_buf.deinit(gpa); |
| ... | ... | @@ -131,10 +139,13 @@ pub fn freeDecl(self: *C, decl_index: Module.Decl.Index) void { |
| 131 | 139 | } |
| 132 | 140 | } |
| 133 | 141 | |
| 134 | pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air: Air, liveness: Liveness) !void { | |
| 135 | const tracy = trace(@src()); | |
| 136 | defer tracy.end(); | |
| 137 | ||
| 142 | pub fn updateFunc( | |
| 143 | self: *C, | |
| 144 | module: *Module, | |
| 145 | func_index: InternPool.Index, | |
| 146 | air: Air, | |
| 147 | liveness: Liveness, | |
| 148 | ) !void { | |
| 138 | 149 | const gpa = self.base.allocator; |
| 139 | 150 | |
| 140 | 151 | const func = module.funcInfo(func_index); |
| ... | ... | @@ -167,6 +178,7 @@ pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air: |
| 167 | 178 | .is_naked_fn = decl.ty.fnCallingConvention(module) == .Naked, |
| 168 | 179 | .fwd_decl = fwd_decl.toManaged(gpa), |
| 169 | 180 | .ctypes = ctypes.*, |
| 181 | .anon_decl_deps = self.anon_decls, | |
| 170 | 182 | }, |
| 171 | 183 | .code = code.toManaged(gpa), |
| 172 | 184 | .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 | 188 | |
| 177 | 189 | function.object.indent_writer = .{ .underlying_writer = function.object.code.writer() }; |
| 178 | 190 | defer { |
| 191 | self.anon_decls = function.object.dg.anon_decl_deps; | |
| 179 | 192 | fwd_decl.* = function.object.dg.fwd_decl.moveToUnmanaged(); |
| 180 | 193 | code.* = function.object.code.moveToUnmanaged(); |
| 181 | 194 | function.deinit(); |
| ... | ... | @@ -200,6 +213,62 @@ pub fn updateFunc(self: *C, module: *Module, func_index: InternPool.Index, air: |
| 200 | 213 | gop.value_ptr.fwd_decl = try self.addString(function.object.dg.fwd_decl.items); |
| 201 | 214 | } |
| 202 | 215 | |
| 216 | fn 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 | ||
| 203 | 272 | pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !void { |
| 204 | 273 | const tracy = trace(@src()); |
| 205 | 274 | defer tracy.end(); |
| ... | ... | @@ -226,12 +295,14 @@ pub fn updateDecl(self: *C, module: *Module, decl_index: Module.Decl.Index) !voi |
| 226 | 295 | .is_naked_fn = false, |
| 227 | 296 | .fwd_decl = fwd_decl.toManaged(gpa), |
| 228 | 297 | .ctypes = ctypes.*, |
| 298 | .anon_decl_deps = self.anon_decls, | |
| 229 | 299 | }, |
| 230 | 300 | .code = code.toManaged(gpa), |
| 231 | 301 | .indent_writer = undefined, // set later so we can get a pointer to object.code |
| 232 | 302 | }; |
| 233 | 303 | object.indent_writer = .{ .underlying_writer = object.code.writer() }; |
| 234 | 304 | defer { |
| 305 | self.anon_decls = object.dg.anon_decl_deps; | |
| 235 | 306 | object.dg.ctypes.deinit(object.dg.gpa); |
| 236 | 307 | fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged(); |
| 237 | 308 | code.* = object.code.moveToUnmanaged(); |
| ... | ... | @@ -289,6 +360,13 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo |
| 289 | 360 | const gpa = self.base.allocator; |
| 290 | 361 | const module = self.base.options.module.?; |
| 291 | 362 | |
| 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 | 370 | // This code path happens exclusively with -ofmt=c. The flush logic for |
| 293 | 371 | // emit-h is in `flushEmitH` below. |
| 294 | 372 | |
| ... | ... | @@ -331,10 +409,15 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo |
| 331 | 409 | for (module.decl_exports.values()) |exports| for (exports.items) |@"export"| |
| 332 | 410 | try export_names.put(gpa, @"export".opts.name, {}); |
| 333 | 411 | |
| 334 | const decl_keys = self.decl_table.keys(); | |
| 335 | for (decl_keys) |decl_index| { | |
| 412 | for (self.anon_decls.values()) |*decl_block| { | |
| 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 | 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 | } |
| 340 | 423 | |
| ... | ... | @@ -344,8 +427,12 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo |
| 344 | 427 | assert(f.ctypes.count() == 0); |
| 345 | 428 | try self.flushCTypes(&f, .none, f.lazy_ctypes); |
| 346 | 429 | |
| 347 | for (self.decl_table.keys(), self.decl_table.values()) |decl_index, db| { | |
| 348 | try self.flushCTypes(&f, decl_index.toOptional(), db.ctypes); | |
| 430 | for (self.anon_decls.values()) |decl_block| { | |
| 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 | } |
| 351 | 438 | |
| ... | ... | @@ -363,10 +450,12 @@ pub fn flushModule(self: *C, _: *Compilation, prog_node: *std.Progress.Node) !vo |
| 363 | 450 | f.file_size += lazy_fwd_decl_len; |
| 364 | 451 | |
| 365 | 452 | // Now the code. |
| 453 | const anon_decl_values = self.anon_decls.values(); | |
| 366 | 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 | 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)); | |
| 370 | 459 | |
| 371 | 460 | const file = self.base.file.?; |
| 372 | 461 | try file.setEndPos(f.file_size); |
| ... | ... | @@ -512,12 +601,14 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void { |
| 512 | 601 | .is_naked_fn = false, |
| 513 | 602 | .fwd_decl = fwd_decl.toManaged(gpa), |
| 514 | 603 | .ctypes = ctypes.*, |
| 604 | .anon_decl_deps = self.anon_decls, | |
| 515 | 605 | }, |
| 516 | 606 | .code = code.toManaged(gpa), |
| 517 | 607 | .indent_writer = undefined, // set later so we can get a pointer to object.code |
| 518 | 608 | }; |
| 519 | 609 | object.indent_writer = .{ .underlying_writer = object.code.writer() }; |
| 520 | 610 | defer { |
| 611 | self.anon_decls = object.dg.anon_decl_deps; | |
| 521 | 612 | object.dg.ctypes.deinit(gpa); |
| 522 | 613 | fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged(); |
| 523 | 614 | code.* = object.code.moveToUnmanaged(); |
| ... | ... | @@ -531,7 +622,11 @@ fn flushErrDecls(self: *C, ctypes: *codegen.CType.Store) FlushDeclError!void { |
| 531 | 622 | ctypes.* = object.dg.ctypes.move(); |
| 532 | 623 | } |
| 533 | 624 | |
| 534 | fn flushLazyFn(self: *C, ctypes: *codegen.CType.Store, lazy_fn: codegen.LazyFnMap.Entry) FlushDeclError!void { | |
| 625 | fn flushLazyFn( | |
| 626 | self: *C, | |
| 627 | ctypes: *codegen.CType.Store, | |
| 628 | lazy_fn: codegen.LazyFnMap.Entry, | |
| 629 | ) FlushDeclError!void { | |
| 535 | 630 | const gpa = self.base.allocator; |
| 536 | 631 | |
| 537 | 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 | 641 | .is_naked_fn = false, |
| 547 | 642 | .fwd_decl = fwd_decl.toManaged(gpa), |
| 548 | 643 | .ctypes = ctypes.*, |
| 644 | .anon_decl_deps = .{}, | |
| 549 | 645 | }, |
| 550 | 646 | .code = code.toManaged(gpa), |
| 551 | 647 | .indent_writer = undefined, // set later so we can get a pointer to object.code |
| 552 | 648 | }; |
| 553 | 649 | object.indent_writer = .{ .underlying_writer = object.code.writer() }; |
| 554 | 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 | 654 | object.dg.ctypes.deinit(gpa); |
| 556 | 655 | fwd_decl.* = object.dg.fwd_decl.moveToUnmanaged(); |
| 557 | 656 | code.* = object.code.moveToUnmanaged(); |
| ... | ... | @@ -578,22 +677,22 @@ fn flushLazyFns(self: *C, f: *Flush, lazy_fns: codegen.LazyFnMap) FlushDeclError |
| 578 | 677 | } |
| 579 | 678 | } |
| 580 | 679 | |
| 581 | fn flushDecl( | |
| 680 | fn flushDeclBlock( | |
| 582 | 681 | self: *C, |
| 583 | 682 | f: *Flush, |
| 584 | decl_index: Module.Decl.Index, | |
| 683 | decl_block: *DeclBlock, | |
| 585 | 684 | export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void), |
| 685 | extern_symbol_name: InternPool.OptionalNullTerminatedString, | |
| 586 | 686 | ) FlushDeclError!void { |
| 587 | 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 | 688 | try self.flushLazyFns(f, decl_block.lazy_fns); |
| 594 | 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 | 694 | f.appendBufAssumeCapacity(self.getString(decl_block.fwd_decl)); |
| 695 | } | |
| 597 | 696 | } |
| 598 | 697 | |
| 599 | 698 | pub 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 | 82 | /// value assigned to label `foo` is an unnamed constant belonging/associated |
| 83 | 83 | /// with `Decl` `main`, and lives as long as that `Decl`. |
| 84 | 84 | unnamed_const_atoms: UnnamedConstTable = .{}, |
| 85 | anon_decls: AnonDeclTable = .{}, | |
| 85 | 86 | |
| 86 | 87 | /// A table of relocations indexed by the owning them `Atom`. |
| 87 | 88 | /// Note that once we refactor `Atom`'s lifetime and ownership rules, |
| ... | ... | @@ -107,6 +108,7 @@ const HotUpdateState = struct { |
| 107 | 108 | loaded_base_address: ?std.os.windows.HMODULE = null, |
| 108 | 109 | }; |
| 109 | 110 | |
| 111 | const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index); | |
| 110 | 112 | const RelocTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Relocation)); |
| 111 | 113 | const BaseRelocationTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); |
| 112 | 114 | const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); |
| ... | ... | @@ -323,6 +325,7 @@ pub fn deinit(self: *Coff) void { |
| 323 | 325 | atoms.deinit(gpa); |
| 324 | 326 | } |
| 325 | 327 | self.unnamed_const_atoms.deinit(gpa); |
| 328 | self.anon_decls.deinit(gpa); | |
| 326 | 329 | |
| 327 | 330 | for (self.relocs.values()) |*relocs| { |
| 328 | 331 | relocs.deinit(gpa); |
| ... | ... | @@ -1077,45 +1080,53 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air: |
| 1077 | 1080 | |
| 1078 | 1081 | pub fn lowerUnnamedConst(self: *Coff, tv: TypedValue, decl_index: Module.Decl.Index) !u32 { |
| 1079 | 1082 | const gpa = self.base.allocator; |
| 1080 | var code_buffer = std.ArrayList(u8).init(gpa); | |
| 1081 | defer code_buffer.deinit(); | |
| 1082 | ||
| 1083 | 1083 | const mod = self.base.options.module.?; |
| 1084 | 1084 | const decl = mod.declPtr(decl_index); |
| 1085 | ||
| 1086 | 1085 | const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index); |
| 1087 | 1086 | if (!gop.found_existing) { |
| 1088 | 1087 | gop.value_ptr.* = .{}; |
| 1089 | 1088 | } |
| 1090 | 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 | } | |
| 1091 | 1106 | |
| 1092 | const atom_index = try self.createAtom(); | |
| 1107 | const LowerConstResult = union(enum) { | |
| 1108 | ok: Atom.Index, | |
| 1109 | fail: *Module.ErrorMsg, | |
| 1110 | }; | |
| 1093 | 1111 | |
| 1094 | const sym_name = blk: { | |
| 1095 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 1112 | fn lowerConst(self: *Coff, name: []const u8, tv: TypedValue, sect_id: u16, src_loc: Module.SrcLoc) !LowerConstResult { | |
| 1113 | const gpa = self.base.allocator; | |
| 1096 | 1114 | |
| 1097 | const index = unnamed_consts.items.len; | |
| 1098 | break :blk try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); | |
| 1099 | }; | |
| 1100 | defer gpa.free(sym_name); | |
| 1101 | { | |
| 1102 | const atom = self.getAtom(atom_index); | |
| 1103 | const sym = atom.getSymbolPtr(self); | |
| 1104 | try self.setSymbolName(sym, sym_name); | |
| 1105 | sym.section_number = @as(coff.SectionNumber, @enumFromInt(self.rdata_section_index.? + 1)); | |
| 1106 | } | |
| 1115 | var code_buffer = std.ArrayList(u8).init(gpa); | |
| 1116 | defer code_buffer.deinit(); | |
| 1117 | ||
| 1118 | const mod = self.base.options.module.?; | |
| 1119 | const atom_index = try self.createAtom(); | |
| 1120 | const sym = self.getAtom(atom_index).getSymbolPtr(self); | |
| 1121 | try self.setSymbolName(sym, name); | |
| 1122 | sym.section_number = @as(coff.SectionNumber, @enumFromInt(sect_id + 1)); | |
| 1107 | 1123 | |
| 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 | 1125 | .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, |
| 1110 | 1126 | }); |
| 1111 | 1127 | var code = switch (res) { |
| 1112 | 1128 | .ok => code_buffer.items, |
| 1113 | .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 | }, | |
| 1129 | .fail => |em| return .{ .fail = em }, | |
| 1119 | 1130 | }; |
| 1120 | 1131 | |
| 1121 | 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 | 1135 | atom.getSymbolPtr(self).value = try self.allocateAtom(atom_index, atom.size, required_alignment); |
| 1125 | 1136 | errdefer self.freeAtom(atom_index); |
| 1126 | 1137 | |
| 1127 | try unnamed_consts.append(gpa, atom_index); | |
| 1128 | ||
| 1129 | log.debug("allocated atom for {s} at 0x{x}", .{ sym_name, atom.getSymbol(self).value }); | |
| 1138 | log.debug("allocated atom for {s} at 0x{x}", .{ name, atom.getSymbol(self).value }); | |
| 1130 | 1139 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| 1131 | 1140 | |
| 1132 | 1141 | try self.writeAtom(atom_index, code); |
| 1133 | 1142 | |
| 1134 | return atom.getSymbolIndex().?; | |
| 1143 | return .{ .ok = atom_index }; | |
| 1135 | 1144 | } |
| 1136 | 1145 | |
| 1137 | 1146 | pub fn updateDecl( |
| ... | ... | @@ -1727,6 +1736,63 @@ pub fn getDeclVAddr(self: *Coff, decl_index: Module.Decl.Index, reloc_info: link |
| 1727 | 1736 | return 0; |
| 1728 | 1737 | } |
| 1729 | 1738 | |
| 1739 | pub 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 | ||
| 1776 | pub 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 | ||
| 1730 | 1796 | pub fn getGlobalSymbol(self: *Coff, name: []const u8, lib_name_name: ?[]const u8) !u32 { |
| 1731 | 1797 | const gop = try self.getOrPutGlobalPtr(name); |
| 1732 | 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 | 155 | /// value assigned to label `foo` is an unnamed constant belonging/associated |
| 156 | 156 | /// with `Decl` `main`, and lives as long as that `Decl`. |
| 157 | 157 | unnamed_consts: UnnamedConstTable = .{}, |
| 158 | anon_decls: AnonDeclTable = .{}, | |
| 158 | 159 | |
| 159 | 160 | comdat_groups: std.ArrayListUnmanaged(ComdatGroup) = .{}, |
| 160 | 161 | comdat_groups_owners: std.ArrayListUnmanaged(ComdatGroupOwner) = .{}, |
| 161 | 162 | comdat_groups_table: std.AutoHashMapUnmanaged(u32, ComdatGroupOwner.Index) = .{}, |
| 162 | 163 | |
| 163 | 164 | const UnnamedConstTable = std.AutoHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Symbol.Index)); |
| 165 | const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Symbol.Index); | |
| 164 | 166 | const LazySymbolTable = std.AutoArrayHashMapUnmanaged(Module.Decl.OptionalIndex, LazySymbolMetadata); |
| 165 | 167 | |
| 166 | 168 | /// When allocating, the ideal_capacity is calculated by |
| ... | ... | @@ -321,6 +323,7 @@ pub fn deinit(self: *Elf) void { |
| 321 | 323 | } |
| 322 | 324 | self.unnamed_consts.deinit(gpa); |
| 323 | 325 | } |
| 326 | self.anon_decls.deinit(gpa); | |
| 324 | 327 | |
| 325 | 328 | if (self.dwarf) |*dw| { |
| 326 | 329 | dw.deinit(); |
| ... | ... | @@ -334,7 +337,6 @@ pub fn deinit(self: *Elf) void { |
| 334 | 337 | |
| 335 | 338 | pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link.File.RelocInfo) !u64 { |
| 336 | 339 | assert(self.llvm_object == null); |
| 337 | ||
| 338 | 340 | const this_sym_index = try self.getOrCreateMetadataForDecl(decl_index); |
| 339 | 341 | const this_sym = self.symbol(this_sym_index); |
| 340 | 342 | const vaddr = this_sym.value; |
| ... | ... | @@ -344,7 +346,57 @@ pub fn getDeclVAddr(self: *Elf, decl_index: Module.Decl.Index, reloc_info: link. |
| 344 | 346 | .r_info = (@as(u64, @intCast(this_sym.esym_index)) << 32) | elf.R_X86_64_64, |
| 345 | 347 | .r_addend = reloc_info.addend, |
| 346 | 348 | }); |
| 349 | return vaddr; | |
| 350 | } | |
| 347 | 351 | |
| 352 | pub 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 | ||
| 389 | pub 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 | 400 | return vaddr; |
| 349 | 401 | } |
| 350 | 402 | |
| ... | ... | @@ -3105,50 +3157,68 @@ fn updateLazySymbol(self: *Elf, sym: link.File.LazySymbol, symbol_index: Symbol. |
| 3105 | 3157 | |
| 3106 | 3158 | pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 { |
| 3107 | 3159 | const gpa = self.base.allocator; |
| 3108 | ||
| 3109 | var code_buffer = std.ArrayList(u8).init(gpa); | |
| 3110 | defer code_buffer.deinit(); | |
| 3111 | ||
| 3112 | 3160 | const mod = self.base.options.module.?; |
| 3113 | 3161 | const gop = try self.unnamed_consts.getOrPut(gpa, decl_index); |
| 3114 | 3162 | if (!gop.found_existing) { |
| 3115 | 3163 | gop.value_ptr.* = .{}; |
| 3116 | 3164 | } |
| 3117 | 3165 | const unnamed_consts = gop.value_ptr; |
| 3118 | ||
| 3119 | 3166 | const decl = mod.declPtr(decl_index); |
| 3120 | const name_str_index = blk: { | |
| 3121 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 3122 | const index = unnamed_consts.items.len; | |
| 3123 | const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); | |
| 3124 | defer gpa.free(name); | |
| 3125 | break :blk try self.strtab.insert(gpa, name); | |
| 3167 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); | |
| 3168 | const index = unnamed_consts.items.len; | |
| 3169 | const name = try std.fmt.allocPrint(gpa, "__unnamed_{s}_{d}", .{ decl_name, index }); | |
| 3170 | defer gpa.free(name); | |
| 3171 | const sym_index = switch (try self.lowerConst(name, typed_value, self.rodata_section_index.?, decl.srcLoc(mod))) { | |
| 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 | ||
| 3185 | const LowerConstResult = union(enum) { | |
| 3186 | ok: Symbol.Index, | |
| 3187 | fail: *Module.ErrorMsg, | |
| 3188 | }; | |
| 3189 | ||
| 3190 | fn 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(); | |
| 3127 | 3201 | |
| 3202 | const mod = self.base.options.module.?; | |
| 3128 | 3203 | const zig_module = self.file(self.zig_module_index.?).?.zig_module; |
| 3129 | 3204 | const sym_index = try zig_module.addAtom(self); |
| 3130 | 3205 | |
| 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 | 3207 | .none = {}, |
| 3133 | 3208 | }, .{ |
| 3134 | 3209 | .parent_atom_index = sym_index, |
| 3135 | 3210 | }); |
| 3136 | 3211 | const code = switch (res) { |
| 3137 | 3212 | .ok => code_buffer.items, |
| 3138 | .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 | }, | |
| 3213 | .fail => |em| return .{ .fail = em }, | |
| 3144 | 3214 | }; |
| 3145 | 3215 | |
| 3146 | const required_alignment = typed_value.ty.abiAlignment(mod); | |
| 3147 | const shdr_index = self.rodata_section_index.?; | |
| 3148 | const phdr_index = self.phdr_to_shdr_table.get(shdr_index).?; | |
| 3216 | const required_alignment = tv.ty.abiAlignment(mod); | |
| 3217 | const phdr_index = self.phdr_to_shdr_table.get(output_section_index).?; | |
| 3149 | 3218 | const local_sym = self.symbol(sym_index); |
| 3219 | const name_str_index = try self.strtab.insert(gpa, name); | |
| 3150 | 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 | 3222 | const local_esym = &zig_module.local_esyms.items[local_sym.esym_index]; |
| 3153 | 3223 | local_esym.st_name = name_str_index; |
| 3154 | 3224 | local_esym.st_info |= elf.STT_OBJECT; |
| ... | ... | @@ -3158,21 +3228,20 @@ pub fn lowerUnnamedConst(self: *Elf, typed_value: TypedValue, decl_index: Module |
| 3158 | 3228 | atom_ptr.name_offset = name_str_index; |
| 3159 | 3229 | atom_ptr.alignment = required_alignment; |
| 3160 | 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; | |
| 3162 | 3232 | |
| 3163 | 3233 | try atom_ptr.allocate(self); |
| 3234 | // TODO rename and re-audit this method | |
| 3164 | 3235 | errdefer self.freeDeclMetadata(sym_index); |
| 3165 | 3236 | |
| 3166 | 3237 | local_sym.value = atom_ptr.value; |
| 3167 | 3238 | local_esym.st_value = atom_ptr.value; |
| 3168 | 3239 | |
| 3169 | try unnamed_consts.append(gpa, atom_ptr.atom_index); | |
| 3170 | ||
| 3171 | 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 | 3242 | try self.base.file.?.pwriteAll(code, file_offset); |
| 3174 | 3243 | |
| 3175 | return sym_index; | |
| 3244 | return .{ .ok = sym_index }; | |
| 3176 | 3245 | } |
| 3177 | 3246 | |
| 3178 | 3247 | pub fn updateDeclExports( |
src/link/MachO.zig+98-24| ... | ... | @@ -109,6 +109,7 @@ atom_by_index_table: std.AutoHashMapUnmanaged(u32, Atom.Index) = .{}, |
| 109 | 109 | /// value assigned to label `foo` is an unnamed constant belonging/associated |
| 110 | 110 | /// with `Decl` `main`, and lives as long as that `Decl`. |
| 111 | 111 | unnamed_const_atoms: UnnamedConstTable = .{}, |
| 112 | anon_decls: AnonDeclTable = .{}, | |
| 112 | 113 | |
| 113 | 114 | /// A table of relocations indexed by the owning them `Atom`. |
| 114 | 115 | /// Note that once we refactor `Atom`'s lifetime and ownership rules, |
| ... | ... | @@ -1899,6 +1900,7 @@ pub fn deinit(self: *MachO) void { |
| 1899 | 1900 | atoms.deinit(gpa); |
| 1900 | 1901 | } |
| 1901 | 1902 | self.unnamed_const_atoms.deinit(gpa); |
| 1903 | self.anon_decls.deinit(gpa); | |
| 1902 | 1904 | |
| 1903 | 1905 | self.atom_by_index_table.deinit(gpa); |
| 1904 | 1906 | |
| ... | ... | @@ -2172,27 +2174,49 @@ pub fn updateFunc(self: *MachO, mod: *Module, func_index: InternPool.Index, air: |
| 2172 | 2174 | |
| 2173 | 2175 | pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Module.Decl.Index) !u32 { |
| 2174 | 2176 | const gpa = self.base.allocator; |
| 2175 | ||
| 2176 | var code_buffer = std.ArrayList(u8).init(gpa); | |
| 2177 | defer code_buffer.deinit(); | |
| 2178 | ||
| 2179 | 2177 | const mod = self.base.options.module.?; |
| 2180 | 2178 | const gop = try self.unnamed_const_atoms.getOrPut(gpa, decl_index); |
| 2181 | 2179 | if (!gop.found_existing) { |
| 2182 | 2180 | gop.value_ptr.* = .{}; |
| 2183 | 2181 | } |
| 2184 | 2182 | const unnamed_consts = gop.value_ptr; |
| 2185 | ||
| 2186 | 2183 | const decl = mod.declPtr(decl_index); |
| 2187 | 2184 | const decl_name = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 2188 | ||
| 2189 | const name_str_index = blk: { | |
| 2190 | const index = unnamed_consts.items.len; | |
| 2191 | const name = try std.fmt.allocPrint(gpa, "___unnamed_{s}_{d}", .{ decl_name, index }); | |
| 2192 | defer gpa.free(name); | |
| 2193 | break :blk try self.strtab.insert(gpa, name); | |
| 2185 | const index = unnamed_consts.items.len; | |
| 2186 | const name = try std.fmt.allocPrint(gpa, "___unnamed_{s}_{d}", .{ decl_name, index }); | |
| 2187 | defer gpa.free(name); | |
| 2188 | const atom_index = switch (try self.lowerConst(name, typed_value, self.data_const_section_index.?, decl.srcLoc(mod))) { | |
| 2189 | .ok => |atom_index| atom_index, | |
| 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 | ||
| 2202 | const LowerConstResult = union(enum) { | |
| 2203 | ok: Atom.Index, | |
| 2204 | fail: *Module.ErrorMsg, | |
| 2205 | }; | |
| 2206 | ||
| 2207 | fn 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.?; | |
| 2196 | 2220 | |
| 2197 | 2221 | log.debug("allocating symbol indexes for {s}", .{name}); |
| 2198 | 2222 | |
| ... | ... | @@ -2200,40 +2224,33 @@ pub fn lowerUnnamedConst(self: *MachO, typed_value: TypedValue, decl_index: Modu |
| 2200 | 2224 | const atom_index = try self.createAtom(sym_index, .{}); |
| 2201 | 2225 | try self.atom_by_index_table.putNoClobber(gpa, sym_index, atom_index); |
| 2202 | 2226 | |
| 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 | 2228 | .parent_atom_index = self.getAtom(atom_index).getSymbolIndex().?, |
| 2205 | 2229 | }); |
| 2206 | 2230 | var code = switch (res) { |
| 2207 | 2231 | .ok => code_buffer.items, |
| 2208 | .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 | }, | |
| 2232 | .fail => |em| return .{ .fail = em }, | |
| 2214 | 2233 | }; |
| 2215 | 2234 | |
| 2216 | const required_alignment = typed_value.ty.abiAlignment(mod); | |
| 2235 | const required_alignment = tv.ty.abiAlignment(mod); | |
| 2217 | 2236 | const atom = self.getAtomPtr(atom_index); |
| 2218 | 2237 | atom.size = code.len; |
| 2219 | 2238 | // TODO: work out logic for disambiguating functions from function pointers |
| 2220 | 2239 | // const sect_id = self.getDeclOutputSection(decl_index); |
| 2221 | const sect_id = self.data_const_section_index.?; | |
| 2222 | 2240 | const symbol = atom.getSymbolPtr(self); |
| 2241 | const name_str_index = try self.strtab.insert(gpa, name); | |
| 2223 | 2242 | symbol.n_strx = name_str_index; |
| 2224 | 2243 | symbol.n_type = macho.N_SECT; |
| 2225 | 2244 | symbol.n_sect = sect_id + 1; |
| 2226 | 2245 | symbol.n_value = try self.allocateAtom(atom_index, code.len, required_alignment); |
| 2227 | 2246 | errdefer self.freeAtom(atom_index); |
| 2228 | 2247 | |
| 2229 | try unnamed_consts.append(gpa, atom_index); | |
| 2230 | ||
| 2231 | 2248 | log.debug("allocated atom for {s} at 0x{x}", .{ name, symbol.n_value }); |
| 2232 | 2249 | log.debug(" (required alignment 0x{x})", .{required_alignment}); |
| 2233 | 2250 | |
| 2234 | 2251 | try self.writeAtom(atom_index, code); |
| 2235 | 2252 | |
| 2236 | return atom.getSymbolIndex().?; | |
| 2253 | return .{ .ok = atom_index }; | |
| 2237 | 2254 | } |
| 2238 | 2255 | |
| 2239 | 2256 | pub 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 | 2857 | return 0; |
| 2841 | 2858 | } |
| 2842 | 2859 | |
| 2860 | pub 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 | ||
| 2897 | pub 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 | ||
| 2843 | 2916 | fn populateMissingMetadata(self: *MachO) !void { |
| 2844 | 2917 | assert(self.mode == .incremental); |
| 2845 | 2918 | |
| ... | ... | @@ -5389,6 +5462,7 @@ const DeclMetadata = struct { |
| 5389 | 5462 | } |
| 5390 | 5463 | }; |
| 5391 | 5464 | |
| 5465 | const AnonDeclTable = std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index); | |
| 5392 | 5466 | const BindingTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Atom.Binding)); |
| 5393 | 5467 | const UnnamedConstTable = std.AutoArrayHashMapUnmanaged(Module.Decl.Index, std.ArrayListUnmanaged(Atom.Index)); |
| 5394 | 5468 | const RebaseTable = std.AutoArrayHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(u32)); |
src/link/Plan9.zig+90-1| ... | ... | @@ -82,6 +82,8 @@ unnamed_const_atoms: UnnamedConstTable = .{}, |
| 82 | 82 | |
| 83 | 83 | lazy_syms: LazySymbolTable = .{}, |
| 84 | 84 | |
| 85 | anon_decls: std.AutoHashMapUnmanaged(InternPool.Index, Atom.Index) = .{}, | |
| 86 | ||
| 85 | 87 | relocs: std.AutoHashMapUnmanaged(Atom.Index, std.ArrayListUnmanaged(Reloc)) = .{}, |
| 86 | 88 | hdr: aout.ExecHdr = undefined, |
| 87 | 89 | |
| ... | ... | @@ -166,6 +168,9 @@ pub const Atom = struct { |
| 166 | 168 | code_len: usize, |
| 167 | 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 | 174 | fn getCode(self: CodePtr, plan9: *const Plan9) []u8 { |
| 170 | 175 | const mod = plan9.base.options.module.?; |
| 171 | 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 | 613 | while (it_lazy.next()) |kv| { |
| 609 | 614 | lazy_atom_count += kv.value_ptr.numberOfAtoms(); |
| 610 | 615 | } |
| 616 | const anon_atom_count = self.anon_decls.count(); | |
| 611 | 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 | } |
| 614 | 620 | |
| 615 | 621 | pub 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 | 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 | 834 | // the lazy data symbols |
| 808 | 835 | var it_lazy = self.lazy_syms.iterator(); |
| 809 | 836 | while (it_lazy.next()) |kv| { |
| ... | ... | @@ -1196,6 +1223,11 @@ pub fn deinit(self: *Plan9) void { |
| 1196 | 1223 | while (itd.next()) |entry| { |
| 1197 | 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 | 1231 | self.data_decl_table.deinit(gpa); |
| 1200 | 1232 | self.syms.deinit(gpa); |
| 1201 | 1233 | self.got_index_free_list.deinit(gpa); |
| ... | ... | @@ -1418,6 +1450,63 @@ pub fn getDeclVAddr( |
| 1418 | 1450 | return undefined; |
| 1419 | 1451 | } |
| 1420 | 1452 | |
| 1453 | pub 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 | ||
| 1500 | pub 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 | ||
| 1421 | 1510 | pub fn addReloc(self: *Plan9, parent_index: Atom.Index, reloc: Reloc) !void { |
| 1422 | 1511 | const gop = try self.relocs.getOrPut(self.base.allocator, parent_index); |
| 1423 | 1512 | if (!gop.found_existing) { |
src/link/Wasm.zig+99-10| ... | ... | @@ -187,6 +187,9 @@ debug_pubtypes_atom: ?Atom.Index = null, |
| 187 | 187 | /// rather than by the linker. |
| 188 | 188 | synthetic_functions: std.ArrayListUnmanaged(Atom.Index) = .{}, |
| 189 | 189 | |
| 190 | /// Map for storing anonymous declarations. Each anonymous decl maps to its Atom's index. | |
| 191 | anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Atom.Index) = .{}, | |
| 192 | ||
| 190 | 193 | pub const Alignment = types.Alignment; |
| 191 | 194 | |
| 192 | 195 | pub const Segment = struct { |
| ... | ... | @@ -1291,6 +1294,7 @@ pub fn deinit(wasm: *Wasm) void { |
| 1291 | 1294 | } |
| 1292 | 1295 | |
| 1293 | 1296 | wasm.decls.deinit(gpa); |
| 1297 | wasm.anon_decls.deinit(gpa); | |
| 1294 | 1298 | wasm.atom_types.deinit(gpa); |
| 1295 | 1299 | wasm.symbols.deinit(gpa); |
| 1296 | 1300 | wasm.symbols_free_list.deinit(gpa); |
| ... | ... | @@ -1548,17 +1552,38 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In |
| 1548 | 1552 | assert(tv.ty.zigTypeTag(mod) != .Fn); // cannot create local symbols for functions |
| 1549 | 1553 | const decl = mod.declPtr(decl_index); |
| 1550 | 1554 | |
| 1551 | // Create and initialize a new local symbol and atom | |
| 1552 | const atom_index = try wasm.createAtom(); | |
| 1553 | 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 | 1557 | const local_index = parent_atom.locals.items.len; |
| 1556 | try parent_atom.locals.append(wasm.base.allocator, atom_index); | |
| 1557 | 1558 | const fqn = mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)); |
| 1558 | 1559 | const name = try std.fmt.allocPrintZ(wasm.base.allocator, "__unnamed_{s}_{d}", .{ |
| 1559 | 1560 | fqn, local_index, |
| 1560 | 1561 | }); |
| 1561 | 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 | ||
| 1577 | const LowerConstResult = union(enum) { | |
| 1578 | ok: Atom.Index, | |
| 1579 | fail: *Module.ErrorMsg, | |
| 1580 | }; | |
| 1581 | ||
| 1582 | fn 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 | 1587 | var value_bytes = std.ArrayList(u8).init(wasm.base.allocator); |
| 1563 | 1588 | defer value_bytes.deinit(); |
| 1564 | 1589 | |
| ... | ... | @@ -1576,7 +1601,7 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In |
| 1576 | 1601 | |
| 1577 | 1602 | const result = try codegen.generateSymbol( |
| 1578 | 1603 | &wasm.base, |
| 1579 | decl.srcLoc(mod), | |
| 1604 | src_loc, | |
| 1580 | 1605 | tv, |
| 1581 | 1606 | &value_bytes, |
| 1582 | 1607 | .none, |
| ... | ... | @@ -1588,17 +1613,15 @@ pub fn lowerUnnamedConst(wasm: *Wasm, tv: TypedValue, decl_index: Module.Decl.In |
| 1588 | 1613 | break :code switch (result) { |
| 1589 | 1614 | .ok => value_bytes.items, |
| 1590 | 1615 | .fail => |em| { |
| 1591 | decl.analysis = .codegen_failure; | |
| 1592 | try mod.failed_decls.put(mod.gpa, decl_index, em); | |
| 1593 | return error.CodegenFail; | |
| 1616 | return .{ .fail = em }; | |
| 1594 | 1617 | }, |
| 1595 | 1618 | }; |
| 1596 | 1619 | }; |
| 1597 | 1620 | |
| 1598 | 1621 | const atom = wasm.getAtomPtr(atom_index); |
| 1599 | atom.size = @as(u32, @intCast(code.len)); | |
| 1622 | atom.size = @intCast(code.len); | |
| 1600 | 1623 | try atom.code.appendSlice(wasm.base.allocator, code); |
| 1601 | return atom.sym_index; | |
| 1624 | return .{ .ok = atom_index }; | |
| 1602 | 1625 | } |
| 1603 | 1626 | |
| 1604 | 1627 | /// Returns the symbol index from a symbol of which its flag is set global, |
| ... | ... | @@ -1679,6 +1702,63 @@ pub fn getDeclVAddr( |
| 1679 | 1702 | return target_symbol_index; |
| 1680 | 1703 | } |
| 1681 | 1704 | |
| 1705 | pub 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 | ||
| 1726 | pub 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 | ||
| 1682 | 1762 | pub fn deleteDeclExport(wasm: *Wasm, decl_index: Module.Decl.Index) void { |
| 1683 | 1763 | if (wasm.llvm_object) |_| return; |
| 1684 | 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 | 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 | } | |
| 3445 | 3534 | |
| 3446 | 3535 | // also parse any backend-generated functions |
| 3447 | 3536 | for (wasm.synthetic_functions.items) |atom_index| { |
src/value.zig+6-3| ... | ... | @@ -1565,12 +1565,14 @@ pub const Value = struct { |
| 1565 | 1565 | } |
| 1566 | 1566 | |
| 1567 | 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 | 1570 | return switch (ptr.len) { |
| 1570 | .none => switch (mod.intern_pool.indexToKey(switch (ptr.addr) { | |
| 1571 | .none => switch (ip.indexToKey(switch (ptr.addr) { | |
| 1571 | 1572 | .decl => |decl| mod.declPtr(decl).ty.toIntern(), |
| 1572 | 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 | 1576 | else => unreachable, |
| 1575 | 1577 | })) { |
| 1576 | 1578 | .array_type => |array_type| array_type.len, |
| ... | ... | @@ -1602,6 +1604,7 @@ pub const Value = struct { |
| 1602 | 1604 | })).toValue(), |
| 1603 | 1605 | .ptr => |ptr| switch (ptr.addr) { |
| 1604 | 1606 | .decl => |decl| mod.declPtr(decl).val.maybeElemValue(mod, index), |
| 1607 | .anon_decl => |anon_decl| anon_decl.toValue().maybeElemValue(mod, index), | |
| 1605 | 1608 | .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod)) |
| 1606 | 1609 | .toValue().maybeElemValue(mod, index), |
| 1607 | 1610 | .int, .eu_payload => null, |