Commit 43daed64fe

Jacob Young <jacobly0@users.noreply.github.com>
2024-02-23 06:17:37
Builder: change tuple metadata to not be inlined in llvm ir
1 parent 1d4a7e1
Changed files (1)
src
codegen
src/codegen/llvm/Builder.zig
@@ -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 },
+                .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(item) }
+                            .{ .raw = @tagName(some) }
                         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))),
-                        },
-                        .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))),
+                            @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),
                     });
                 },