enum Metadata [src]

Fields

none = 0
empty_tuple = 1
_

Members

Source

pub const Metadata = enum(u32) { none = 0, empty_tuple = 1, _, const first_forward_reference = 1 << 29; const first_local_metadata = 1 << 30; pub const Tag = enum(u6) { none, file, compile_unit, @"compile_unit optimized", subprogram, @"subprogram local", @"subprogram definition", @"subprogram local definition", @"subprogram optimized", @"subprogram optimized local", @"subprogram optimized definition", @"subprogram optimized local definition", lexical_block, location, basic_bool_type, basic_unsigned_type, basic_signed_type, basic_float_type, composite_struct_type, composite_union_type, composite_enumeration_type, composite_array_type, composite_vector_type, derived_pointer_type, derived_member_type, subroutine_type, enumerator_unsigned, enumerator_signed_positive, enumerator_signed_negative, subrange, tuple, str_tuple, module_flag, expression, local_var, parameter, global_var, @"global_var local", global_var_expression, constant, pub fn isInline(tag: Tag) bool { return switch (tag) { .none, .expression, .constant, => true, .file, .compile_unit, .@"compile_unit optimized", .subprogram, .@"subprogram local", .@"subprogram definition", .@"subprogram local definition", .@"subprogram optimized", .@"subprogram optimized local", .@"subprogram optimized definition", .@"subprogram optimized local definition", .lexical_block, .location, .basic_bool_type, .basic_unsigned_type, .basic_signed_type, .basic_float_type, .composite_struct_type, .composite_union_type, .composite_enumeration_type, .composite_array_type, .composite_vector_type, .derived_pointer_type, .derived_member_type, .subroutine_type, .enumerator_unsigned, .enumerator_signed_positive, .enumerator_signed_negative, .subrange, .tuple, .str_tuple, .module_flag, .local_var, .parameter, .global_var, .@"global_var local", .global_var_expression, => false, }; } }; pub fn isInline(self: Metadata, builder: *const Builder) bool { return builder.metadata_items.items(.tag)[@intFromEnum(self)].isInline(); } pub fn unwrap(self: Metadata, builder: *const Builder) Metadata { var metadata = self; while (@intFromEnum(metadata) >= Metadata.first_forward_reference and @intFromEnum(metadata) < Metadata.first_local_metadata) { const index = @intFromEnum(metadata) - Metadata.first_forward_reference; metadata = builder.metadata_forward_references.items[index]; assert(metadata != .none); } return metadata; } pub const Item = struct { tag: Tag, data: ExtraIndex, const ExtraIndex = u32; }; pub const DIFlags = packed struct(u32) { Visibility: enum(u2) { Zero, Private, Protected, Public } = .Zero, FwdDecl: bool = false, AppleBlock: bool = false, ReservedBit4: u1 = 0, Virtual: bool = false, Artificial: bool = false, Explicit: bool = false, Prototyped: bool = false, ObjcClassComplete: bool = false, ObjectPointer: bool = false, Vector: bool = false, StaticMember: bool = false, LValueReference: bool = false, RValueReference: bool = false, ExportSymbols: bool = false, Inheritance: enum(u2) { Zero, SingleInheritance, MultipleInheritance, VirtualInheritance, } = .Zero, IntroducedVirtual: bool = false, BitField: bool = false, NoReturn: bool = false, ReservedBit21: u1 = 0, TypePassbyValue: bool = false, TypePassbyReference: bool = false, EnumClass: bool = false, Thunk: bool = false, NonTrivial: bool = false, BigEndian: bool = false, LittleEndian: bool = false, AllCallsDescribed: bool = false, Unused: u2 = 0, pub fn format( self: DIFlags, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype, ) @TypeOf(writer).Error!void { var need_pipe = false; inline for (@typeInfo(DIFlags).@"struct".fields) |field| { switch (@typeInfo(field.type)) { .bool => if (@field(self, field.name)) { if (need_pipe) try writer.writeAll(" | ") else need_pipe = true; try writer.print("DIFlag{s}", .{field.name}); }, .@"enum" => if (@field(self, field.name) != .Zero) { if (need_pipe) try writer.writeAll(" | ") else need_pipe = true; try writer.print("DIFlag{s}", .{@tagName(@field(self, field.name))}); }, .int => assert(@field(self, field.name) == 0), else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)), } } if (!need_pipe) try writer.writeByte('0'); } }; pub const File = struct { filename: MetadataString, directory: MetadataString, }; pub const CompileUnit = struct { pub const Options = struct { optimized: bool, }; file: Metadata, producer: MetadataString, enums: Metadata, globals: Metadata, }; pub const Subprogram = struct { pub const Options = struct { di_flags: DIFlags, sp_flags: DISPFlags, }; pub const DISPFlags = packed struct(u32) { Virtuality: enum(u2) { Zero, Virtual, PureVirtual } = .Zero, LocalToUnit: bool = false, Definition: bool = false, Optimized: bool = false, Pure: bool = false, Elemental: bool = false, Recursive: bool = false, MainSubprogram: bool = false, Deleted: bool = false, ReservedBit10: u1 = 0, ObjCDirect: bool = false, Unused: u20 = 0, pub fn format( self: DISPFlags, comptime _: []const u8, _: std.fmt.FormatOptions, writer: anytype, ) @TypeOf(writer).Error!void { var need_pipe = false; inline for (@typeInfo(DISPFlags).@"struct".fields) |field| { switch (@typeInfo(field.type)) { .bool => if (@field(self, field.name)) { if (need_pipe) try writer.writeAll(" | ") else need_pipe = true; try writer.print("DISPFlag{s}", .{field.name}); }, .@"enum" => if (@field(self, field.name) != .Zero) { if (need_pipe) try writer.writeAll(" | ") else need_pipe = true; try writer.print("DISPFlag{s}", .{@tagName(@field(self, field.name))}); }, .int => assert(@field(self, field.name) == 0), else => @compileError("bad field type: " ++ field.name ++ ": " ++ @typeName(field.type)), } } if (!need_pipe) try writer.writeByte('0'); } }; file: Metadata, name: MetadataString, linkage_name: MetadataString, line: u32, scope_line: u32, ty: Metadata, di_flags: DIFlags, compile_unit: Metadata, }; pub const LexicalBlock = struct { scope: Metadata, file: Metadata, line: u32, column: u32, }; pub const Location = struct { line: u32, column: u32, scope: Metadata, inlined_at: Metadata, }; pub const BasicType = struct { name: MetadataString, size_in_bits_lo: u32, size_in_bits_hi: u32, pub fn bitSize(self: BasicType) u64 { return @as(u64, self.size_in_bits_hi) << 32 | self.size_in_bits_lo; } }; pub const CompositeType = struct { name: MetadataString, file: Metadata, scope: Metadata, line: u32, underlying_type: Metadata, size_in_bits_lo: u32, size_in_bits_hi: u32, align_in_bits_lo: u32, align_in_bits_hi: u32, fields_tuple: Metadata, pub fn bitSize(self: CompositeType) u64 { return @as(u64, self.size_in_bits_hi) << 32 | self.size_in_bits_lo; } pub fn bitAlign(self: CompositeType) u64 { return @as(u64, self.align_in_bits_hi) << 32 | self.align_in_bits_lo; } }; pub const DerivedType = struct { name: MetadataString, file: Metadata, scope: Metadata, line: u32, underlying_type: Metadata, size_in_bits_lo: u32, size_in_bits_hi: u32, align_in_bits_lo: u32, align_in_bits_hi: u32, offset_in_bits_lo: u32, offset_in_bits_hi: u32, pub fn bitSize(self: DerivedType) u64 { return @as(u64, self.size_in_bits_hi) << 32 | self.size_in_bits_lo; } pub fn bitAlign(self: DerivedType) u64 { return @as(u64, self.align_in_bits_hi) << 32 | self.align_in_bits_lo; } pub fn bitOffset(self: DerivedType) u64 { return @as(u64, self.offset_in_bits_hi) << 32 | self.offset_in_bits_lo; } }; pub const SubroutineType = struct { types_tuple: Metadata, }; pub const Enumerator = struct { name: MetadataString, bit_width: u32, limbs_index: u32, limbs_len: u32, }; pub const Subrange = struct { lower_bound: Metadata, count: Metadata, }; pub const Expression = struct { elements_len: u32, // elements: [elements_len]u32 }; pub const Tuple = struct { elements_len: u32, // elements: [elements_len]Metadata }; pub const StrTuple = struct { str: MetadataString, elements_len: u32, // elements: [elements_len]Metadata }; pub const ModuleFlag = struct { behavior: Metadata, name: MetadataString, constant: Metadata, }; pub const LocalVar = struct { name: MetadataString, file: Metadata, scope: Metadata, line: u32, ty: Metadata, }; pub const Parameter = struct { name: MetadataString, file: Metadata, scope: Metadata, line: u32, ty: Metadata, arg_no: u32, }; pub const GlobalVar = struct { pub const Options = struct { local: bool, }; name: MetadataString, linkage_name: MetadataString, file: Metadata, scope: Metadata, line: u32, ty: Metadata, variable: Variable.Index, }; pub const GlobalVarExpression = struct { variable: Metadata, expression: Metadata, }; pub fn toValue(self: Metadata) Value { return @enumFromInt(Value.first_metadata + @intFromEnum(self)); } const Formatter = struct { builder: *Builder, need_comma: bool, map: std.AutoArrayHashMapUnmanaged(union(enum) { metadata: Metadata, debug_location: DebugLocation.Location, }, void) = .{}, const FormatData = struct { formatter: *Formatter, prefix: []const u8 = "", node: Node, const Node = union(enum) { none, @"inline": Metadata, index: u32, local_value: ValueData, local_metadata: ValueData, local_inline: Metadata, local_index: u32, string: MetadataString, bool: bool, u32: u32, u64: u64, di_flags: DIFlags, sp_flags: Subprogram.DISPFlags, raw: []const u8, const ValueData = struct { value: Value, function: Function.Index, }; }; }; fn format( data: FormatData, comptime fmt_str: []const u8, fmt_opts: std.fmt.FormatOptions, writer: anytype, ) @TypeOf(writer).Error!void { if (data.node == .none) return; const is_specialized = fmt_str.len > 0 and fmt_str[0] == 'S'; const recurse_fmt_str = if (is_specialized) fmt_str[1..] else fmt_str; if (data.formatter.need_comma) try writer.writeAll(", "); defer data.formatter.need_comma = true; try writer.writeAll(data.prefix); const builder = data.formatter.builder; switch (data.node) { .none => unreachable, .@"inline" => |node| { const needed_comma = data.formatter.need_comma; defer data.formatter.need_comma = needed_comma; data.formatter.need_comma = false; const item = builder.metadata_items.get(@intFromEnum(node)); switch (item.tag) { .expression => { var extra = builder.metadataExtraDataTrail(Expression, item.data); const elements = extra.trail.next(extra.data.elements_len, u32, builder); try writer.writeAll("!DIExpression("); for (elements) |element| try format(.{ .formatter = data.formatter, .node = .{ .u64 = element }, }, "%", fmt_opts, writer); try writer.writeByte(')'); }, .constant => try Constant.format(.{ .constant = @enumFromInt(item.data), .builder = builder, }, recurse_fmt_str, fmt_opts, writer), else => unreachable, } }, .index => |node| try writer.print("!{d}", .{node}), inline .local_value, .local_metadata => |node, tag| try Value.format(.{ .value = node.value, .function = node.function, .builder = builder, }, switch (tag) { .local_value => recurse_fmt_str, .local_metadata => "%", else => unreachable, }, fmt_opts, writer), inline .local_inline, .local_index => |node, tag| { if (comptime std.mem.eql(u8, recurse_fmt_str, "%")) try writer.print("{%} ", .{Type.metadata.fmt(builder)}); try format(.{ .formatter = data.formatter, .node = @unionInit(FormatData.Node, @tagName(tag)["local_".len..], node), }, "%", fmt_opts, writer); }, .string => |node| try writer.print((if (is_specialized) "" else "!") ++ "{}", .{ node.fmt(builder), }), inline .bool, .u32, .u64, .di_flags, .sp_flags, => |node| try writer.print("{}", .{node}), .raw => |node| try writer.writeAll(node), } } inline fn fmt(formatter: *Formatter, prefix: []const u8, node: anytype) switch (@TypeOf(node)) { Metadata => Allocator.Error, else => error{}, }!std.fmt.Formatter(format) { const Node = @TypeOf(node); const MaybeNode = switch (@typeInfo(Node)) { .optional => Node, .null => ?noreturn, else => ?Node, }; const Some = @typeInfo(MaybeNode).optional.child; return .{ .data = .{ .formatter = formatter, .prefix = prefix, .node = if (@as(MaybeNode, node)) |some| switch (@typeInfo(Some)) { .@"enum" => |enum_info| switch (Some) { Metadata => switch (some) { .none => .none, else => try formatter.refUnwrapped(some.unwrap(formatter.builder)), }, MetadataString => .{ .string = some }, else => if (enum_info.is_exhaustive) .{ .raw = @tagName(some) } else @compileError("unknown type to format: " ++ @typeName(Node)), }, .enum_literal => .{ .raw = @tagName(some) }, .bool => .{ .bool = some }, .@"struct" => switch (Some) { DIFlags => .{ .di_flags = some }, Subprogram.DISPFlags => .{ .sp_flags = some }, else => @compileError("unknown type to format: " ++ @typeName(Node)), }, .int, .comptime_int => .{ .u64 = some }, .pointer => .{ .raw = some }, else => @compileError("unknown type to format: " ++ @typeName(Node)), } else switch (@typeInfo(Node)) { .optional, .null => .none, else => unreachable, }, } }; } inline fn fmtLocal( formatter: *Formatter, prefix: []const u8, value: Value, function: Function.Index, ) Allocator.Error!std.fmt.Formatter(format) { return .{ .data = .{ .formatter = formatter, .prefix = prefix, .node = switch (value.unwrap()) { .instruction, .constant => .{ .local_value = .{ .value = value, .function = function, } }, .metadata => |metadata| if (value == .none) .none else node: { const unwrapped = metadata.unwrap(formatter.builder); break :node if (@intFromEnum(unwrapped) >= first_local_metadata) .{ .local_metadata = .{ .value = function.ptrConst(formatter.builder).debug_values[ @intFromEnum(unwrapped) - first_local_metadata ].toValue(), .function = function, } } else switch (try formatter.refUnwrapped(unwrapped)) { .@"inline" => |node| .{ .local_inline = node }, .index => |node| .{ .local_index = node }, else => unreachable, }; }, }, } }; } fn refUnwrapped(formatter: *Formatter, node: Metadata) Allocator.Error!FormatData.Node { assert(node != .none); assert(@intFromEnum(node) < first_forward_reference); const builder = formatter.builder; const unwrapped_metadata = node.unwrap(builder); const tag = formatter.builder.metadata_items.items(.tag)[@intFromEnum(unwrapped_metadata)]; switch (tag) { .none => unreachable, .expression, .constant => return .{ .@"inline" = unwrapped_metadata }, else => { assert(!tag.isInline()); const gop = try formatter.map.getOrPut(builder.gpa, .{ .metadata = unwrapped_metadata }); return .{ .index = @intCast(gop.index) }; }, } } inline fn specialized( formatter: *Formatter, distinct: enum { @"!", @"distinct !" }, node: enum { DIFile, DICompileUnit, DISubprogram, DILexicalBlock, DILocation, DIBasicType, DICompositeType, DIDerivedType, DISubroutineType, DIEnumerator, DISubrange, DILocalVariable, DIGlobalVariable, DIGlobalVariableExpression, }, nodes: anytype, writer: anytype, ) !void { comptime var fmt_str: []const u8 = ""; const names = comptime std.meta.fieldNames(@TypeOf(nodes)); comptime var fields: [2 + names.len]std.builtin.Type.StructField = undefined; inline for (fields[0..2], .{ "distinct", "node" }) |*field, name| { fmt_str = fmt_str ++ "{[" ++ name ++ "]s}"; field.* = .{ .name = name, .type = []const u8, .default_value_ptr = null, .is_comptime = false, .alignment = 0, }; } fmt_str = fmt_str ++ "("; inline for (fields[2..], names) |*field, name| { fmt_str = fmt_str ++ "{[" ++ name ++ "]S}"; field.* = .{ .name = name, .type = std.fmt.Formatter(format), .default_value_ptr = null, .is_comptime = false, .alignment = 0, }; } fmt_str = fmt_str ++ ")\n"; var fmt_args: @Type(.{ .@"struct" = .{ .layout = .auto, .fields = &fields, .decls = &.{}, .is_tuple = false, } }) = undefined; fmt_args.distinct = @tagName(distinct); fmt_args.node = @tagName(node); inline for (names) |name| @field(fmt_args, name) = try formatter.fmt( name ++ ": ", @field(nodes, name), ); try writer.print(fmt_str, fmt_args); } }; }