enum Metadata [src]
Fields
none = 0
empty_tuple = 1
_
Members
- BasicType (struct)
- CompileUnit (struct)
- CompositeType (struct)
- DerivedType (struct)
- DIFlags (struct)
- Enumerator (struct)
- Expression (struct)
- File (struct)
- GlobalVar (struct)
- GlobalVarExpression (struct)
- isInline (Function)
- Item (struct)
- LexicalBlock (struct)
- LocalVar (struct)
- Location (struct)
- ModuleFlag (struct)
- Parameter (struct)
- StrTuple (struct)
- Subprogram (struct)
- Subrange (struct)
- SubroutineType (struct)
- Tag (enum)
- toValue (Function)
- Tuple (struct)
- unwrap (Function)
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);
}
};
}