diff options
| author | Alex Rønne Petersen <alex@alexrp.com> | 2025-02-24 12:35:40 +0100 |
|---|---|---|
| committer | Andrew Kelley <andrew@ziglang.org> | 2025-02-27 01:32:49 -0500 |
| commit | 5c44934e20fedb29b88616f51de70c92e5d4ba42 (patch) | |
| tree | 467f18b43b38aff31a089685fb2ba4f9cf4d7a8e /src/codegen/llvm/BitcodeReader.zig | |
| parent | dea72d15da4fba909dc3ccb2e9dc5286372ac023 (diff) | |
| download | zig-5c44934e20fedb29b88616f51de70c92e5d4ba42.tar.gz zig-5c44934e20fedb29b88616f51de70c92e5d4ba42.zip | |
Move the compiler's LLVM bitcode builder to std.zig.llvm.
Diffstat (limited to 'src/codegen/llvm/BitcodeReader.zig')
| -rw-r--r-- | src/codegen/llvm/BitcodeReader.zig | 515 |
1 files changed, 0 insertions, 515 deletions
diff --git a/src/codegen/llvm/BitcodeReader.zig b/src/codegen/llvm/BitcodeReader.zig deleted file mode 100644 index 8a9af15629..0000000000 --- a/src/codegen/llvm/BitcodeReader.zig +++ /dev/null @@ -1,515 +0,0 @@ -allocator: std.mem.Allocator, -record_arena: std.heap.ArenaAllocator.State, -reader: std.io.AnyReader, -keep_names: bool, -bit_buffer: u32, -bit_offset: u5, -stack: std.ArrayListUnmanaged(State), -block_info: std.AutoHashMapUnmanaged(u32, Block.Info), - -pub const Item = union(enum) { - start_block: Block, - record: Record, - end_block: Block, -}; - -pub const Block = struct { - name: []const u8, - id: u32, - len: u32, - - const block_info: u32 = 0; - const first_reserved: u32 = 1; - const last_standard: u32 = 7; - - const Info = struct { - block_name: []const u8, - record_names: std.AutoHashMapUnmanaged(u32, []const u8), - abbrevs: Abbrev.Store, - - const default: Info = .{ - .block_name = &.{}, - .record_names = .{}, - .abbrevs = .{ .abbrevs = .{} }, - }; - - const set_bid_id: u32 = 1; - const block_name_id: u32 = 2; - const set_record_name_id: u32 = 3; - - fn deinit(info: *Info, allocator: std.mem.Allocator) void { - allocator.free(info.block_name); - var record_names_it = info.record_names.valueIterator(); - while (record_names_it.next()) |record_name| allocator.free(record_name.*); - info.record_names.deinit(allocator); - info.abbrevs.deinit(allocator); - info.* = undefined; - } - }; -}; - -pub const Record = struct { - name: []const u8, - id: u32, - operands: []const u64, - blob: []const u8, - - fn toOwnedAbbrev(record: Record, allocator: std.mem.Allocator) !Abbrev { - var operands = std.ArrayList(Abbrev.Operand).init(allocator); - defer operands.deinit(); - - assert(record.id == Abbrev.Builtin.define_abbrev.toRecordId()); - var i: usize = 0; - while (i < record.operands.len) switch (record.operands[i]) { - Abbrev.Operand.literal_id => { - try operands.append(.{ .literal = record.operands[i + 1] }); - i += 2; - }, - @intFromEnum(Abbrev.Operand.Encoding.fixed) => { - try operands.append(.{ .encoding = .{ .fixed = @intCast(record.operands[i + 1]) } }); - i += 2; - }, - @intFromEnum(Abbrev.Operand.Encoding.vbr) => { - try operands.append(.{ .encoding = .{ .vbr = @intCast(record.operands[i + 1]) } }); - i += 2; - }, - @intFromEnum(Abbrev.Operand.Encoding.array) => { - try operands.append(.{ .encoding = .{ .array = 6 } }); - i += 1; - }, - @intFromEnum(Abbrev.Operand.Encoding.char6) => { - try operands.append(.{ .encoding = .char6 }); - i += 1; - }, - @intFromEnum(Abbrev.Operand.Encoding.blob) => { - try operands.append(.{ .encoding = .{ .blob = 6 } }); - i += 1; - }, - else => unreachable, - }; - - return .{ .operands = try operands.toOwnedSlice() }; - } -}; - -pub const InitOptions = struct { - reader: std.io.AnyReader, - keep_names: bool = false, -}; -pub fn init(allocator: std.mem.Allocator, options: InitOptions) BitcodeReader { - return .{ - .allocator = allocator, - .record_arena = .{}, - .reader = options.reader, - .keep_names = options.keep_names, - .bit_buffer = 0, - .bit_offset = 0, - .stack = .{}, - .block_info = .{}, - }; -} - -pub fn deinit(bc: *BitcodeReader) void { - var block_info_it = bc.block_info.valueIterator(); - while (block_info_it.next()) |block_info| block_info.deinit(bc.allocator); - bc.block_info.deinit(bc.allocator); - for (bc.stack.items) |*state| state.deinit(bc.allocator); - bc.stack.deinit(bc.allocator); - bc.record_arena.promote(bc.allocator).deinit(); - bc.* = undefined; -} - -pub fn checkMagic(bc: *BitcodeReader, magic: *const [4]u8) !void { - var buffer: [4]u8 = undefined; - try bc.readBytes(&buffer); - if (!std.mem.eql(u8, &buffer, magic)) return error.InvalidMagic; - - try bc.startBlock(null, 2); - try bc.block_info.put(bc.allocator, Block.block_info, Block.Info.default); -} - -pub fn next(bc: *BitcodeReader) !?Item { - while (true) { - const record = (try bc.nextRecord()) orelse - return if (bc.stack.items.len > 1) error.EndOfStream else null; - switch (record.id) { - else => return .{ .record = record }, - Abbrev.Builtin.end_block.toRecordId() => { - const block_id = bc.stack.items[bc.stack.items.len - 1].block_id.?; - try bc.endBlock(); - return .{ .end_block = .{ - .name = if (bc.block_info.get(block_id)) |block_info| - block_info.block_name - else - &.{}, - .id = block_id, - .len = 0, - } }; - }, - Abbrev.Builtin.enter_subblock.toRecordId() => { - const block_id: u32 = @intCast(record.operands[0]); - switch (block_id) { - Block.block_info => try bc.parseBlockInfoBlock(), - Block.first_reserved...Block.last_standard => return error.UnsupportedBlockId, - else => { - try bc.startBlock(block_id, @intCast(record.operands[1])); - return .{ .start_block = .{ - .name = if (bc.block_info.get(block_id)) |block_info| - block_info.block_name - else - &.{}, - .id = block_id, - .len = @intCast(record.operands[2]), - } }; - }, - } - }, - Abbrev.Builtin.define_abbrev.toRecordId() => try bc.stack.items[bc.stack.items.len - 1] - .abbrevs.addOwnedAbbrev(bc.allocator, try record.toOwnedAbbrev(bc.allocator)), - } - } -} - -pub fn skipBlock(bc: *BitcodeReader, block: Block) !void { - assert(bc.bit_offset == 0); - try bc.reader.skipBytes(@as(u34, block.len) * 4, .{}); - try bc.endBlock(); -} - -fn nextRecord(bc: *BitcodeReader) !?Record { - const state = &bc.stack.items[bc.stack.items.len - 1]; - const abbrev_id = bc.readFixed(u32, state.abbrev_id_width) catch |err| switch (err) { - error.EndOfStream => return null, - else => |e| return e, - }; - if (abbrev_id >= state.abbrevs.abbrevs.items.len) return error.InvalidAbbrevId; - const abbrev = state.abbrevs.abbrevs.items[abbrev_id]; - - var record_arena = bc.record_arena.promote(bc.allocator); - defer bc.record_arena = record_arena.state; - _ = record_arena.reset(.retain_capacity); - - var operands = try std.ArrayList(u64).initCapacity(record_arena.allocator(), abbrev.operands.len); - var blob = std.ArrayList(u8).init(record_arena.allocator()); - for (abbrev.operands, 0..) |abbrev_operand, abbrev_operand_i| switch (abbrev_operand) { - .literal => |value| operands.appendAssumeCapacity(value), - .encoding => |abbrev_encoding| switch (abbrev_encoding) { - .fixed => |width| operands.appendAssumeCapacity(try bc.readFixed(u64, width)), - .vbr => |width| operands.appendAssumeCapacity(try bc.readVbr(u64, width)), - .array => |len_width| { - assert(abbrev_operand_i + 2 == abbrev.operands.len); - const len: usize = @intCast(try bc.readVbr(u32, len_width)); - try operands.ensureUnusedCapacity(len); - for (0..len) |_| switch (abbrev.operands[abbrev.operands.len - 1]) { - .literal => |elem_value| operands.appendAssumeCapacity(elem_value), - .encoding => |elem_encoding| switch (elem_encoding) { - .fixed => |elem_width| operands.appendAssumeCapacity(try bc.readFixed(u64, elem_width)), - .vbr => |elem_width| operands.appendAssumeCapacity(try bc.readVbr(u64, elem_width)), - .array, .blob => return error.InvalidArrayElement, - .char6 => operands.appendAssumeCapacity(try bc.readChar6()), - }, - .align_32_bits, .block_len => return error.UnsupportedArrayElement, - .abbrev_op => switch (try bc.readFixed(u1, 1)) { - 1 => try operands.appendSlice(&.{ - Abbrev.Operand.literal_id, - try bc.readVbr(u64, 8), - }), - 0 => { - const encoding: Abbrev.Operand.Encoding = - @enumFromInt(try bc.readFixed(u3, 3)); - try operands.append(@intFromEnum(encoding)); - switch (encoding) { - .fixed, .vbr => try operands.append(try bc.readVbr(u7, 5)), - .array, .char6, .blob => {}, - _ => return error.UnsuportedAbbrevEncoding, - } - }, - }, - }; - break; - }, - .char6 => operands.appendAssumeCapacity(try bc.readChar6()), - .blob => |len_width| { - assert(abbrev_operand_i + 1 == abbrev.operands.len); - const len = std.math.cast(usize, try bc.readVbr(u32, len_width)) orelse - return error.Overflow; - bc.align32Bits(); - try bc.readBytes(try blob.addManyAsSlice(len)); - bc.align32Bits(); - }, - }, - .align_32_bits => bc.align32Bits(), - .block_len => operands.appendAssumeCapacity(try bc.read32Bits()), - .abbrev_op => unreachable, - }; - return .{ - .name = name: { - if (operands.items.len < 1) break :name &.{}; - const record_id = std.math.cast(u32, operands.items[0]) orelse break :name &.{}; - if (state.block_id) |block_id| { - if (bc.block_info.get(block_id)) |block_info| { - break :name block_info.record_names.get(record_id) orelse break :name &.{}; - } - } - break :name &.{}; - }, - .id = std.math.cast(u32, operands.items[0]) orelse return error.InvalidRecordId, - .operands = operands.items[1..], - .blob = blob.items, - }; -} - -fn startBlock(bc: *BitcodeReader, block_id: ?u32, new_abbrev_len: u6) !void { - const abbrevs = if (block_id) |id| - if (bc.block_info.get(id)) |block_info| block_info.abbrevs.abbrevs.items else &.{} - else - &.{}; - - const state = try bc.stack.addOne(bc.allocator); - state.* = .{ - .block_id = block_id, - .abbrev_id_width = new_abbrev_len, - .abbrevs = .{ .abbrevs = .{} }, - }; - try state.abbrevs.abbrevs.ensureTotalCapacity( - bc.allocator, - @typeInfo(Abbrev.Builtin).@"enum".fields.len + abbrevs.len, - ); - - assert(state.abbrevs.abbrevs.items.len == @intFromEnum(Abbrev.Builtin.end_block)); - try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, .{ - .operands = &.{ - .{ .literal = Abbrev.Builtin.end_block.toRecordId() }, - .align_32_bits, - }, - }); - assert(state.abbrevs.abbrevs.items.len == @intFromEnum(Abbrev.Builtin.enter_subblock)); - try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, .{ - .operands = &.{ - .{ .literal = Abbrev.Builtin.enter_subblock.toRecordId() }, - .{ .encoding = .{ .vbr = 8 } }, // blockid - .{ .encoding = .{ .vbr = 4 } }, // newabbrevlen - .align_32_bits, - .block_len, - }, - }); - assert(state.abbrevs.abbrevs.items.len == @intFromEnum(Abbrev.Builtin.define_abbrev)); - try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, .{ - .operands = &.{ - .{ .literal = Abbrev.Builtin.define_abbrev.toRecordId() }, - .{ .encoding = .{ .array = 5 } }, // numabbrevops - .abbrev_op, - }, - }); - assert(state.abbrevs.abbrevs.items.len == @intFromEnum(Abbrev.Builtin.unabbrev_record)); - try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, .{ - .operands = &.{ - .{ .encoding = .{ .vbr = 6 } }, // code - .{ .encoding = .{ .array = 6 } }, // numops - .{ .encoding = .{ .vbr = 6 } }, // ops - }, - }); - assert(state.abbrevs.abbrevs.items.len == @typeInfo(Abbrev.Builtin).@"enum".fields.len); - for (abbrevs) |abbrev| try state.abbrevs.addAbbrevAssumeCapacity(bc.allocator, abbrev); -} - -fn endBlock(bc: *BitcodeReader) !void { - if (bc.stack.items.len == 0) return error.InvalidEndBlock; - bc.stack.items[bc.stack.items.len - 1].deinit(bc.allocator); - bc.stack.items.len -= 1; -} - -fn parseBlockInfoBlock(bc: *BitcodeReader) !void { - var block_id: ?u32 = null; - while (true) { - const record = (try bc.nextRecord()) orelse return error.EndOfStream; - switch (record.id) { - Abbrev.Builtin.end_block.toRecordId() => break, - Abbrev.Builtin.define_abbrev.toRecordId() => { - const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse - return error.UnspecifiedBlockId); - if (!gop.found_existing) gop.value_ptr.* = Block.Info.default; - try gop.value_ptr.abbrevs.addOwnedAbbrev( - bc.allocator, - try record.toOwnedAbbrev(bc.allocator), - ); - }, - Block.Info.set_bid_id => block_id = std.math.cast(u32, record.operands[0]) orelse - return error.Overflow, - Block.Info.block_name_id => if (bc.keep_names) { - const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse - return error.UnspecifiedBlockId); - if (!gop.found_existing) gop.value_ptr.* = Block.Info.default; - const name = try bc.allocator.alloc(u8, record.operands.len); - errdefer bc.allocator.free(name); - for (name, record.operands) |*byte, operand| - byte.* = std.math.cast(u8, operand) orelse return error.InvalidName; - gop.value_ptr.block_name = name; - }, - Block.Info.set_record_name_id => if (bc.keep_names) { - const gop = try bc.block_info.getOrPut(bc.allocator, block_id orelse - return error.UnspecifiedBlockId); - if (!gop.found_existing) gop.value_ptr.* = Block.Info.default; - const name = try bc.allocator.alloc(u8, record.operands.len - 1); - errdefer bc.allocator.free(name); - for (name, record.operands[1..]) |*byte, operand| - byte.* = std.math.cast(u8, operand) orelse return error.InvalidName; - try gop.value_ptr.record_names.put( - bc.allocator, - std.math.cast(u32, record.operands[0]) orelse return error.Overflow, - name, - ); - }, - else => return error.UnsupportedBlockInfoRecord, - } - } -} - -fn align32Bits(bc: *BitcodeReader) void { - bc.bit_offset = 0; -} - -fn read32Bits(bc: *BitcodeReader) !u32 { - assert(bc.bit_offset == 0); - return bc.reader.readInt(u32, .little); -} - -fn readBytes(bc: *BitcodeReader, bytes: []u8) !void { - assert(bc.bit_offset == 0); - try bc.reader.readNoEof(bytes); - - const trailing_bytes = bytes.len % 4; - if (trailing_bytes > 0) { - var bit_buffer = [1]u8{0} ** 4; - try bc.reader.readNoEof(bit_buffer[trailing_bytes..]); - bc.bit_buffer = std.mem.readInt(u32, &bit_buffer, .little); - bc.bit_offset = @intCast(trailing_bytes * 8); - } -} - -fn readFixed(bc: *BitcodeReader, comptime T: type, bits: u7) !T { - var result: T = 0; - var shift: std.math.Log2IntCeil(T) = 0; - var remaining = bits; - while (remaining > 0) { - if (bc.bit_offset == 0) bc.bit_buffer = try bc.read32Bits(); - const chunk_len = @min(@as(u6, 32) - bc.bit_offset, remaining); - const chunk_mask = @as(u32, std.math.maxInt(u32)) >> @intCast(32 - chunk_len); - result |= @as(T, @intCast(bc.bit_buffer >> bc.bit_offset & chunk_mask)) << @intCast(shift); - shift += @intCast(chunk_len); - remaining -= chunk_len; - bc.bit_offset = @truncate(bc.bit_offset + chunk_len); - } - return result; -} - -fn readVbr(bc: *BitcodeReader, comptime T: type, bits: u7) !T { - const chunk_bits: u6 = @intCast(bits - 1); - const chunk_msb = @as(u64, 1) << chunk_bits; - - var result: u64 = 0; - var shift: u6 = 0; - while (true) { - const chunk = try bc.readFixed(u64, bits); - result |= (chunk & (chunk_msb - 1)) << shift; - if (chunk & chunk_msb == 0) break; - shift += chunk_bits; - } - return @intCast(result); -} - -fn readChar6(bc: *BitcodeReader) !u8 { - return switch (try bc.readFixed(u6, 6)) { - 0...25 => |c| @as(u8, c - 0) + 'a', - 26...51 => |c| @as(u8, c - 26) + 'A', - 52...61 => |c| @as(u8, c - 52) + '0', - 62 => '.', - 63 => '_', - }; -} - -const State = struct { - block_id: ?u32, - abbrev_id_width: u6, - abbrevs: Abbrev.Store, - - fn deinit(state: *State, allocator: std.mem.Allocator) void { - state.abbrevs.deinit(allocator); - state.* = undefined; - } -}; - -const Abbrev = struct { - operands: []const Operand, - - const Builtin = enum(u2) { - end_block, - enter_subblock, - define_abbrev, - unabbrev_record, - - const first_record_id: u32 = std.math.maxInt(u32) - @typeInfo(Builtin).@"enum".fields.len + 1; - fn toRecordId(builtin: Builtin) u32 { - return first_record_id + @intFromEnum(builtin); - } - }; - - const Operand = union(enum) { - literal: u64, - encoding: union(Encoding) { - fixed: u7, - vbr: u6, - array: u3, - char6, - blob: u3, - }, - align_32_bits, - block_len, - abbrev_op, - - const literal_id = std.math.maxInt(u64); - const Encoding = enum(u3) { - fixed = 1, - vbr = 2, - array = 3, - char6 = 4, - blob = 5, - _, - }; - }; - - const Store = struct { - abbrevs: std.ArrayListUnmanaged(Abbrev), - - fn deinit(store: *Store, allocator: std.mem.Allocator) void { - for (store.abbrevs.items) |abbrev| allocator.free(abbrev.operands); - store.abbrevs.deinit(allocator); - store.* = undefined; - } - - fn addAbbrev(store: *Store, allocator: std.mem.Allocator, abbrev: Abbrev) !void { - try store.ensureUnusedCapacity(allocator, 1); - store.addAbbrevAssumeCapacity(abbrev); - } - - fn addAbbrevAssumeCapacity(store: *Store, allocator: std.mem.Allocator, abbrev: Abbrev) !void { - store.abbrevs.appendAssumeCapacity(.{ - .operands = try allocator.dupe(Abbrev.Operand, abbrev.operands), - }); - } - - fn addOwnedAbbrev(store: *Store, allocator: std.mem.Allocator, abbrev: Abbrev) !void { - try store.abbrevs.ensureUnusedCapacity(allocator, 1); - store.addOwnedAbbrevAssumeCapacity(abbrev); - } - - fn addOwnedAbbrevAssumeCapacity(store: *Store, abbrev: Abbrev) void { - store.abbrevs.appendAssumeCapacity(abbrev); - } - }; -}; - -const assert = std.debug.assert; -const std = @import("std"); - -const BitcodeReader = @This(); |
