aboutsummaryrefslogtreecommitdiff
path: root/src/codegen/llvm/bitcode_writer.zig
diff options
context:
space:
mode:
authorAlex Rønne Petersen <alex@alexrp.com>2025-02-24 12:35:40 +0100
committerAndrew Kelley <andrew@ziglang.org>2025-02-27 01:32:49 -0500
commit5c44934e20fedb29b88616f51de70c92e5d4ba42 (patch)
tree467f18b43b38aff31a089685fb2ba4f9cf4d7a8e /src/codegen/llvm/bitcode_writer.zig
parentdea72d15da4fba909dc3ccb2e9dc5286372ac023 (diff)
downloadzig-5c44934e20fedb29b88616f51de70c92e5d4ba42.tar.gz
zig-5c44934e20fedb29b88616f51de70c92e5d4ba42.zip
Move the compiler's LLVM bitcode builder to std.zig.llvm.
Diffstat (limited to 'src/codegen/llvm/bitcode_writer.zig')
-rw-r--r--src/codegen/llvm/bitcode_writer.zig433
1 files changed, 0 insertions, 433 deletions
diff --git a/src/codegen/llvm/bitcode_writer.zig b/src/codegen/llvm/bitcode_writer.zig
deleted file mode 100644
index 049a15fe17..0000000000
--- a/src/codegen/llvm/bitcode_writer.zig
+++ /dev/null
@@ -1,433 +0,0 @@
-const std = @import("std");
-
-pub const AbbrevOp = union(enum) {
- literal: u32, // 0
- fixed: u16, // 1
- fixed_runtime: type, // 1
- vbr: u16, // 2
- char6: void, // 4
- blob: void, // 5
- array_fixed: u16, // 3, 1
- array_fixed_runtime: type, // 3, 1
- array_vbr: u16, // 3, 2
- array_char6: void, // 3, 4
-};
-
-pub const Error = error{OutOfMemory};
-
-pub fn BitcodeWriter(comptime types: []const type) type {
- return struct {
- const BcWriter = @This();
-
- buffer: std.ArrayList(u32),
- bit_buffer: u32 = 0,
- bit_count: u5 = 0,
-
- widths: [types.len]u16,
-
- pub fn getTypeWidth(self: BcWriter, comptime Type: type) u16 {
- return self.widths[comptime std.mem.indexOfScalar(type, types, Type).?];
- }
-
- pub fn init(allocator: std.mem.Allocator, widths: [types.len]u16) BcWriter {
- return .{
- .buffer = std.ArrayList(u32).init(allocator),
- .widths = widths,
- };
- }
-
- pub fn deinit(self: BcWriter) void {
- self.buffer.deinit();
- }
-
- pub fn toOwnedSlice(self: *BcWriter) Error![]const u32 {
- std.debug.assert(self.bit_count == 0);
- return self.buffer.toOwnedSlice();
- }
-
- pub fn length(self: BcWriter) usize {
- std.debug.assert(self.bit_count == 0);
- return self.buffer.items.len;
- }
-
- pub fn writeBits(self: *BcWriter, value: anytype, bits: u16) Error!void {
- if (bits == 0) return;
-
- var in_buffer = bufValue(value, 32);
- var in_bits = bits;
-
- // Store input bits in buffer if they fit otherwise store as many as possible and flush
- if (self.bit_count > 0) {
- const bits_remaining = 31 - self.bit_count + 1;
- const n: u5 = @intCast(@min(bits_remaining, in_bits));
- const v = @as(u32, @truncate(in_buffer)) << self.bit_count;
- self.bit_buffer |= v;
- in_buffer >>= n;
-
- self.bit_count +%= n;
- in_bits -= n;
-
- if (self.bit_count != 0) return;
- try self.buffer.append(self.bit_buffer);
- self.bit_buffer = 0;
- }
-
- // Write 32-bit chunks of input bits
- while (in_bits >= 32) {
- try self.buffer.append(@truncate(in_buffer));
-
- in_buffer >>= 31;
- in_buffer >>= 1;
- in_bits -= 32;
- }
-
- // Store remaining input bits in buffer
- if (in_bits > 0) {
- self.bit_count = @intCast(in_bits);
- self.bit_buffer = @truncate(in_buffer);
- }
- }
-
- pub fn writeVBR(self: *BcWriter, value: anytype, comptime vbr_bits: usize) Error!void {
- comptime {
- std.debug.assert(vbr_bits > 1);
- if (@bitSizeOf(@TypeOf(value)) > 64) @compileError("Unsupported VBR block type: " ++ @typeName(@TypeOf(value)));
- }
-
- var in_buffer = bufValue(value, vbr_bits);
-
- const continue_bit = @as(@TypeOf(in_buffer), 1) << @intCast(vbr_bits - 1);
- const mask = continue_bit - 1;
-
- // If input is larger than one VBR block can store
- // then store vbr_bits - 1 bits and a continue bit
- while (in_buffer > mask) {
- try self.writeBits(in_buffer & mask | continue_bit, vbr_bits);
- in_buffer >>= @intCast(vbr_bits - 1);
- }
-
- // Store remaining bits
- try self.writeBits(in_buffer, vbr_bits);
- }
-
- pub fn bitsVBR(_: *const BcWriter, value: anytype, comptime vbr_bits: usize) u16 {
- comptime {
- std.debug.assert(vbr_bits > 1);
- if (@bitSizeOf(@TypeOf(value)) > 64) @compileError("Unsupported VBR block type: " ++ @typeName(@TypeOf(value)));
- }
-
- var bits: u16 = 0;
-
- var in_buffer = bufValue(value, vbr_bits);
-
- const continue_bit = @as(@TypeOf(in_buffer), 1) << @intCast(vbr_bits - 1);
- const mask = continue_bit - 1;
-
- // If input is larger than one VBR block can store
- // then store vbr_bits - 1 bits and a continue bit
- while (in_buffer > mask) {
- bits += @intCast(vbr_bits);
- in_buffer >>= @intCast(vbr_bits - 1);
- }
-
- // Store remaining bits
- bits += @intCast(vbr_bits);
- return bits;
- }
-
- pub fn write6BitChar(self: *BcWriter, c: u8) Error!void {
- try self.writeBits(charTo6Bit(c), 6);
- }
-
- pub fn writeBlob(self: *BcWriter, blob: []const u8) Error!void {
- const blob_word_size = std.mem.alignForward(usize, blob.len, 4);
- try self.buffer.ensureUnusedCapacity(blob_word_size + 1);
- self.alignTo32() catch unreachable;
-
- const slice = self.buffer.addManyAsSliceAssumeCapacity(blob_word_size / 4);
- const slice_bytes = std.mem.sliceAsBytes(slice);
- @memcpy(slice_bytes[0..blob.len], blob);
- @memset(slice_bytes[blob.len..], 0);
- }
-
- pub fn alignTo32(self: *BcWriter) Error!void {
- if (self.bit_count == 0) return;
-
- try self.buffer.append(self.bit_buffer);
- self.bit_buffer = 0;
- self.bit_count = 0;
- }
-
- pub fn enterTopBlock(self: *BcWriter, comptime SubBlock: type) Error!BlockWriter(SubBlock) {
- return BlockWriter(SubBlock).init(self, 2, true);
- }
-
- fn BlockWriter(comptime Block: type) type {
- return struct {
- const Self = @This();
-
- // The minimum abbrev id length based on the number of abbrevs present in the block
- pub const abbrev_len = std.math.log2_int_ceil(
- u6,
- 4 + (if (@hasDecl(Block, "abbrevs")) Block.abbrevs.len else 0),
- );
-
- start: usize,
- bitcode: *BcWriter,
-
- pub fn init(bitcode: *BcWriter, comptime parent_abbrev_len: u6, comptime define_abbrevs: bool) Error!Self {
- try bitcode.writeBits(1, parent_abbrev_len);
- try bitcode.writeVBR(Block.id, 8);
- try bitcode.writeVBR(abbrev_len, 4);
- try bitcode.alignTo32();
-
- // We store the index of the block size and store a dummy value as the number of words in the block
- const start = bitcode.length();
- try bitcode.writeBits(0, 32);
-
- var self = Self{
- .start = start,
- .bitcode = bitcode,
- };
-
- // Predefine all block abbrevs
- if (define_abbrevs) {
- inline for (Block.abbrevs) |Abbrev| {
- try self.defineAbbrev(&Abbrev.ops);
- }
- }
-
- return self;
- }
-
- pub fn enterSubBlock(self: Self, comptime SubBlock: type, comptime define_abbrevs: bool) Error!BlockWriter(SubBlock) {
- return BlockWriter(SubBlock).init(self.bitcode, abbrev_len, define_abbrevs);
- }
-
- pub fn end(self: *Self) Error!void {
- try self.bitcode.writeBits(0, abbrev_len);
- try self.bitcode.alignTo32();
-
- // Set the number of words in the block at the start of the block
- self.bitcode.buffer.items[self.start] = @truncate(self.bitcode.length() - self.start - 1);
- }
-
- pub fn writeUnabbrev(self: *Self, code: u32, values: []const u64) Error!void {
- try self.bitcode.writeBits(3, abbrev_len);
- try self.bitcode.writeVBR(code, 6);
- try self.bitcode.writeVBR(values.len, 6);
- for (values) |val| {
- try self.bitcode.writeVBR(val, 6);
- }
- }
-
- pub fn writeAbbrev(self: *Self, params: anytype) Error!void {
- return self.writeAbbrevAdapted(params, struct {
- pub fn get(_: @This(), param: anytype, comptime _: []const u8) @TypeOf(param) {
- return param;
- }
- }{});
- }
-
- pub fn abbrevId(comptime Abbrev: type) u32 {
- inline for (Block.abbrevs, 0..) |abbrev, i| {
- if (Abbrev == abbrev) return i + 4;
- }
-
- @compileError("Unknown abbrev: " ++ @typeName(Abbrev));
- }
-
- pub fn writeAbbrevAdapted(
- self: *Self,
- params: anytype,
- adapter: anytype,
- ) Error!void {
- const Abbrev = @TypeOf(params);
-
- try self.bitcode.writeBits(comptime abbrevId(Abbrev), abbrev_len);
-
- const fields = std.meta.fields(Abbrev);
-
- // This abbreviation might only contain literals
- if (fields.len == 0) return;
-
- comptime var field_index: usize = 0;
- inline for (Abbrev.ops) |ty| {
- const field_name = fields[field_index].name;
- const param = @field(params, field_name);
-
- switch (ty) {
- .literal => continue,
- .fixed => |len| try self.bitcode.writeBits(adapter.get(param, field_name), len),
- .fixed_runtime => |width_ty| try self.bitcode.writeBits(
- adapter.get(param, field_name),
- self.bitcode.getTypeWidth(width_ty),
- ),
- .vbr => |len| try self.bitcode.writeVBR(adapter.get(param, field_name), len),
- .char6 => try self.bitcode.write6BitChar(adapter.get(param, field_name)),
- .blob => {
- try self.bitcode.writeVBR(param.len, 6);
- try self.bitcode.writeBlob(param);
- },
- .array_fixed => |len| {
- try self.bitcode.writeVBR(param.len, 6);
- for (param) |x| {
- try self.bitcode.writeBits(adapter.get(x, field_name), len);
- }
- },
- .array_fixed_runtime => |width_ty| {
- try self.bitcode.writeVBR(param.len, 6);
- for (param) |x| {
- try self.bitcode.writeBits(
- adapter.get(x, field_name),
- self.bitcode.getTypeWidth(width_ty),
- );
- }
- },
- .array_vbr => |len| {
- try self.bitcode.writeVBR(param.len, 6);
- for (param) |x| {
- try self.bitcode.writeVBR(adapter.get(x, field_name), len);
- }
- },
- .array_char6 => {
- try self.bitcode.writeVBR(param.len, 6);
- for (param) |x| {
- try self.bitcode.write6BitChar(adapter.get(x, field_name));
- }
- },
- }
- field_index += 1;
- if (field_index == fields.len) break;
- }
- }
-
- pub fn defineAbbrev(self: *Self, comptime ops: []const AbbrevOp) Error!void {
- const bitcode = self.bitcode;
- try bitcode.writeBits(2, abbrev_len);
-
- // ops.len is not accurate because arrays are actually two ops
- try bitcode.writeVBR(blk: {
- var count: usize = 0;
- inline for (ops) |op| {
- count += switch (op) {
- .literal, .fixed, .fixed_runtime, .vbr, .char6, .blob => 1,
- .array_fixed, .array_fixed_runtime, .array_vbr, .array_char6 => 2,
- };
- }
- break :blk count;
- }, 5);
-
- inline for (ops) |op| {
- switch (op) {
- .literal => |value| {
- try bitcode.writeBits(1, 1);
- try bitcode.writeVBR(value, 8);
- },
- .fixed => |width| {
- try bitcode.writeBits(0, 1);
- try bitcode.writeBits(1, 3);
- try bitcode.writeVBR(width, 5);
- },
- .fixed_runtime => |width_ty| {
- try bitcode.writeBits(0, 1);
- try bitcode.writeBits(1, 3);
- try bitcode.writeVBR(bitcode.getTypeWidth(width_ty), 5);
- },
- .vbr => |width| {
- try bitcode.writeBits(0, 1);
- try bitcode.writeBits(2, 3);
- try bitcode.writeVBR(width, 5);
- },
- .char6 => {
- try bitcode.writeBits(0, 1);
- try bitcode.writeBits(4, 3);
- },
- .blob => {
- try bitcode.writeBits(0, 1);
- try bitcode.writeBits(5, 3);
- },
- .array_fixed => |width| {
- // Array op
- try bitcode.writeBits(0, 1);
- try bitcode.writeBits(3, 3);
-
- // Fixed or VBR op
- try bitcode.writeBits(0, 1);
- try bitcode.writeBits(1, 3);
- try bitcode.writeVBR(width, 5);
- },
- .array_fixed_runtime => |width_ty| {
- // Array op
- try bitcode.writeBits(0, 1);
- try bitcode.writeBits(3, 3);
-
- // Fixed or VBR op
- try bitcode.writeBits(0, 1);
- try bitcode.writeBits(1, 3);
- try bitcode.writeVBR(bitcode.getTypeWidth(width_ty), 5);
- },
- .array_vbr => |width| {
- // Array op
- try bitcode.writeBits(0, 1);
- try bitcode.writeBits(3, 3);
-
- // Fixed or VBR op
- try bitcode.writeBits(0, 1);
- try bitcode.writeBits(2, 3);
- try bitcode.writeVBR(width, 5);
- },
- .array_char6 => {
- // Array op
- try bitcode.writeBits(0, 1);
- try bitcode.writeBits(3, 3);
-
- // Char6 op
- try bitcode.writeBits(0, 1);
- try bitcode.writeBits(4, 3);
- },
- }
- }
- }
- };
- }
- };
-}
-
-fn charTo6Bit(c: u8) u8 {
- return switch (c) {
- 'a'...'z' => c - 'a',
- 'A'...'Z' => c - 'A' + 26,
- '0'...'9' => c - '0' + 52,
- '.' => 62,
- '_' => 63,
- else => @panic("Failed to encode byte as 6-bit char"),
- };
-}
-
-fn BufType(comptime T: type, comptime min_len: usize) type {
- return std.meta.Int(.unsigned, @max(min_len, @bitSizeOf(switch (@typeInfo(T)) {
- .comptime_int => u32,
- .int => |info| if (info.signedness == .unsigned)
- T
- else
- @compileError("Unsupported type: " ++ @typeName(T)),
- .@"enum" => |info| info.tag_type,
- .bool => u1,
- .@"struct" => |info| switch (info.layout) {
- .auto, .@"extern" => @compileError("Unsupported type: " ++ @typeName(T)),
- .@"packed" => std.meta.Int(.unsigned, @bitSizeOf(T)),
- },
- else => @compileError("Unsupported type: " ++ @typeName(T)),
- })));
-}
-
-fn bufValue(value: anytype, comptime min_len: usize) BufType(@TypeOf(value), min_len) {
- return switch (@typeInfo(@TypeOf(value))) {
- .comptime_int, .int => @intCast(value),
- .@"enum" => @intFromEnum(value),
- .bool => @intFromBool(value),
- .@"struct" => @intCast(@as(std.meta.Int(.unsigned, @bitSizeOf(@TypeOf(value))), @bitCast(value))),
- else => unreachable,
- };
-}