Builder: change tuple metadata to not be inlined in llvm ir

This commit is contained in:
Jacob Young
2024-02-23 06:17:37 +01:00
parent 1d4a7e123c
commit 43daed64fe

View File

@@ -7640,7 +7640,6 @@ pub const Metadata = enum(u32) {
pub fn isInline(tag: Tag) bool {
return switch (tag) {
.none,
.tuple,
.expression,
.constant,
=> true,
@@ -7673,6 +7672,7 @@ pub const Metadata = enum(u32) {
.enumerator_signed_positive,
.enumerator_signed_negative,
.subrange,
.tuple,
.module_flag,
.local_var,
.parameter,
@@ -7988,58 +7988,31 @@ pub const Metadata = enum(u32) {
need_comma: bool,
map: std.AutoArrayHashMapUnmanaged(Metadata, void) = .{},
fn unwrapAssumeExists(formatter: *Formatter, item: Metadata) FormatData.Item {
if (item == .none) return .none;
const unwrapped_metadata = item.unwrap(formatter.builder);
const tag = formatter.builder.metadata_items.items(.tag)[@intFromEnum(unwrapped_metadata)];
return if (tag.isInline())
.{ .@"inline" = unwrapped_metadata }
else
.{ .index = @intCast(formatter.map.getIndex(unwrapped_metadata).?) };
}
fn unwrap(formatter: *Formatter, item: Metadata) Allocator.Error!FormatData.Item {
if (item == .none) return .none;
const builder = formatter.builder;
const unwrapped_metadata = item.unwrap(builder);
const tag = formatter.builder.metadata_items.items(.tag)[@intFromEnum(unwrapped_metadata)];
switch (tag) {
.none => unreachable,
.tuple => {
var extra = builder.metadataExtraDataTrail(
Metadata.Tuple,
builder.metadata_items.items(.data)[@intFromEnum(unwrapped_metadata)],
);
const elements = extra.trail.next(extra.data.elements_len, Metadata, builder);
for (elements) |element| _ = try formatter.unwrap(element);
},
.expression, .constant => {},
else => {
assert(!tag.isInline());
const gop = try formatter.map.getOrPutValue(builder.gpa, unwrapped_metadata, {});
return .{ .index = @intCast(gop.index) };
},
}
return .{ .@"inline" = unwrapped_metadata };
}
const FormatData = struct {
formatter: *Formatter,
prefix: []const u8 = "",
item: FormatData.Item,
node: Node,
const Item = union(enum) {
const Node = union(enum) {
none,
@"inline": Metadata,
index: u32,
local_value: ValueData,
local_metadata: ValueData,
local_inline: Metadata,
local_index: u32,
string: MetadataString,
value: struct {
value: Value,
function: Function.Index,
},
bool: bool,
u32: u32,
u64: u64,
raw: []const u8,
const ValueData = struct {
value: Value,
function: Function.Index,
};
};
};
fn format(
@@ -8048,146 +8021,154 @@ pub const Metadata = enum(u32) {
fmt_opts: std.fmt.FormatOptions,
writer: anytype,
) @TypeOf(writer).Error!void {
if (data.item == .none) return;
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.item) {
switch (data.node) {
.none => unreachable,
.@"inline" => |item| {
.@"inline" => |node| {
const needed_comma = data.formatter.need_comma;
defer data.formatter.need_comma = needed_comma;
data.formatter.need_comma = false;
const metadata_item = builder.metadata_items.get(@intFromEnum(item));
switch (metadata_item.tag) {
.tuple => {
var extra =
builder.metadataExtraDataTrail(Metadata.Tuple, metadata_item.data);
const elements =
extra.trail.next(extra.data.elements_len, Metadata, builder);
try writer.writeAll("!{");
for (elements) |element| try format(.{
.formatter = data.formatter,
.item = data.formatter.unwrapAssumeExists(element),
}, "%", fmt_opts, writer);
try writer.writeByte('}');
},
const item = builder.metadata_items.get(@intFromEnum(node));
switch (item.tag) {
.expression => {
var extra =
builder.metadataExtraDataTrail(Metadata.Expression, metadata_item.data);
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,
.item = .{ .u64 = element },
.node = .{ .u64 = element },
}, "%", fmt_opts, writer);
try writer.writeByte(')');
},
.constant => try Constant.format(.{
.constant = @enumFromInt(metadata_item.data),
.constant = @enumFromInt(item.data),
.builder = builder,
}, fmt_str, fmt_opts, writer),
}, recurse_fmt_str, fmt_opts, writer),
else => unreachable,
}
},
.index => |item| try writer.print("!{d}", .{item}),
.value => |item| switch (item.value.unwrap()) {
.instruction, .constant => try Value.format(.{
.value = item.value,
.function = item.function,
.builder = builder,
}, fmt_str, fmt_opts, writer),
.metadata => |metadata| if (@intFromEnum(metadata) >=
Metadata.first_local_metadata)
try Value.format(.{
.value = item.function.ptrConst(builder).debug_values[
@intFromEnum(metadata) - Metadata.first_local_metadata
].toValue(),
.function = item.function,
.builder = builder,
}, "%", fmt_opts, writer)
else if (metadata != .none) {
if (comptime std.mem.eql(u8, fmt_str, "%"))
try writer.print("{%} ", .{Type.metadata.fmt(builder)});
try Metadata.Formatter.format(.{
.formatter = data.formatter,
.item = data.formatter.unwrapAssumeExists(metadata),
}, "", fmt_opts, writer);
},
.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 => |item| try writer.print("{}", .{item.fmt(data.formatter.builder)}),
inline .bool, .u32, .u64 => |item| try writer.print("{}", .{item}),
.raw => |item| try writer.writeAll(item),
.string => |node| try writer.print("{s}{}", .{
if (is_specialized) "" else "!",
node.fmt(builder),
}),
inline .bool, .u32, .u64 => |node| try writer.print("{}", .{node}),
.raw => |node| try writer.writeAll(node),
}
}
inline fn fmt(formatter: *Formatter, prefix: []const u8, item: anytype) switch (@TypeOf(item)) {
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,
.item = switch (@typeInfo(@TypeOf(item))) {
.Null => .none,
.Enum => |enum_info| switch (@TypeOf(item)) {
Metadata => try formatter.unwrap(item),
MetadataString => .{ .string = item },
else => if (enum_info.is_exhaustive)
.{ .raw = @tagName(item) }
else
@compileError("unknown type to format: " ++ @typeName(@TypeOf(item))),
},
.EnumLiteral => .{ .raw = @tagName(item) },
.Bool => .{ .bool = item },
.Struct => .{ .u32 = @bitCast(item) },
.Int, .ComptimeInt => .{ .u64 = item },
.Pointer => .{ .raw = item },
.Optional => if (item) |some| switch (@typeInfo(@TypeOf(some))) {
.Enum => |enum_info| switch (@TypeOf(some)) {
Metadata => try formatter.unwrap(some),
MetadataString => .{ .string = some },
else => if (enum_info.is_exhaustive)
.{ .raw = @tagName(some) }
else
@compileError("unknown type to format: " ++ @typeName(@TypeOf(item))),
.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)),
},
.Bool => .{ .bool = some },
.Struct => .{ .u32 = @bitCast(some) },
.Int => .{ .u64 = some },
.Pointer => .{ .raw = some },
else => @compileError("unknown type to format: " ++ @typeName(@TypeOf(item))),
} else .none,
else => @compileError("unknown type to format: " ++ @typeName(@TypeOf(item))),
MetadataString => .{ .string = some },
else => if (enum_info.is_exhaustive)
.{ .raw = @tagName(some) }
else
@compileError("unknown type to format: " ++ @typeName(Node)),
},
.EnumLiteral => .{ .raw = @tagName(some) },
.Bool => .{ .bool = some },
.Struct => .{ .u32 = @bitCast(some) },
.Int, .ComptimeInt => .{ .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,
item: Value,
value: Value,
function: Function.Index,
) Allocator.Error!std.fmt.Formatter(format) {
return .{ .data = .{
.formatter = formatter,
.prefix = prefix,
.item = .{ .value = .{
.value = switch (item.unwrap()) {
.instruction, .constant => item,
.metadata => |metadata| value: {
const unwrapped_metadata = metadata.unwrap(formatter.builder);
if (@intFromEnum(unwrapped_metadata) < Metadata.first_local_metadata)
_ = try formatter.unwrap(unwrapped_metadata);
break :value unwrapped_metadata.toValue();
},
.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,
};
},
.function = function,
} },
},
} };
}
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.getOrPutValue(builder.gpa, unwrapped_metadata, {});
return .{ .index = @intCast(gop.index) };
},
}
}
inline fn specialized(
formatter: *Formatter,
@@ -8208,11 +8189,11 @@ pub const Metadata = enum(u32) {
DIGlobalVariable,
DIGlobalVariableExpression,
},
items: anytype,
nodes: anytype,
writer: anytype,
) !void {
comptime var fmt_str: []const u8 = "";
const names = comptime std.meta.fieldNames(@TypeOf(items));
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}";
@@ -8226,7 +8207,7 @@ pub const Metadata = enum(u32) {
}
fmt_str = fmt_str ++ "(";
inline for (fields[2..], names) |*field, name| {
fmt_str = fmt_str ++ "{[" ++ name ++ "]}";
fmt_str = fmt_str ++ "{[" ++ name ++ "]S}";
field.* = .{
.name = name,
.type = std.fmt.Formatter(format),
@@ -8247,7 +8228,7 @@ pub const Metadata = enum(u32) {
fmt_args.node = @tagName(node);
inline for (names) |name| @field(fmt_args, name) = try formatter.fmt(
name ++ ": ",
@field(items, name),
@field(nodes, name),
);
try writer.print(fmt_str, fmt_args);
}
@@ -9877,7 +9858,7 @@ pub fn printUnbuffered(
metadata_formatter.need_comma = false;
defer metadata_formatter.need_comma = undefined;
switch (metadata_item.tag) {
.none, .tuple, .expression, .constant => unreachable,
.none, .expression, .constant => unreachable,
.file => {
const extra = self.metadataExtraData(Metadata.File, metadata_item.data);
try metadata_formatter.specialized(.@"!", .DIFile, .{
@@ -10139,11 +10120,20 @@ pub fn printUnbuffered(
.stride = null,
}, writer);
},
.tuple => {
var extra = self.metadataExtraDataTrail(Metadata.Tuple, metadata_item.data);
const elements = extra.trail.next(extra.data.elements_len, Metadata, self);
try writer.writeAll("!{");
for (elements) |element| try writer.print("{[element]%}", .{
.element = try metadata_formatter.fmt("", element),
});
try writer.writeAll("}\n");
},
.module_flag => {
const extra = self.metadataExtraData(Metadata.ModuleFlag, metadata_item.data);
try writer.print("!{{{[behavior]%}{[name]%}{[constant]%}}}\n", .{
.behavior = try metadata_formatter.fmt("", extra.behavior),
.name = try metadata_formatter.fmt("!", extra.name),
.name = try metadata_formatter.fmt("", extra.name),
.constant = try metadata_formatter.fmt("", extra.constant),
});
},