diff options
| author | antlilja <liljaanton2001@gmail.com> | 2023-08-13 16:04:18 +0200 |
|---|---|---|
| committer | antlilja <liljaanton2001@gmail.com> | 2024-02-21 16:24:59 +0100 |
| commit | b4369dfbda9eae40287972e82febda6bea72f572 (patch) | |
| tree | f4740cf89c5b0a301fde85c079cc15f4a7ba4550 /src/codegen | |
| parent | 5bd2a7c4d69c1777b684daeb5b1c50aaee927087 (diff) | |
| download | zig-b4369dfbda9eae40287972e82febda6bea72f572.tar.gz zig-b4369dfbda9eae40287972e82febda6bea72f572.zip | |
LLVM: Add toBitcode to Builder
Diffstat (limited to 'src/codegen')
| -rw-r--r-- | src/codegen/llvm/Builder.zig | 1475 |
1 files changed, 1474 insertions, 1 deletions
diff --git a/src/codegen/llvm/Builder.zig b/src/codegen/llvm/Builder.zig index 4f08ba88f4..8549eb64b0 100644 --- a/src/codegen/llvm/Builder.zig +++ b/src/codegen/llvm/Builder.zig @@ -1121,7 +1121,7 @@ pub const Attribute = union(Kind) { => |kind| { const field = comptime blk: { @setEvalBranchQuota(10_000); - inline for (@typeInfo(Attribute).Union.fields) |field| { + for (@typeInfo(Attribute).Union.fields) |field| { if (std.mem.eql(u8, field.name, @tagName(kind))) break :blk field; } unreachable; @@ -12042,6 +12042,1476 @@ fn constantExtraData(self: *const Builder, comptime T: type, index: Constant.Ite return self.constantExtraDataTrail(T, index).data; } +pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]const u32 { + const BitcodeWriter = bitcode_writer.BitcodeWriter(&.{ Type, FunctionAttributes }); + var bitcode = BitcodeWriter.init(allocator, &.{ + std.math.log2_int_ceil(usize, self.type_items.items.len - 1), + std.math.log2_int_ceil(usize, self.function_attributes_set.count() - 1), + }); + errdefer bitcode.deinit(); + + // Write LLVM IR magic + try bitcode.writeBits(IR.MAGIC, 32); + + var record = std.ArrayListUnmanaged(u64){}; + defer record.deinit(self.gpa); + + // IDENTIFICATION_BLOCK + { + const Identification = IR.Identification; + var identification_block = try bitcode.enterTopBlock(Identification); + + const producer = try std.fmt.allocPrint(self.gpa, "zig {d}.{d}.{d}", .{ + build_options.semver.major, + build_options.semver.minor, + build_options.semver.patch, + }); + defer self.gpa.free(producer); + + try identification_block.writeAbbrev(Identification.Version{ .string = producer }); + try identification_block.writeAbbrev(Identification.Epoch{ .epoch = 0 }); + + try identification_block.end(); + } + + // MODULE_BLOCK + { + const Module = IR.Module; + var module_block = try bitcode.enterTopBlock(Module); + + try module_block.writeAbbrev(Module.Version{}); + + if (self.target_triple.slice(self)) |triple| { + try module_block.writeAbbrev(Module.String{ + .code = 2, + .string = triple, + }); + } + + if (self.data_layout.slice(self)) |data_layout| { + try module_block.writeAbbrev(Module.String{ + .code = 3, + .string = data_layout, + }); + } + + if (self.source_filename.slice(self)) |source_filename| { + try module_block.writeAbbrev(Module.String{ + .code = 16, + .string = source_filename, + }); + } + + if (self.module_asm.items.len != 0) { + try module_block.writeAbbrev(Module.String{ + .code = 4, + .string = self.module_asm.items, + }); + } + + // TYPE_BLOCK + { + var type_block = try module_block.enterSubBlock(IR.Type); + + try type_block.writeAbbrev(IR.Type.NumEntry{ .num = @intCast(self.type_items.items.len) }); + + for (self.type_items.items, 0..) |item, i| { + const ty: Type = @enumFromInt(i); + + switch (item.tag) { + .simple => try type_block.writeAbbrev(IR.Type.Simple{ .code = @truncate(item.data) }), + .integer => try type_block.writeAbbrev(IR.Type.Integer{ .width = item.data }), + .structure, + .packed_structure, + => |kind| { + const is_packed = switch (kind) { + .structure => false, + .packed_structure => true, + else => unreachable, + }; + var extra = self.typeExtraDataTrail(Type.Structure, item.data); + try type_block.writeAbbrev(IR.Type.StructAnon{ + .is_packed = is_packed, + .types = extra.trail.next(extra.data.fields_len, Type, self), + }); + }, + .named_structure => { + const extra = self.typeExtraData(Type.NamedStructure, item.data); + try type_block.writeAbbrev(IR.Type.StructName{ + .string = extra.id.slice(self).?, + }); + + const real_struct = self.type_items.items[@intFromEnum(extra.body)]; + const is_packed: bool = switch (real_struct.tag) { + .structure => false, + .packed_structure => true, + else => unreachable, + }; + + var real_extra = self.typeExtraDataTrail(Type.Structure, real_struct.data); + try type_block.writeAbbrev(IR.Type.StructNamed{ + .is_packed = is_packed, + .types = real_extra.trail.next(real_extra.data.fields_len, Type, self), + }); + }, + .array, + .small_array, + => try type_block.writeAbbrev(IR.Type.Array{ + .len = ty.aggregateLen(self), + .child = ty.childType(self), + }), + .vector, + .scalable_vector, + => try type_block.writeAbbrev(IR.Type.Vector{ + .len = ty.aggregateLen(self), + .child = ty.childType(self), + }), + .pointer => try type_block.writeAbbrev(IR.Type.Pointer{ + .addr_space = ty.pointerAddrSpace(self), + }), + .target => { + var extra = self.typeExtraDataTrail(Type.Target, item.data); + try type_block.writeAbbrev(IR.Type.StructName{ + .string = extra.data.name.slice(self).?, + }); + + const types = extra.trail.next(extra.data.types_len, Type, self); + const ints = extra.trail.next(extra.data.ints_len, u32, self); + + try type_block.writeAbbrev(IR.Type.Target{ + .num_types = extra.data.types_len, + .types = types, + .ints = ints, + }); + }, + .function, .vararg_function => |kind| { + const is_vararg = switch (kind) { + .function => false, + .vararg_function => true, + else => unreachable, + }; + var extra = self.typeExtraDataTrail(Type.Function, item.data); + try type_block.writeAbbrev(IR.Type.Function{ + .is_vararg = is_vararg, + .return_type = extra.data.ret, + .param_types = extra.trail.next(extra.data.params_len, Type, self), + }); + }, + } + } + + try type_block.end(); + } + + var attributes_set: std.AutoArrayHashMapUnmanaged(struct { + attributes: Attributes, + index: u32, + }, void) = .{}; + defer attributes_set.deinit(self.gpa); + + // PARAMATTR_GROUP_BLOCK + { + const ParamattrGroup = IR.ParamattrGroup; + + var paramattr_group_block = try module_block.enterSubBlock(ParamattrGroup); + + for (self.function_attributes_set.keys()) |func_attributes| { + for (func_attributes.slice(self), 0..) |attributes, i| { + const attributes_slice = attributes.slice(self); + if (attributes_slice.len == 0) continue; + + const attr_gop = try attributes_set.getOrPut(self.gpa, .{ + .attributes = attributes, + .index = @intCast(i), + }); + + if (attr_gop.found_existing) continue; + + record.clearRetainingCapacity(); + try record.ensureUnusedCapacity(self.gpa, 2); + + record.appendAssumeCapacity(attr_gop.index); + record.appendAssumeCapacity(switch (i) { + 0 => 0xffffffff, + else => i - 1, + }); + + for (attributes_slice) |attr_index| { + const kind = attr_index.getKind(self); + switch (attr_index.toAttribute(self)) { + .zeroext, + .signext, + .inreg, + .@"noalias", + .nocapture, + .nofree, + .nest, + .returned, + .nonnull, + .swiftself, + .swiftasync, + .swifterror, + .immarg, + .noundef, + .allocalign, + .allocptr, + .readnone, + .readonly, + .writeonly, + .alwaysinline, + .builtin, + .cold, + .convergent, + .disable_sanitizer_information, + .fn_ret_thunk_extern, + .hot, + .inlinehint, + .jumptable, + .minsize, + .naked, + .nobuiltin, + .nocallback, + .noduplicate, + .noimplicitfloat, + .@"noinline", + .nomerge, + .nonlazybind, + .noprofile, + .skipprofile, + .noredzone, + .noreturn, + .norecurse, + .willreturn, + .nosync, + .nounwind, + .nosanitize_bounds, + .nosanitize_coverage, + .null_pointer_is_valid, + .optforfuzzing, + .optnone, + .optsize, + .returns_twice, + .safestack, + .sanitize_address, + .sanitize_memory, + .sanitize_thread, + .sanitize_hwaddress, + .sanitize_memtag, + .speculative_load_hardening, + .speculatable, + .ssp, + .sspstrong, + .sspreq, + .strictfp, + .nocf_check, + .shadowcallstack, + .mustprogress, + .no_sanitize_address, + .no_sanitize_hwaddress, + .sanitize_address_dyninit, + => { + try record.ensureUnusedCapacity(self.gpa, 2); + record.appendAssumeCapacity(0); + record.appendAssumeCapacity(@intFromEnum(kind)); + }, + .byval, + .byref, + .preallocated, + .inalloca, + .sret, + .elementtype, + => |ty| { + try record.ensureUnusedCapacity(self.gpa, 3); + record.appendAssumeCapacity(6); + record.appendAssumeCapacity(@intFromEnum(kind)); + record.appendAssumeCapacity(@intFromEnum(ty)); + }, + .@"align", + .alignstack, + => |alignment| { + try record.ensureUnusedCapacity(self.gpa, 3); + record.appendAssumeCapacity(1); + record.appendAssumeCapacity(@intFromEnum(kind)); + record.appendAssumeCapacity(alignment.toByteUnits() orelse 0); + }, + .dereferenceable, + .dereferenceable_or_null, + => |size| { + try record.ensureUnusedCapacity(self.gpa, 3); + record.appendAssumeCapacity(1); + record.appendAssumeCapacity(@intFromEnum(kind)); + record.appendAssumeCapacity(size); + }, + .nofpclass => |fpclass| { + try record.ensureUnusedCapacity(self.gpa, 3); + record.appendAssumeCapacity(1); + record.appendAssumeCapacity(@intFromEnum(kind)); + record.appendAssumeCapacity(@as(u32, @bitCast(fpclass))); + }, + .allockind => |allockind| { + try record.ensureUnusedCapacity(self.gpa, 3); + record.appendAssumeCapacity(1); + record.appendAssumeCapacity(@intFromEnum(kind)); + record.appendAssumeCapacity(@as(u32, @bitCast(allockind))); + }, + + .allocsize => |allocsize| { + try record.ensureUnusedCapacity(self.gpa, 3); + record.appendAssumeCapacity(1); + record.appendAssumeCapacity(@intFromEnum(kind)); + record.appendAssumeCapacity(@bitCast(allocsize.toLlvm())); + }, + .memory => |memory| { + try record.ensureUnusedCapacity(self.gpa, 3); + record.appendAssumeCapacity(1); + record.appendAssumeCapacity(@intFromEnum(kind)); + record.appendAssumeCapacity(@as(u32, @bitCast(memory))); + }, + .uwtable => |uwtable| if (uwtable != .none) { + try record.ensureUnusedCapacity(self.gpa, 3); + record.appendAssumeCapacity(1); + record.appendAssumeCapacity(@intFromEnum(kind)); + record.appendAssumeCapacity(@intFromEnum(uwtable)); + }, + .vscale_range => |vscale_range| { + try record.ensureUnusedCapacity(self.gpa, 3); + record.appendAssumeCapacity(1); + record.appendAssumeCapacity(@intFromEnum(kind)); + record.appendAssumeCapacity(@bitCast(vscale_range.toLlvm())); + }, + .string => |string_attr| { + const string_attr_kind_slice = string_attr.kind.slice(self).?; + const string_attr_value_slice = if (string_attr.value != .none) + string_attr.value.slice(self).? + else + null; + + try record.ensureUnusedCapacity( + self.gpa, + 2 + string_attr_kind_slice.len + if (string_attr_value_slice) |slice| slice.len + 1 else 0, + ); + record.appendAssumeCapacity(if (string_attr.value == .none) 3 else 4); + for (string_attr.kind.slice(self).?) |c| { + record.appendAssumeCapacity(c); + } + record.appendAssumeCapacity(0); + if (string_attr_value_slice) |slice| { + for (slice) |c| { + record.appendAssumeCapacity(c); + } + record.appendAssumeCapacity(0); + } + }, + .none => unreachable, + } + } + + try paramattr_group_block.writeUnabbrev(3, record.items); + } + } + + try paramattr_group_block.end(); + } + + // PARAMATTR_BLOCK + { + const Paramattr = IR.Paramattr; + var paramattr_block = try module_block.enterSubBlock(Paramattr); + + for (self.function_attributes_set.keys()) |func_attributes| { + const func_attributes_slice = func_attributes.slice(self); + record.clearRetainingCapacity(); + try record.ensureUnusedCapacity(self.gpa, func_attributes_slice.len); + for (func_attributes_slice, 0..) |attributes, i| { + const attributes_slice = attributes.slice(self); + if (attributes_slice.len == 0) continue; + + const group_index = attributes_set.getIndex(.{ + .attributes = attributes, + .index = @intCast(i), + }) orelse unreachable; + record.appendAssumeCapacity(@intCast(group_index)); + } + + try paramattr_block.writeAbbrev(Paramattr.Entry{ .group_indices = record.items }); + } + + try paramattr_block.end(); + } + + var globals = std.AutoArrayHashMapUnmanaged(Global.Index, void){}; + defer globals.deinit(self.gpa); + try globals.ensureUnusedCapacity( + self.gpa, + self.variables.items.len + + self.functions.items.len + + self.aliases.items.len, + ); + + for (self.variables.items) |variable| { + if (variable.global.getReplacement(self) != .none) continue; + + globals.putAssumeCapacity(variable.global, {}); + } + + for (self.functions.items) |function| { + if (function.global.getReplacement(self) != .none) continue; + + globals.putAssumeCapacity(function.global, {}); + } + + for (self.aliases.items) |alias| { + if (alias.global.getReplacement(self) != .none) continue; + + globals.putAssumeCapacity(alias.global, {}); + } + + const ConstantAdapter = struct { + const ConstantAdapter = @This(); + builder: *const Builder, + globals: *const std.AutoArrayHashMapUnmanaged(Global.Index, void), + + pub fn get(adapter: @This(), param: anytype, comptime field_name: []const u8) @TypeOf(param) { + _ = field_name; + return switch (@TypeOf(param)) { + Constant => @enumFromInt(adapter.getConstantIndex(param)), + else => param, + }; + } + + pub fn getConstantIndex(adapter: ConstantAdapter, constant: Constant) u32 { + return switch (constant.unwrap()) { + .constant => |c| c + adapter.numGlobals(), + .global => |global| @intCast(adapter.globals.getIndex(global.unwrap(adapter.builder)).?), + }; + } + + pub fn numConstants(adapter: ConstantAdapter) u32 { + return @intCast(adapter.globals.count() + adapter.builder.constant_items.len); + } + + pub fn numGlobals(adapter: ConstantAdapter) u32 { + return @intCast(adapter.globals.count()); + } + }; + + const constant_adapter = ConstantAdapter{ + .builder = self, + .globals = &globals, + }; + + // Globals + { + var section_map: std.AutoArrayHashMapUnmanaged(String, void) = .{}; + defer section_map.deinit(self.gpa); + try section_map.ensureUnusedCapacity(self.gpa, globals.count()); + + for (self.variables.items) |variable| { + if (variable.global.getReplacement(self) != .none) continue; + + const section = blk: { + if (variable.section == .none) break :blk 0; + const gop = section_map.getOrPutAssumeCapacity(variable.section); + if (!gop.found_existing) { + try module_block.writeAbbrev(Module.String{ + .code = 5, + .string = variable.section.slice(self) orelse unreachable, + }); + } + break :blk gop.index + 1; + }; + + const initid = if (variable.init == .no_init) + 0 + else + (constant_adapter.getConstantIndex(variable.init) + 1); + + const strtab = variable.global.strtab(self); + + const global = variable.global.ptrConst(self); + try module_block.writeAbbrev(Module.Variable{ + .strtab_offset = strtab.offset, + .strtab_size = strtab.size, + .type_index = global.type, + .is_const = .{ + .is_const = switch (variable.mutability) { + .global => false, + .constant => true, + }, + .addr_space = global.addr_space, + }, + .initid = initid, + .linkage = global.linkage, + .alignment = variable.alignment.toLlvm(), + .section = section, + .visibility = global.visibility, + .thread_local = variable.thread_local, + .unnamed_addr = global.unnamed_addr, + .externally_initialized = global.externally_initialized, + .dllstorageclass = global.dll_storage_class, + .preemption = global.preemption, + }); + } + + for (self.functions.items) |func| { + if (func.global.getReplacement(self) != .none) continue; + + const section = blk: { + if (func.section == .none) break :blk 0; + const gop = section_map.getOrPutAssumeCapacity(func.section); + if (!gop.found_existing) { + try module_block.writeAbbrev(Module.String{ + .code = 5, + .string = func.section.slice(self) orelse unreachable, + }); + } + break :blk gop.index + 1; + }; + + const paramattr_index = if (self.function_attributes_set.getIndex(func.attributes)) |index| + index + 1 + else + 0; + + const strtab = func.global.strtab(self); + + const global = func.global.ptrConst(self); + try module_block.writeAbbrev(Module.Function{ + .strtab_offset = strtab.offset, + .strtab_size = strtab.size, + .type_index = global.type, + .call_conv = func.call_conv, + .is_proto = func.instructions.len == 0, + .linkage = global.linkage, + .paramattr = paramattr_index, + .alignment = func.alignment.toLlvm(), + .section = section, + .visibility = global.visibility, + .unnamed_addr = global.unnamed_addr, + .dllstorageclass = global.dll_storage_class, + .preemption = global.preemption, + .addr_space = global.addr_space, + }); + } + + for (self.aliases.items) |alias| { + if (alias.global.getReplacement(self) != .none) continue; + + const strtab = alias.global.strtab(self); + + const global = alias.global.ptrConst(self); + try module_block.writeAbbrev(Module.Alias{ + .strtab_offset = strtab.offset, + .strtab_size = strtab.size, + .type_index = global.type, + .addr_space = global.addr_space, + .aliasee = constant_adapter.getConstantIndex(alias.aliasee), + .linkage = global.linkage, + .visibility = global.visibility, + .thread_local = alias.thread_local, + .unnamed_addr = global.unnamed_addr, + .dllstorageclass = global.dll_storage_class, + .preemption = global.preemption, + }); + } + } + + // CONSTANTS_BLOCK + { + const Constants = IR.Constants; + var constants_block = try module_block.enterSubBlock(Constants); + + var current_type: Type = .none; + const tags = self.constant_items.items(.tag); + const datas = self.constant_items.items(.data); + for (0..self.constant_items.len) |index| { + record.clearRetainingCapacity(); + const constant: Constant = @enumFromInt(index); + const constant_type = constant.typeOf(self); + if (constant_type != current_type) { + try constants_block.writeAbbrev(Constants.SetType{ .type_id = constant_type }); + current_type = constant_type; + } + const data = datas[index]; + switch (tags[index]) { + .null, + .zeroinitializer, + .none, + => try constants_block.writeAbbrev(Constants.Null{}), + .undef => try constants_block.writeAbbrev(Constants.Undef{}), + .poison => try constants_block.writeAbbrev(Constants.Poison{}), + .positive_integer, + .negative_integer, + => |tag| { + const extra: *align(@alignOf(std.math.big.Limb)) Constant.Integer = + @ptrCast(self.constant_limbs.items[data..][0..Constant.Integer.limbs]); + const limbs = self.constant_limbs + .items[data + Constant.Integer.limbs ..][0..extra.limbs_len]; + const bigint = std.math.big.int.Const{ + .limbs = limbs, + .positive = tag == .positive_integer, + }; + + const bit_count = extra.type.scalarBits(self); + if (bit_count <= 64) { + const val = bigint.to(i64) catch unreachable; + const emit_val = if (tag == .positive_integer) + @shlWithOverflow(val, 1)[0] + else + (@shlWithOverflow(@addWithOverflow(~val, 1)[0], 1)[0] | 1); + try constants_block.writeAbbrev(Constants.Integer{ .value = @bitCast(emit_val) }); + } else { + const word_count = std.mem.alignForward(u24, bit_count, 64) / 64; + try record.ensureUnusedCapacity(self.gpa, word_count); + const buffer: [*]u8 = @ptrCast(record.items.ptr); + bigint.writeTwosComplement(buffer[0..(word_count * 8)], .little); + + const signed_buffer: [*]i64 = @ptrCast(record.items.ptr); + for (signed_buffer[0..word_count], 0..) |val, i| { + signed_buffer[i] = if (val >= 0) + @shlWithOverflow(val, 1)[0] + else + (@shlWithOverflow(@addWithOverflow(~val, 1)[0], 1)[0] | 1); + } + + try constants_block.writeUnabbrev(5, record.items.ptr[0..word_count]); + } + }, + .half, + .bfloat, + => try constants_block.writeAbbrev(Constants.Half{ .value = @truncate(data) }), + .float => try constants_block.writeAbbrev(Constants.Float{ .value = data }), + .double => { + const extra = self.constantExtraData(Constant.Double, data); + try constants_block.writeAbbrev(Constants.Double{ + .value = (@as(u64, extra.hi) << 32) | extra.lo, + }); + }, + .x86_fp80 => { + const extra = self.constantExtraData(Constant.Fp80, data); + try constants_block.writeAbbrev(Constants.Fp80{ + .lo = @as(u64, extra.lo_hi) << 32 | @as(u64, extra.lo_lo), + .hi = @intCast(extra.hi), + }); + }, + .fp128, + .ppc_fp128, + => { + const extra = self.constantExtraData(Constant.Fp128, data); + try constants_block.writeAbbrev(Constants.Fp128{ + .lo = @as(u64, extra.lo_hi) << 32 | @as(u64, extra.lo_lo), + .hi = @as(u64, extra.hi_hi) << 32 | @as(u64, extra.hi_lo), + }); + }, + .array, + .vector, + .structure, + .packed_structure, + => { + var extra = self.constantExtraDataTrail(Constant.Aggregate, data); + const len: u32 = @intCast(extra.data.type.aggregateLen(self)); + const values = extra.trail.next(len, Constant, self); + + try constants_block.writeAbbrevAdapted( + Constants.Aggregate{ .values = values }, + constant_adapter, + ); + }, + .splat => { + const ConstantsWriter = @TypeOf(constants_block); + const extra = self.constantExtraData(Constant.Splat, data); + const vector_len = extra.type.vectorLen(self); + const c = constant_adapter.getConstantIndex(extra.value); + + try bitcode.writeBits( + ConstantsWriter.abbrevId(Constants.Aggregate), + ConstantsWriter.abbrev_len, + ); + try bitcode.writeVBR(vector_len, 6); + for (0..vector_len) |_| { + try bitcode.writeBits(c, Constants.Aggregate.ops[1].array_fixed); + } + }, + .string, + .string_null, + => { + const str: String = @enumFromInt(data); + if (str == .none) { + try constants_block.writeAbbrev(Constants.Null{}); + } else { + const slice = str.slice(self) orelse unreachable; + switch (tags[index]) { + .string => try constants_block.writeAbbrev(Constants.String{ .string = slice }), + .string_null => try constants_block.writeAbbrev(Constants.CString{ .string = slice }), + else => unreachable, + } + } + }, + .bitcast, + .inttoptr, + .ptrtoint, + .fptosi, + .fptoui, + .sitofp, + .uitofp, + .addrspacecast, + .fptrunc, + .trunc, + .fpext, + .sext, + .zext, + => |tag| { + const extra = self.constantExtraData(Constant.Cast, data); + try constants_block.writeAbbrevAdapted(Constants.Cast{ + .type_index = extra.type, + .val = extra.val, + .opcode = tag.toCastOpcode(), + }, constant_adapter); + }, + .add, + .@"add nsw", + .@"add nuw", + .sub, + .@"sub nsw", + .@"sub nuw", + .mul, + .@"mul nsw", + .@"mul nuw", + .shl, + .lshr, + .ashr, + .@"and", + .@"or", + .xor, + => |tag| { + const extra = self.constantExtraData(Constant.Binary, data); + try constants_block.writeAbbrevAdapted(Constants.Binary{ + .opcode = tag.toBinaryOpcode(), + .lhs = extra.lhs, + .rhs = extra.rhs, + }, constant_adapter); + }, + .icmp, + .fcmp, + => { + const extra = self.constantExtraData(Constant.Compare, data); + try constants_block.writeAbbrevAdapted(Constants.Cmp{ + .ty = extra.lhs.typeOf(self), + .lhs = extra.lhs, + .rhs = extra.rhs, + .pred = extra.cond, + }, constant_adapter); + }, + .extractelement => { + const extra = self.constantExtraData(Constant.ExtractElement, data); + try constants_block.writeAbbrevAdapted(Constants.ExtractElement{ + .val_type = extra.val.typeOf(self), + .val = extra.val, + .index_type = extra.index.typeOf(self), + .index = extra.index, + }, constant_adapter); + }, + .insertelement => { + const extra = self.constantExtraData(Constant.InsertElement, data); + try constants_block.writeAbbrevAdapted(Constants.InsertElement{ + .val = extra.val, + .elem = extra.elem, + .index_type = extra.index.typeOf(self), + .index = extra.index, + }, constant_adapter); + }, + .shufflevector => { + const extra = self.constantExtraData(Constant.ShuffleVector, data); + const ty = constant.typeOf(self); + const lhs_type = extra.lhs.typeOf(self); + // Check if instruction is widening, truncating or not + if (ty == lhs_type) { + try constants_block.writeAbbrevAdapted(Constants.ShuffleVector{ + .lhs = extra.lhs, + .rhs = extra.rhs, + .mask = extra.mask, + }, constant_adapter); + } else { + try constants_block.writeAbbrevAdapted(Constants.ShuffleVectorEx{ + .ty = ty, + .lhs = extra.lhs, + .rhs = extra.rhs, + .mask = extra.mask, + }, constant_adapter); + } + }, + .getelementptr, + .@"getelementptr inbounds", + => |tag| { + var extra = self.constantExtraDataTrail(Constant.GetElementPtr, data); + const indices = extra.trail.next(extra.data.info.indices_len, Constant, self); + try record.ensureUnusedCapacity(self.gpa, 1 + 2 + 2 * indices.len); + + record.appendAssumeCapacity(@intFromEnum(extra.data.type)); + + record.appendAssumeCapacity(@intFromEnum(extra.data.base.typeOf(self))); + record.appendAssumeCapacity(constant_adapter.getConstantIndex(extra.data.base)); + + for (indices) |i| { + record.appendAssumeCapacity(@intFromEnum(i.typeOf(self))); + record.appendAssumeCapacity(constant_adapter.getConstantIndex(i)); + } + + try constants_block.writeUnabbrev(switch (tag) { + .getelementptr => 12, + .@"getelementptr inbounds" => 20, + else => unreachable, + }, record.items); + }, + .@"asm", + .@"asm sideeffect", + .@"asm alignstack", + .@"asm sideeffect alignstack", + .@"asm inteldialect", + .@"asm sideeffect inteldialect", + .@"asm alignstack inteldialect", + .@"asm sideeffect alignstack inteldialect", + .@"asm unwind", + .@"asm sideeffect unwind", + .@"asm alignstack unwind", + .@"asm sideeffect alignstack unwind", + .@"asm inteldialect unwind", + .@"asm sideeffect inteldialect unwind", + .@"asm alignstack inteldialect unwind", + .@"asm sideeffect alignstack inteldialect unwind", + => |tag| { + const extra = self.constantExtraData(Constant.Assembly, data); + + const assembly_slice = extra.assembly.slice(self) orelse unreachable; + const constraints_slice = extra.constraints.slice(self) orelse unreachable; + + try record.ensureUnusedCapacity(self.gpa, 4 + assembly_slice.len + constraints_slice.len); + + record.appendAssumeCapacity(@intFromEnum(extra.type)); + record.appendAssumeCapacity(switch (tag) { + .@"asm" => 0, + .@"asm sideeffect" => 0b0001, + .@"asm sideeffect alignstack" => 0b0011, + .@"asm sideeffect inteldialect" => 0b0101, + .@"asm sideeffect alignstack inteldialect" => 0b0111, + .@"asm sideeffect unwind" => 0b1001, + .@"asm sideeffect alignstack unwind" => 0b1011, + .@"asm sideeffect inteldialect unwind" => 0b1101, + .@"asm sideeffect alignstack inteldialect unwind" => 0b1111, + .@"asm alignstack" => 0b0010, + .@"asm inteldialect" => 0b0100, + .@"asm alignstack inteldialect" => 0b0110, + .@"asm unwind" => 0b1000, + .@"asm alignstack unwind" => 0b1010, + .@"asm inteldialect unwind" => 0b1100, + .@"asm alignstack inteldialect unwind" => 0b1110, + else => unreachable, + }); + + record.appendAssumeCapacity(assembly_slice.len); + for (assembly_slice) |c| record.appendAssumeCapacity(c); + + record.appendAssumeCapacity(constraints_slice.len); + for (constraints_slice) |c| record.appendAssumeCapacity(c); + + try constants_block.writeUnabbrev(30, record.items); + }, + .blockaddress => { + const extra = self.constantExtraData(Constant.BlockAddress, data); + try constants_block.writeAbbrev(Constants.BlockAddress{ + .type_id = extra.function.typeOf(self), + .function = constant_adapter.getConstantIndex(extra.function.toConst(self)), + .block = @intFromEnum(extra.block), + }); + }, + .dso_local_equivalent, + .no_cfi, + => |tag| { + const function: Function.Index = @enumFromInt(data); + try constants_block.writeAbbrev(Constants.DsoLocalEquivalentOrNoCfi{ + .code = switch (tag) { + .dso_local_equivalent => 27, + .no_cfi => 29, + else => unreachable, + }, + .type_id = function.typeOf(self), + .function = constant_adapter.getConstantIndex(function.toConst(self)), + }); + }, + } + } + + try constants_block.end(); + } + + // FUNCTION_BLOCKS + { + const FunctionAdapter = struct { + constant_adapter: ConstantAdapter, + func: *const Function, + instruction_index: u32 = 0, + + pub fn init( + const_adapter: ConstantAdapter, + func: *const Function, + ) @This() { + return .{ + .constant_adapter = const_adapter, + .func = func, + .instruction_index = 0, + }; + } + + pub fn get(adapter: @This(), value: anytype, comptime field_name: []const u8) @TypeOf(value) { + _ = field_name; + const Ty = @TypeOf(value); + return switch (Ty) { + Value => @enumFromInt(adapter.getOffsetValueIndex(value)), + Constant => @enumFromInt(adapter.getOffsetConstantIndex(value)), + FunctionAttributes => @enumFromInt(if (value == .none) 0 else (adapter.constant_adapter.builder.function_attributes_set.getIndex(value) orelse unreachable) + 1), + else => value, + }; + } + + pub fn getValueIndex(adapter: @This(), value: Value) u32 { + return @intCast(switch (value.unwrap()) { + .instruction => |instruction| instruction.valueIndex(adapter.func) + adapter.firstInstr(), + .constant => |constant| adapter.constant_adapter.getConstantIndex(constant), + }); + } + + pub fn getOffsetValueIndex(adapter: @This(), value: Value) u32 { + return adapter.offset() - adapter.getValueIndex(value); + } + + pub fn getOffsetValueSignedIndex(adapter: @This(), value: Value) i32 { + const signed_offset: i32 = @intCast(adapter.offset()); + const signed_value: i32 = @intCast(adapter.getValueIndex(value)); + return signed_offset - signed_value; + } + + pub fn getOffsetConstantIndex(adapter: @This(), constant: Constant) u32 { + return adapter.offset() - adapter.constant_adapter.getConstantIndex(constant); + } + + pub fn offset(adapter: @This()) u32 { + return @as( + Function.Instruction.Index, + @enumFromInt(adapter.instruction_index), + ).valueIndex(adapter.func) + adapter.firstInstr(); + } + + fn firstInstr(adapter: @This()) u32 { + return adapter.constant_adapter.numConstants(); + } + + pub fn next(adapter: *@This()) void { + adapter.instruction_index += 1; + } + }; + + for (self.functions.items, 0..) |func, func_index| { + const FunctionBlock = IR.FunctionBlock; + if (func.global.getReplacement(self) != .none) continue; + + if (func.instructions.len == 0) continue; + + var function_block = try module_block.enterSubBlock(FunctionBlock); + + try function_block.writeAbbrev(FunctionBlock.DeclareBlocks{ .num_blocks = func.blocks.len }); + + var adapter = FunctionAdapter.init(constant_adapter, &func); + + const tags = func.instructions.items(.tag); + const datas = func.instructions.items(.data); + + var block_incoming_len: u32 = undefined; + for (0..func.instructions.len) |instr_index| { + const tag = tags[instr_index]; + + record.clearRetainingCapacity(); + + switch (tag) { + .block => block_incoming_len = datas[instr_index], + .arg => {}, + .@"unreachable" => try function_block.writeAbbrev(FunctionBlock.Unreachable{}), + .call, + .@"musttail call", + .@"notail call", + .@"tail call", + => |kind| { + var extra = func.extraDataTrail(Function.Instruction.Call, datas[instr_index]); + + const call_conv = extra.data.info.call_conv; + const args = extra.trail.next(extra.data.args_len, Value, &func); + try function_block.writeAbbrevAdapted(FunctionBlock.Call{ + .attributes = extra.data.attributes, + .call_type = switch (kind) { + .call => .{ .call_conv = call_conv }, + .@"tail call" => .{ .tail = true, .call_conv = call_conv }, + .@"musttail call" => .{ .must_tail = true, .call_conv = call_conv }, + .@"notail call" => .{ .no_tail = true, .call_conv = call_conv }, + else => unreachable, + }, + .type_id = extra.data.ty, + .callee = extra.data.callee, + .args = args, + }, adapter); + }, + .@"call fast", + .@"musttail call fast", + .@"notail call fast", + .@"tail call fast", + => |kind| { + var extra = func.extraDataTrail(Function.Instruction.Call, datas[instr_index]); + + const call_conv = extra.data.info.call_conv; + const args = extra.trail.next(extra.data.args_len, Value, &func); + try function_block.writeAbbrevAdapted(FunctionBlock.CallFast{ + .attributes = extra.data.attributes, + .call_type = switch (kind) { + .call => .{ .call_conv = call_conv }, + .@"tail call" => .{ .tail = true, .call_conv = call_conv }, + .@"musttail call" => .{ .must_tail = true, .call_conv = call_conv }, + .@"notail call" => .{ .no_tail = true, .call_conv = call_conv }, + else => unreachable, + }, + .fast_math = .{}, + .type_id = extra.data.ty, + .callee = extra.data.callee, + .args = args, + }, adapter); + }, + .add, + .@"add nsw", + .@"add nuw", + .@"add nuw nsw", + .@"and", + .fadd, + .fdiv, + .fmul, + .mul, + .@"mul nsw", + .@"mul nuw", + .@"mul nuw nsw", + .frem, + .fsub, + .sdiv, + .@"sdiv exact", + .sub, + .@"sub nsw", + .@"sub nuw", + .@"sub nuw nsw", + .udiv, + .@"udiv exact", + .xor, + .shl, + .@"shl nsw", + .@"shl nuw", + .@"shl nuw nsw", + .lshr, + .@"lshr exact", + .@"or", + .urem, + .srem, + .ashr, + .@"ashr exact", + => { + const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.Binary{ + .opcode = tag.toBinaryOpcode(), + .lhs = adapter.getOffsetValueIndex(extra.lhs), + .rhs = adapter.getOffsetValueIndex(extra.rhs), + }); + }, + .@"fadd fast", + .@"fdiv fast", + .@"fmul fast", + .@"frem fast", + .@"fsub fast", + => { + const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.BinaryFast{ + .opcode = tag.toBinaryOpcode(), + .lhs = adapter.getOffsetValueIndex(extra.lhs), + .rhs = adapter.getOffsetValueIndex(extra.rhs), + .fast_math = .{}, + }); + }, + .alloca, + .@"alloca inalloca", + => |kind| { + const extra = func.extraData(Function.Instruction.Alloca, datas[instr_index]); + const alignment = extra.info.alignment.toLlvm(); + try function_block.writeAbbrev(FunctionBlock.Alloca{ + .inst_type = extra.type, + .len_type = if (extra.len == .none) .i1 else extra.len.typeOf(@enumFromInt(func_index), self), + .len_value = adapter.getValueIndex(if (extra.len == .none) Constant.true.toValue() else extra.len), + .flags = .{ + .align_lower = @truncate(alignment), + .inalloca = kind == .@"alloca inalloca", + .explicit_type = true, + .swift_error = false, + .align_upper = @truncate(alignment << 5), + }, + }); + }, + .bitcast, + .inttoptr, + .ptrtoint, + .fptosi, + .fptoui, + .sitofp, + .uitofp, + .addrspacecast, + .fptrunc, + .trunc, + .fpext, + .sext, + .zext, + => { + const extra = func.extraData(Function.Instruction.Cast, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.Cast{ + .val = adapter.getOffsetValueIndex(extra.val), + .type_index = extra.type, + .opcode = tag.toCastOpcode(), + }); + }, + .@"fcmp false", + .@"fcmp oeq", + .@"fcmp oge", + .@"fcmp ogt", + .@"fcmp ole", + .@"fcmp olt", + .@"fcmp one", + .@"fcmp ord", + .@"fcmp true", + .@"fcmp ueq", + .@"fcmp uge", + .@"fcmp ugt", + .@"fcmp ule", + .@"fcmp ult", + .@"fcmp une", + .@"fcmp uno", + .@"icmp eq", + .@"icmp ne", + .@"icmp sge", + .@"icmp sgt", + .@"icmp sle", + .@"icmp slt", + .@"icmp uge", + .@"icmp ugt", + .@"icmp ule", + .@"icmp ult", + => { + const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.Cmp{ + .lhs = adapter.getOffsetValueIndex(extra.lhs), + .rhs = adapter.getOffsetValueIndex(extra.rhs), + .pred = tag.toCmpPredicate(), + }); + }, + .@"fcmp fast false", + .@"fcmp fast oeq", + .@"fcmp fast oge", + .@"fcmp fast ogt", + .@"fcmp fast ole", + .@"fcmp fast olt", + .@"fcmp fast one", + .@"fcmp fast ord", + .@"fcmp fast true", + .@"fcmp fast ueq", + .@"fcmp fast uge", + .@"fcmp fast ugt", + .@"fcmp fast ule", + .@"fcmp fast ult", + .@"fcmp fast une", + .@"fcmp fast uno", + => { + const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.CmpFast{ + .lhs = adapter.getOffsetValueIndex(extra.lhs), + .rhs = adapter.getOffsetValueIndex(extra.rhs), + .pred = tag.toCmpPredicate(), + .fast_math = .{}, + }); + }, + .fneg => try function_block.writeAbbrev(FunctionBlock.FNeg{ + .val = adapter.getOffsetValueIndex(@enumFromInt(datas[instr_index])), + }), + .@"fneg fast" => try function_block.writeAbbrev(FunctionBlock.FNegFast{ + .val = adapter.getOffsetValueIndex(@enumFromInt(datas[instr_index])), + .fast_math = .{}, + }), + .extractvalue => { + var extra = func.extraDataTrail(Function.Instruction.ExtractValue, datas[instr_index]); + const indices = extra.trail.next(extra.data.indices_len, u32, &func); + try function_block.writeAbbrev(FunctionBlock.ExtractValue{ + .val = adapter.getOffsetValueIndex(extra.data.val), + .indices = indices, + }); + }, + .insertvalue => { + var extra = func.extraDataTrail(Function.Instruction.InsertValue, datas[instr_index]); + const indices = extra.trail.next(extra.data.indices_len, u32, &func); + try function_block.writeAbbrev(FunctionBlock.InsertValue{ + .val = adapter.getOffsetValueIndex(extra.data.val), + .elem = adapter.getOffsetValueIndex(extra.data.elem), + .indices = indices, + }); + }, + .extractelement => { + const extra = func.extraData(Function.Instruction.ExtractElement, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.ExtractElement{ + .val = adapter.getOffsetValueIndex(extra.val), + .index = adapter.getOffsetValueIndex(extra.index), + }); + }, + .insertelement => { + const extra = func.extraData(Function.Instruction.InsertElement, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.InsertElement{ + .val = adapter.getOffsetValueIndex(extra.val), + .elem = adapter.getOffsetValueIndex(extra.elem), + .index = adapter.getOffsetValueIndex(extra.index), + }); + }, + .select => { + const extra = func.extraData(Function.Instruction.Select, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.Select{ + .lhs = adapter.getOffsetValueIndex(extra.lhs), + .rhs = adapter.getOffsetValueIndex(extra.rhs), + .cond = adapter.getOffsetValueIndex(extra.cond), + }); + }, + .@"select fast" => { + const extra = func.extraData(Function.Instruction.Select, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.SelectFast{ + .lhs = adapter.getOffsetValueIndex(extra.lhs), + .rhs = adapter.getOffsetValueIndex(extra.rhs), + .cond = adapter.getOffsetValueIndex(extra.cond), + .fast_math = .{}, + }); + }, + .shufflevector => { + const extra = func.extraData(Function.Instruction.ShuffleVector, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.ShuffleVector{ + .lhs = adapter.getOffsetValueIndex(extra.lhs), + .rhs = adapter.getOffsetValueIndex(extra.rhs), + .mask = adapter.getOffsetValueIndex(extra.mask), + }); + }, + .getelementptr, + .@"getelementptr inbounds", + => { + var extra = func.extraDataTrail(Function.Instruction.GetElementPtr, datas[instr_index]); + const indices = extra.trail.next(extra.data.indices_len, Value, &func); + try function_block.writeAbbrevAdapted( + FunctionBlock.GetElementPtr{ + .is_inbounds = tag == .@"getelementptr inbounds", + .type_index = extra.data.type, + .base = extra.data.base, + .indices = indices, + }, + adapter, + ); + }, + .load => { + const extra = func.extraData(Function.Instruction.Load, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.Load{ + .ptr = adapter.getOffsetValueIndex(extra.ptr), + .ty = extra.type, + .alignment = extra.info.alignment.toLlvm(), + .is_volatile = extra.info.access_kind == .@"volatile", + }); + }, + .@"load atomic" => { + const extra = func.extraData(Function.Instruction.Load, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.LoadAtomic{ + .ptr = adapter.getOffsetValueIndex(extra.ptr), + .ty = extra.type, + .alignment = extra.info.alignment.toLlvm(), + .is_volatile = extra.info.access_kind == .@"volatile", + .success_ordering = extra.info.success_ordering, + .sync_scope = extra.info.sync_scope, + }); + }, + .store => { + const extra = func.extraData(Function.Instruction.Store, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.Store{ + .ptr = adapter.getOffsetValueIndex(extra.ptr), + .val = adapter.getOffsetValueIndex(extra.val), + .alignment = extra.info.alignment.toLlvm(), + .is_volatile = extra.info.access_kind == .@"volatile", + }); + }, + .@"store atomic" => { + const extra = func.extraData(Function.Instruction.Store, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.StoreAtomic{ + .ptr = adapter.getOffsetValueIndex(extra.ptr), + .val = adapter.getOffsetValueIndex(extra.val), + .alignment = extra.info.alignment.toLlvm(), + .is_volatile = extra.info.access_kind == .@"volatile", + .success_ordering = extra.info.success_ordering, + .sync_scope = extra.info.sync_scope, + }); + }, + .br => { + try function_block.writeAbbrev(FunctionBlock.BrUnconditional{ + .block = datas[instr_index], + }); + }, + .br_cond => { + const extra = func.extraData(Function.Instruction.BrCond, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.BrConditional{ + .then_block = @intFromEnum(extra.then), + .else_block = @intFromEnum(extra.@"else"), + .condition = adapter.getOffsetValueIndex(extra.cond), + }); + }, + .@"switch" => { + var extra = func.extraDataTrail(Function.Instruction.Switch, datas[instr_index]); + + try record.ensureUnusedCapacity(self.gpa, 3 + extra.data.cases_len * 2); + + // Conditional type + record.appendAssumeCapacity(@intFromEnum(extra.data.val.typeOf(@enumFromInt(func_index), self))); + + // Conditional + record.appendAssumeCapacity(adapter.getOffsetValueIndex(extra.data.val)); + + // Default block + record.appendAssumeCapacity(@intFromEnum(extra.data.default)); + + const vals = extra.trail.next(extra.data.cases_len, Constant, &func); + const blocks = extra.trail.next(extra.data.cases_len, Function.Block.Index, &func); + for (vals, blocks) |val, block| { + record.appendAssumeCapacity(adapter.constant_adapter.getConstantIndex(val)); + record.appendAssumeCapacity(@intFromEnum(block)); + } + + try function_block.writeUnabbrev(12, record.items); + }, + .va_arg => { + const extra = func.extraData(Function.Instruction.VaArg, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.VaArg{ + .list_type = extra.list.typeOf(@enumFromInt(func_index), self), + .list = adapter.getOffsetValueIndex(extra.list), + .type = extra.type, + }); + }, + .phi, + .@"phi fast", + => |kind| { + var extra = func.extraDataTrail(Function.Instruction.Phi, datas[instr_index]); + const vals = extra.trail.next(block_incoming_len, Value, &func); + const blocks = extra.trail.next(block_incoming_len, Function.Block.Index, &func); + + try record.ensureUnusedCapacity( + self.gpa, + 1 + block_incoming_len * 2 + @intFromBool(kind == .@"phi fast"), + ); + + record.appendAssumeCapacity(@intFromEnum(extra.data.type)); + + for (vals, blocks) |val, block| { + const offset_value = adapter.getOffsetValueSignedIndex(val); + const abs_value: u32 = @intCast(@abs(offset_value)); + const signed_vbr = if (offset_value > 0) abs_value << 1 else ((abs_value << 1) | 1); + record.appendAssumeCapacity(signed_vbr); + record.appendAssumeCapacity(@intFromEnum(block)); + } + + if (kind == .@"phi fast") record.appendAssumeCapacity(@as(u8, @bitCast(FastMath{}))); + + try function_block.writeUnabbrev(16, record.items); + }, + .ret => try function_block.writeAbbrev(FunctionBlock.Ret{ + .val = adapter.getOffsetValueIndex(@enumFromInt(datas[instr_index])), + }), + .@"ret void" => try function_block.writeAbbrev(FunctionBlock.RetVoid{}), + .atomicrmw => { + const extra = func.extraData(Function.Instruction.AtomicRmw, datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.AtomicRmw{ + .ptr = adapter.getOffsetValueIndex(extra.ptr), + .val = adapter.getOffsetValueIndex(extra.val), + .operation = extra.info.atomic_rmw_operation, + .is_volatile = extra.info.access_kind == .@"volatile", + .success_ordering = extra.info.success_ordering, + .sync_scope = extra.info.sync_scope, + .alignment = extra.info.alignment.toLlvm(), + }); + }, + .cmpxchg, + .@"cmpxchg weak", + => |kind| { + const extra = func.extraData(Function.Instruction.CmpXchg, datas[instr_index]); + + try function_block.writeAbbrev(FunctionBlock.CmpXchg{ + .ptr = adapter.getOffsetValueIndex(extra.ptr), + .cmp = adapter.getOffsetValueIndex(extra.cmp), + .new = adapter.getOffsetValueIndex(extra.new), + .is_volatile = extra.info.access_kind == .@"volatile", + .success_ordering = extra.info.success_ordering, + .sync_scope = extra.info.sync_scope, + .failure_ordering = extra.info.failure_ordering, + .is_weak = kind == .@"cmpxchg weak", + .alignment = extra.info.alignment.toLlvm(), + }); + }, + .fence => { + const info: MemoryAccessInfo = @bitCast(datas[instr_index]); + try function_block.writeAbbrev(FunctionBlock.Fence{ + .ordering = info.success_ordering, + .sync_scope = info.sync_scope, + }); + }, + } + + adapter.next(); + } + + // VALUE_SYMTAB + if (!self.strip) { + const ValueSymbolTable = IR.FunctionValueSymbolTable; + + var value_symtab_block = try function_block.enterSubBlock(ValueSymbolTable); + + for (func.blocks, 0..) |block, block_index| { + const name = block.instruction.name(&func); + + if (name == .none or name == .empty) continue; + + try value_symtab_block.writeAbbrev(ValueSymbolTable.BlockEntry{ + .value_id = @intCast(block_index), + .string = name.slice(self).?, + }); + } + + // TODO: Emit non block entries if the builder ever starts assigning names to non blocks + + try value_symtab_block.end(); + } + + try function_block.end(); + } + } + + try module_block.end(); + } + + // STRTAB_BLOCK + { + const Strtab = IR.Strtab; + var strtab_block = try bitcode.enterTopBlock(Strtab); + + try strtab_block.writeAbbrev(Strtab.Blob{ .blob = self.string_bytes.items }); + + try strtab_block.end(); + } + + return bitcode.toSlice(); +} + const assert = std.debug.assert; const build_options = @import("build_options"); const builtin = @import("builtin"); @@ -12052,5 +13522,8 @@ else const log = std.log.scoped(.llvm); const std = @import("std"); +const bitcode_writer = @import("bitcode_writer.zig"); +const IR = @import("IR.zig"); + const Allocator = std.mem.Allocator; const Builder = @This(); |
