diff --git a/src/InternPool.zig b/src/InternPool.zig index d7c0e4861d589139683c273cbd396b3ce1ee35fb..14490c21dbb513c78db62b229f201c3956a2cfc7 100644 --- a/src/InternPool.zig +++ b/src/InternPool.zig @@ -1074,6 +1074,7 @@ pub const Key = union(enum) { decl: Module.Decl.Index, mut_decl: MutDecl, + anon_decl: Index, comptime_field: Index, int: Index, eu_payload: Index, @@ -1230,10 +1231,12 @@ pub const Key = union(enum) { asBytes(&x.decl) ++ asBytes(&x.runtime_index), ), - .int, .eu_payload, .opt_payload, .comptime_field => |int| Hash.hash( - seed2, - asBytes(&int), - ), + .anon_decl, + .int, + .eu_payload, + .opt_payload, + .comptime_field, + => |int| Hash.hash(seed2, asBytes(&int)), .elem, .field => |x| Hash.hash( seed2, @@ -1497,6 +1500,7 @@ pub const Key = union(enum) { return switch (a_info.addr) { .decl => |a_decl| a_decl == b_info.addr.decl, .mut_decl => |a_mut_decl| std.meta.eql(a_mut_decl, b_info.addr.mut_decl), + .anon_decl => |a_decl| a_decl == b_info.addr.anon_decl, .int => |a_int| a_int == b_info.addr.int, .eu_payload => |a_eu_payload| a_eu_payload == b_info.addr.eu_payload, .opt_payload => |a_opt_payload| a_opt_payload == b_info.addr.opt_payload, @@ -2123,6 +2127,7 @@ pub const Index = enum(u32) { simple_value: struct { data: SimpleValue }, ptr_decl: struct { data: *PtrDecl }, ptr_mut_decl: struct { data: *PtrMutDecl }, + ptr_anon_decl: struct { data: *PtrAnonDecl }, ptr_comptime_field: struct { data: *PtrComptimeField }, ptr_int: struct { data: *PtrBase }, ptr_eu_payload: struct { data: *PtrBase }, @@ -2572,6 +2577,9 @@ pub const Tag = enum(u8) { /// A pointer to a decl that can be mutated at comptime. /// data is extra index of `PtrMutDecl`, which contains the type and address. ptr_mut_decl, + /// A pointer to an anonymous decl. + /// data is extra index of `PtrAnonDecl`, which contains the type and decl value. + ptr_anon_decl, /// data is extra index of `PtrComptimeField`, which contains the pointer type and field value. ptr_comptime_field, /// A pointer with an integer value. @@ -2767,6 +2775,7 @@ pub const Tag = enum(u8) { .simple_value => unreachable, .ptr_decl => PtrDecl, .ptr_mut_decl => PtrMutDecl, + .ptr_anon_decl => PtrAnonDecl, .ptr_comptime_field => PtrComptimeField, .ptr_int => PtrBase, .ptr_eu_payload => PtrBase, @@ -3364,6 +3373,11 @@ pub const PtrDecl = struct { decl: Module.Decl.Index, }; +pub const PtrAnonDecl = struct { + ty: Index, + val: Index, +}; + pub const PtrMutDecl = struct { ty: Index, decl: Module.Decl.Index, @@ -3713,6 +3727,13 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { } }, } }; }, + .ptr_anon_decl => { + const info = ip.extraData(PtrAnonDecl, data); + return .{ .ptr = .{ + .ty = info.ty, + .addr = .{ .anon_decl = info.val }, + } }; + }, .ptr_comptime_field => { const info = ip.extraData(PtrComptimeField, data); return .{ .ptr = .{ @@ -3790,6 +3811,9 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key { .runtime_index = sub_info.runtime_index, } }; }, + .ptr_anon_decl => .{ + .anon_decl = ip.extraData(PtrAnonDecl, ptr_item.data).val, + }, .ptr_comptime_field => .{ .comptime_field = ip.extraData(PtrComptimeField, ptr_item.data).field_val, }, @@ -4542,6 +4566,13 @@ pub fn get(ip: *InternPool, gpa: Allocator, key: Key) Allocator.Error!Index { .runtime_index = mut_decl.runtime_index, }), }), + .anon_decl => |anon_decl| ip.items.appendAssumeCapacity(.{ + .tag = .ptr_anon_decl, + .data = try ip.addExtra(gpa, PtrAnonDecl{ + .ty = ptr.ty, + .val = anon_decl, + }), + }), .comptime_field => |field_val| { assert(field_val != .none); ip.items.appendAssumeCapacity(.{ @@ -7147,6 +7178,7 @@ fn dumpStatsFallible(ip: *const InternPool, arena: Allocator) anyerror!void { .simple_value => 0, .ptr_decl => @sizeOf(PtrDecl), .ptr_mut_decl => @sizeOf(PtrMutDecl), + .ptr_anon_decl => @sizeOf(PtrAnonDecl), .ptr_comptime_field => @sizeOf(PtrComptimeField), .ptr_int => @sizeOf(PtrBase), .ptr_eu_payload => @sizeOf(PtrBase), @@ -7276,6 +7308,7 @@ fn dumpAllFallible(ip: *const InternPool) anyerror!void { .runtime_value, .ptr_decl, .ptr_mut_decl, + .ptr_anon_decl, .ptr_comptime_field, .ptr_int, .ptr_eu_payload, @@ -7656,6 +7689,7 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index { inline .ptr_decl, .ptr_mut_decl, + .ptr_anon_decl, .ptr_comptime_field, .ptr_int, .ptr_eu_payload, @@ -7816,6 +7850,7 @@ pub fn getBackingAddrTag(ip: *const InternPool, val: Index) ?Key.Ptr.Addr.Tag { switch (ip.items.items(.tag)[base]) { .ptr_decl => return .decl, .ptr_mut_decl => return .mut_decl, + .ptr_anon_decl => return .anon_decl, .ptr_comptime_field => return .comptime_field, .ptr_int => return .int, inline .ptr_eu_payload, @@ -7991,6 +8026,7 @@ pub fn zigTypeTagOrPoison(ip: *const InternPool, index: Index) error{GenericPois .simple_value, .ptr_decl, .ptr_mut_decl, + .ptr_anon_decl, .ptr_comptime_field, .ptr_int, .ptr_eu_payload, diff --git a/src/Module.zig b/src/Module.zig index c4c2b634f704da392d7e0dfa17265ede76d6140f..8c4035cc9af78f99f4fd72079202436b53215a85 100644 --- a/src/Module.zig +++ b/src/Module.zig @@ -109,9 +109,6 @@ comptime_capture_scopes: std.AutoArrayHashMapUnmanaged(CaptureScope.Key, InternP /// This memory lives until the Module is destroyed. tmp_hack_arena: std.heap.ArenaAllocator, -/// This is currently only used for string literals. -memoized_decls: std.AutoHashMapUnmanaged(InternPool.Index, Decl.Index) = .{}, - /// We optimize memory usage for a compilation with no compile errors by storing the /// error messages and mapping outside of `Decl`. /// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator. @@ -2627,7 +2624,6 @@ pub fn deinit(mod: *Module) void { mod.global_assembly.deinit(gpa); mod.reference_table.deinit(gpa); - mod.memoized_decls.deinit(gpa); mod.intern_pool.deinit(gpa); mod.tmp_hack_arena.deinit(); @@ -5814,6 +5810,7 @@ pub fn markReferencedDeclsAlive(mod: *Module, val: Value) Allocator.Error!void { .ptr => |ptr| { switch (ptr.addr) { .decl => |decl| try mod.markDeclIndexAlive(decl), + .anon_decl => {}, .mut_decl => |mut_decl| try mod.markDeclIndexAlive(mut_decl.decl), .int, .comptime_field => {}, .eu_payload, .opt_payload => |parent| try mod.markReferencedDeclsAlive(parent.toValue()), diff --git a/src/Sema.zig b/src/Sema.zig index d626de4d18a0871333995328491ab3a9335063b1..c1187c0591bd3ad49dbb2d8c2a491a7a2f0d6a1b 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -1091,7 +1091,7 @@ fn analyzeBodyInner( .slice_sentinel => try sema.zirSliceSentinel(block, inst), .slice_start => try sema.zirSliceStart(block, inst), .slice_length => try sema.zirSliceLength(block, inst), - .str => try sema.zirStr(block, inst), + .str => try sema.zirStr(inst), .switch_block => try sema.zirSwitchBlock(block, inst, false), .switch_block_ref => try sema.zirSwitchBlock(block, inst, true), .type_info => try sema.zirTypeInfo(block, inst), @@ -2185,7 +2185,7 @@ fn resolveMaybeUndefValIntable(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Va if (val.ip_index == .none) return val; if (sema.mod.intern_pool.isVariable(val.toIntern())) return null; if (sema.mod.intern_pool.getBackingAddrTag(val.toIntern())) |addr| switch (addr) { - .decl, .mut_decl, .comptime_field => return null, + .decl, .anon_decl, .mut_decl, .comptime_field => return null, .int => {}, .eu_payload, .opt_payload, .elem, .field => unreachable, }; @@ -5501,38 +5501,40 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag); } -fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { - const tracy = trace(@src()); - defer tracy.end(); - +fn zirStr(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { const bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code); - return sema.addStrLit(block, bytes); + return sema.addStrLitNoAlias(bytes); } -fn addStrLit(sema: *Sema, block: *Block, bytes: []const u8) CompileError!Air.Inst.Ref { - const mod = sema.mod; - const gpa = sema.gpa; - // TODO: write something like getCoercedInts to avoid needing to dupe +fn addStrLit(sema: *Sema, bytes: []const u8) CompileError!Air.Inst.Ref { const duped_bytes = try sema.arena.dupe(u8, bytes); - const ty = try mod.arrayType(.{ + return addStrLitNoAlias(sema, duped_bytes); +} + +/// Safe to call when `bytes` does not point into `InternPool`. +fn addStrLitNoAlias(sema: *Sema, bytes: []const u8) CompileError!Air.Inst.Ref { + const mod = sema.mod; + const array_ty = try mod.arrayType(.{ .len = bytes.len, .sentinel = .zero_u8, .child = .u8_type, }); const val = try mod.intern(.{ .aggregate = .{ - .ty = ty.toIntern(), - .storage = .{ .bytes = duped_bytes }, + .ty = array_ty.toIntern(), + .storage = .{ .bytes = bytes }, } }); - const gop = try mod.memoized_decls.getOrPut(gpa, val); - if (!gop.found_existing) { - const new_decl_index = try mod.createAnonymousDecl(block, .{ - .ty = ty, - .val = val.toValue(), - }); - gop.value_ptr.* = new_decl_index; - try mod.finalizeAnonDecl(new_decl_index); - } - return sema.analyzeDeclRef(gop.value_ptr.*); + const ptr_ty = try sema.ptrType(.{ + .child = array_ty.toIntern(), + .flags = .{ + .alignment = .none, + .is_const = true, + .address_space = .generic, + }, + }); + return Air.internedToRef((try mod.intern(.{ .ptr = .{ + .ty = ptr_ty.toIntern(), + .addr = .{ .anon_decl = val }, + } }))); } 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 try sema.zirSaveErrRetIndex(block, inst); continue; }, - .str => try sema.zirStr(block, inst), + .str => try sema.zirStr(inst), .as_node => try sema.zirAsNode(block, inst), .field_val => try sema.zirFieldVal(block, inst), .@"unreachable" => { @@ -20170,7 +20172,7 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| { const err_name = sema.mod.intern_pool.indexToKey(val.toIntern()).err.name; - return sema.addStrLit(block, sema.mod.intern_pool.stringToSlice(err_name)); + return sema.addStrLit(sema.mod.intern_pool.stringToSlice(err_name)); } // 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 .EnumLiteral => { const val = try sema.resolveConstValue(block, .unneeded, operand, undefined); const tag_name = ip.indexToKey(val.toIntern()).enum_literal; - return sema.addStrLit(block, ip.stringToSlice(tag_name)); + return sema.addStrLit(ip.stringToSlice(tag_name)); }, .Enum => operand_ty, .Union => operand_ty.unionTagType(mod) orelse { @@ -20330,7 +20332,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air }; // TODO: write something like getCoercedInts to avoid needing to dupe const field_name = enum_ty.enumFieldName(field_index, mod); - return sema.addStrLit(block, ip.stringToSlice(field_name)); + return sema.addStrLit(ip.stringToSlice(field_name)); } try sema.requireRuntimeBlock(block, src, operand_src); if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) { @@ -29859,7 +29861,7 @@ fn beginComptimePtrMutation( const mod = sema.mod; const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr; switch (ptr.addr) { - .decl, .int => unreachable, // isComptimeMutablePtr has been checked already + .decl, .anon_decl, .int => unreachable, // isComptimeMutablePtr has been checked already .mut_decl => |mut_decl| { const decl = mod.declPtr(mut_decl.decl); return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl); @@ -30455,9 +30457,10 @@ fn beginComptimePtrLoad( maybe_array_ty: ?Type, ) ComptimePtrLoadError!ComptimePtrLoadKit { const mod = sema.mod; + const ip = &mod.intern_pool; const target = mod.getTarget(); - var deref: ComptimePtrLoadKit = switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) { + var deref: ComptimePtrLoadKit = switch (ip.indexToKey(ptr_val.toIntern())) { .ptr => |ptr| switch (ptr.addr) { .decl, .mut_decl => blk: { const decl_index = switch (ptr.addr) { @@ -30478,9 +30481,21 @@ fn beginComptimePtrLoad( .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null, }; }, + .anon_decl => |decl_val| blk: { + if (decl_val.toValue().getVariable(mod) != null) return error.RuntimeLoad; + const decl_ty = ip.typeOf(decl_val).toType(); + const decl_tv: TypedValue = .{ .ty = decl_ty, .val = decl_val.toValue() }; + const layout_defined = decl_ty.hasWellDefinedLayout(mod); + break :blk ComptimePtrLoadKit{ + .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null, + .pointee = decl_tv, + .is_mutable = false, + .ty_without_well_defined_layout = if (!layout_defined) decl_ty else null, + }; + }, .int => return error.RuntimeLoad, .eu_payload, .opt_payload => |container_ptr| blk: { - const container_ty = mod.intern_pool.typeOf(container_ptr).toType().childType(mod); + const container_ty = ip.typeOf(container_ptr).toType().childType(mod); const payload_ty = switch (ptr.addr) { .eu_payload => container_ty.errorUnionPayload(mod), .opt_payload => container_ty.optionalChild(mod), @@ -30502,13 +30517,13 @@ fn beginComptimePtrLoad( const payload_val = switch (tv.val.ip_index) { .none => tv.val.cast(Value.Payload.SubValue).?.data, .null_value => return sema.fail(block, src, "attempt to use null value", .{}), - else => switch (mod.intern_pool.indexToKey(tv.val.toIntern())) { + else => switch (ip.indexToKey(tv.val.toIntern())) { .error_union => |error_union| switch (error_union.val) { .err_name => |err_name| return sema.fail( block, src, "attempt to unwrap error: {}", - .{err_name.fmt(&mod.intern_pool)}, + .{err_name.fmt(ip)}, ), .payload => |payload| payload, }, @@ -30527,7 +30542,7 @@ fn beginComptimePtrLoad( break :blk deref; }, .comptime_field => |comptime_field| blk: { - const field_ty = mod.intern_pool.typeOf(comptime_field).toType(); + const field_ty = ip.typeOf(comptime_field).toType(); break :blk ComptimePtrLoadKit{ .parent = null, .pointee = .{ .ty = field_ty, .val = comptime_field.toValue() }, @@ -30536,15 +30551,15 @@ fn beginComptimePtrLoad( }; }, .elem => |elem_ptr| blk: { - const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod); + const elem_ty = ip.typeOf(elem_ptr.base).toType().elemType2(mod); var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.base.toValue(), null); // This code assumes that elem_ptrs have been "flattened" in order for direct dereference // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened" - switch (mod.intern_pool.indexToKey(elem_ptr.base)) { + switch (ip.indexToKey(elem_ptr.base)) { .ptr => |base_ptr| switch (base_ptr.addr) { - .elem => |base_elem| assert(!mod.intern_pool.typeOf(base_elem.base).toType().elemType2(mod).eql(elem_ty, mod)), + .elem => |base_elem| assert(!ip.typeOf(base_elem.base).toType().elemType2(mod).eql(elem_ty, mod)), else => {}, }, else => {}, @@ -30616,7 +30631,7 @@ fn beginComptimePtrLoad( }, .field => |field_ptr| blk: { const field_index: u32 = @intCast(field_ptr.index); - const container_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod); + const container_ty = ip.typeOf(field_ptr.base).toType().childType(mod); var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.base.toValue(), container_ty); if (container_ty.hasWellDefinedLayout(mod)) { @@ -30655,7 +30670,7 @@ fn beginComptimePtrLoad( }, Value.slice_len_index => TypedValue{ .ty = Type.usize, - .val = mod.intern_pool.indexToKey(try tv.val.intern(tv.ty, mod)).ptr.len.toValue(), + .val = ip.indexToKey(try tv.val.intern(tv.ty, mod)).ptr.len.toValue(), }, else => unreachable, }; @@ -34529,7 +34544,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value { else => (try sema.resolveLazyValue(ptr.len.toValue())).toIntern(), }; switch (ptr.addr) { - .decl, .mut_decl => return if (resolved_len == ptr.len) + .decl, .mut_decl, .anon_decl => return if (resolved_len == ptr.len) val else (try mod.intern(.{ .ptr = .{ @@ -34537,6 +34552,7 @@ fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value { .addr = switch (ptr.addr) { .decl => |decl| .{ .decl = decl }, .mut_decl => |mut_decl| .{ .mut_decl = mut_decl }, + .anon_decl => |anon_decl| .{ .anon_decl = anon_decl }, else => unreachable, }, .len = resolved_len, @@ -36568,6 +36584,7 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value { .runtime_value, .simple_value, .ptr_decl, + .ptr_anon_decl, .ptr_mut_decl, .ptr_comptime_field, .ptr_int, diff --git a/src/TypedValue.zig b/src/TypedValue.zig index cef22543a36be16504dd347a6181bf5022eb92c8..3d77d6b8a06b48e84300e95888425309bb960021 100644 --- a/src/TypedValue.zig +++ b/src/TypedValue.zig @@ -321,6 +321,15 @@ pub fn print( .val = decl.val, }, writer, level - 1, mod); }, + .anon_decl => |decl_val| { + if (level == 0) return writer.print("(anon decl '{d}')", .{ + @intFromEnum(decl_val), + }); + return print(.{ + .ty = ip.typeOf(decl_val).toType(), + .val = decl_val.toValue(), + }, writer, level - 1, mod); + }, .mut_decl => |mut_decl| { const decl = mod.declPtr(mut_decl.decl); if (level == 0) return writer.print("(mut decl '{}')", .{decl.name.fmt(ip)}); diff --git a/src/arch/wasm/CodeGen.zig b/src/arch/wasm/CodeGen.zig index 3d3054c61807e8fac89f12568977748f4c8a9396..92a292116ea32485a70e380e00791edfdadcad2c 100644 --- a/src/arch/wasm/CodeGen.zig +++ b/src/arch/wasm/CodeGen.zig @@ -3075,6 +3075,7 @@ fn lowerParentPtr(func: *CodeGen, ptr_val: Value, offset: u32) InnerError!WValue .decl => |decl_index| { return func.lowerParentPtrDecl(ptr_val, decl_index, offset); }, + .anon_decl => @panic("TODO"), .mut_decl => |mut_decl| { const decl_index = mut_decl.decl; return func.lowerParentPtrDecl(ptr_val, decl_index, offset); diff --git a/src/codegen.zig b/src/codegen.zig index 738281cf55208d906566d8c75ab266467bda6c36..ecbc05b1cc1439d44178709c8fe13793b5187b59 100644 --- a/src/codegen.zig +++ b/src/codegen.zig @@ -655,6 +655,7 @@ fn lowerParentPtr( debug_output, reloc_info, ), + .anon_decl => @panic("TODO"), .int => |int| try generateSymbol(bin_file, src_loc, .{ .ty = Type.usize, .val = int.toValue(), diff --git a/src/codegen/c.zig b/src/codegen/c.zig index b627d952e5402e92620422bc094cdc908b396083..a16096fa18ea1569e96c19b0d284b19d4175df03 100644 --- a/src/codegen/c.zig +++ b/src/codegen/c.zig @@ -604,6 +604,7 @@ pub const DeclGen = struct { }, location, ), + .anon_decl => @panic("TODO"), .int => |int| { try writer.writeByte('('); try dg.renderCType(writer, ptr_cty); @@ -1155,6 +1156,7 @@ pub const DeclGen = struct { }, ptr_location, ), + .anon_decl => @panic("TODO"), .int => |int| { try writer.writeAll("(("); try dg.renderType(writer, ptr_ty); diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index fa6282a71b79db5445e31247b8553ec0fc92fcef..b7943dd4aafe477a0e242d4d0f7c79425a078d3c 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -810,6 +810,8 @@ pub const Object = struct { /// * it works for functions not all globals. /// Therefore, this table keeps track of the mapping. decl_map: std.AutoHashMapUnmanaged(Module.Decl.Index, Builder.Global.Index), + /// Same deal as `decl_map` but for anonymous declarations, which are always global constants. + anon_decl_map: std.AutoHashMapUnmanaged(InternPool.Index, Builder.Global.Index), /// Serves the same purpose as `decl_map` but only used for the `is_named_enum_value` instruction. named_enum_map: std.AutoHashMapUnmanaged(Module.Decl.Index, Builder.Function.Index), /// Maps Zig types to LLVM types. The table memory is backed by the GPA of @@ -993,6 +995,7 @@ pub const Object = struct { .target_data = target_data, .target = options.target, .decl_map = .{}, + .anon_decl_map = .{}, .named_enum_map = .{}, .type_map = .{}, .di_type_map = .{}, @@ -1011,6 +1014,7 @@ pub const Object = struct { self.target_machine.dispose(); } self.decl_map.deinit(gpa); + self.anon_decl_map.deinit(gpa); self.named_enum_map.deinit(gpa); self.type_map.deinit(gpa); self.extern_collisions.deinit(gpa); @@ -3038,6 +3042,31 @@ pub const Object = struct { } } + fn resolveGlobalAnonDecl( + o: *Object, + decl_val: InternPool.Index, + llvm_addr_space: Builder.AddrSpace, + ) Error!Builder.Variable.Index { + const gop = try o.anon_decl_map.getOrPut(o.gpa, decl_val); + if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.variable; + errdefer assert(o.anon_decl_map.remove(decl_val)); + + const mod = o.module; + const decl_ty = mod.intern_pool.typeOf(decl_val); + + const variable_index = try o.builder.addVariable( + try o.builder.fmt("__anon_{d}", .{@intFromEnum(decl_val)}), + try o.lowerType(decl_ty.toType()), + llvm_addr_space, + ); + gop.value_ptr.* = variable_index.ptrConst(&o.builder).global; + + try variable_index.setInitializer(try o.lowerValue(decl_val), &o.builder); + variable_index.setLinkage(.internal, &o.builder); + variable_index.setUnnamedAddr(.unnamed_addr, &o.builder); + return variable_index; + } + fn resolveGlobalDecl( o: *Object, decl_index: Module.Decl.Index, @@ -3764,6 +3793,7 @@ pub const Object = struct { const ptr_val = switch (ptr.addr) { .decl => |decl| try o.lowerDeclRefValue(ptr_ty, decl), .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_ty, mut_decl.decl), + .anon_decl => |anon_decl| try o.lowerAnonDeclRef(ptr_ty, anon_decl), .int => |int| try o.lowerIntAsPtr(int), .eu_payload, .opt_payload, @@ -4216,10 +4246,12 @@ pub const Object = struct { return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint); } - const ParentPtr = struct { - ty: Type, - llvm_ptr: Builder.Value, - }; + fn lowerParentPtrAnonDecl(o: *Object, decl_val: InternPool.Index) Error!Builder.Constant { + const mod = o.module; + const decl_ty = mod.intern_pool.typeOf(decl_val).toType(); + const ptr_ty = try mod.singleMutPtrType(decl_ty); + return o.lowerAnonDeclRef(ptr_ty, decl_val); + } fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant { const mod = o.module; @@ -4229,13 +4261,14 @@ pub const Object = struct { return o.lowerDeclRefValue(ptr_ty, decl_index); } - fn lowerParentPtr(o: *Object, ptr_val: Value) Allocator.Error!Builder.Constant { + fn lowerParentPtr(o: *Object, ptr_val: Value) Error!Builder.Constant { const mod = o.module; const ip = &mod.intern_pool; const ptr = ip.indexToKey(ptr_val.toIntern()).ptr; return switch (ptr.addr) { - .decl => |decl| o.lowerParentPtrDecl(decl), - .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl), + .decl => |decl| try o.lowerParentPtrDecl(decl), + .mut_decl => |mut_decl| try o.lowerParentPtrDecl(mut_decl.decl), + .anon_decl => |anon_decl| try o.lowerParentPtrAnonDecl(anon_decl), .int => |int| try o.lowerIntAsPtr(int), .eu_payload => |eu_ptr| { const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue()); @@ -4349,6 +4382,49 @@ pub const Object = struct { }; } + /// This logic is very similar to `lowerDeclRefValue` but for anonymous declarations. + /// Maybe the logic could be unified. + fn lowerAnonDeclRef( + o: *Object, + ptr_ty: Type, + decl_val: InternPool.Index, + ) Error!Builder.Constant { + const mod = o.module; + const ip = &mod.intern_pool; + const decl_ty = ip.typeOf(decl_val).toType(); + const target = mod.getTarget(); + + if (decl_val.toValue().getFunction(mod)) |func| { + _ = func; + @panic("TODO"); + } else if (decl_val.toValue().getExternFunc(mod)) |func| { + _ = func; + @panic("TODO"); + } + + const is_fn_body = decl_ty.zigTypeTag(mod) == .Fn; + if ((!is_fn_body and !decl_ty.hasRuntimeBits(mod)) or + (is_fn_body and mod.typeToFunc(decl_ty).?.is_generic)) return o.lowerPtrToVoid(ptr_ty); + + if (is_fn_body) + @panic("TODO"); + + const addr_space = target_util.defaultAddressSpace(target, .global_constant); + const llvm_addr_space = toLlvmAddressSpace(addr_space, target); + const llvm_global = (try o.resolveGlobalAnonDecl(decl_val, llvm_addr_space)).ptrConst(&o.builder).global; + + const llvm_val = try o.builder.convConst( + .unneeded, + llvm_global.toConst(), + try o.builder.ptrType(llvm_addr_space), + ); + + return o.builder.convConst(if (ptr_ty.isAbiInt(mod)) switch (ptr_ty.intInfo(mod).signedness) { + .signed => .signed, + .unsigned => .unsigned, + } else .unneeded, llvm_val, try o.lowerType(ptr_ty)); + } + fn lowerDeclRefValue(o: *Object, ty: Type, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant { const mod = o.module; diff --git a/src/codegen/spirv.zig b/src/codegen/spirv.zig index 016604e1f66ab9288d8a8d3cd7b3ecd35e163fae..a4d3ec7f461f2d524a789a763c7d7e38bed63ea3 100644 --- a/src/codegen/spirv.zig +++ b/src/codegen/spirv.zig @@ -818,6 +818,7 @@ pub const DeclGen = struct { const mod = self.module; switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) { .decl => |decl| return try self.constructDeclRef(ptr_ty, decl), + .anon_decl => @panic("TODO"), .mut_decl => |decl_mut| return try self.constructDeclRef(ptr_ty, decl_mut.decl), .int => |int| { const ptr_id = self.spv.allocId(); diff --git a/src/value.zig b/src/value.zig index d37e039abf101f0ee313a27f9ee65be1e80306fa..2c4a88da17d145b6493ada0edfa04d9aff739b62 100644 --- a/src/value.zig +++ b/src/value.zig @@ -1565,12 +1565,14 @@ pub const Value = struct { } pub fn sliceLen(val: Value, mod: *Module) u64 { - const ptr = mod.intern_pool.indexToKey(val.toIntern()).ptr; + const ip = &mod.intern_pool; + const ptr = ip.indexToKey(val.toIntern()).ptr; return switch (ptr.len) { - .none => switch (mod.intern_pool.indexToKey(switch (ptr.addr) { + .none => switch (ip.indexToKey(switch (ptr.addr) { .decl => |decl| mod.declPtr(decl).ty.toIntern(), .mut_decl => |mut_decl| mod.declPtr(mut_decl.decl).ty.toIntern(), - .comptime_field => |comptime_field| mod.intern_pool.typeOf(comptime_field), + .anon_decl => |anon_decl| ip.typeOf(anon_decl), + .comptime_field => |comptime_field| ip.typeOf(comptime_field), else => unreachable, })) { .array_type => |array_type| array_type.len, @@ -1602,6 +1604,7 @@ pub const Value = struct { })).toValue(), .ptr => |ptr| switch (ptr.addr) { .decl => |decl| mod.declPtr(decl).val.maybeElemValue(mod, index), + .anon_decl => |anon_decl| anon_decl.toValue().maybeElemValue(mod, index), .mut_decl => |mut_decl| (try mod.declPtr(mut_decl.decl).internValue(mod)) .toValue().maybeElemValue(mod, index), .int, .eu_payload => null,