diff options
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/llvm/Builder.zig | 266 |
1 files changed, 128 insertions, 138 deletions
diff --git a/src/codegen/llvm/Builder.zig b/src/codegen/llvm/Builder.zig index 5de1d827b1..02f5ce7d16 100644 --- a/src/codegen/llvm/Builder.zig +++ b/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), }); }, |
