authorgravatar for liljaanton2001@gmail.comantlilja <liljaanton2001@gmail.com> 2023-08-13 16:04:18+02:00
committergravatar for liljaanton2001@gmail.comantlilja <liljaanton2001@gmail.com> 2024-02-21 16:24:59+01:00
logb4369dfbda9eae40287972e82febda6bea72f572
treef4740cf89c5b0a301fde85c079cc15f4a7ba4550
parent5bd2a7c4d69c1777b684daeb5b1c50aaee927087

LLVM: Add toBitcode to Builder


1 files changed, 1474 insertions(+), 1 deletions(-)

src/codegen/llvm/Builder.zig+1474-1
...@@ -1121,7 +1121,7 @@ pub const Attribute = union(Kind) {...@@ -1121,7 +1121,7 @@ pub const Attribute = union(Kind) {
1121 => |kind| {1121 => |kind| {
1122 const field = comptime blk: {1122 const field = comptime blk: {
1123 @setEvalBranchQuota(10_000);1123 @setEvalBranchQuota(10_000);
1124 inline for (@typeInfo(Attribute).Union.fields) |field| {1124 for (@typeInfo(Attribute).Union.fields) |field| {
1125 if (std.mem.eql(u8, field.name, @tagName(kind))) break :blk field;1125 if (std.mem.eql(u8, field.name, @tagName(kind))) break :blk field;
1126 }1126 }
1127 unreachable;1127 unreachable;
...@@ -12042,6 +12042,1476 @@ fn constantExtraData(self: *const Builder, comptime T: type, index: Constant.Ite...@@ -12042,6 +12042,1476 @@ fn constantExtraData(self: *const Builder, comptime T: type, index: Constant.Ite
12042 return self.constantExtraDataTrail(T, index).data;12042 return self.constantExtraDataTrail(T, index).data;
12043}12043}
1204412044
12045pub fn toBitcode(self: *Builder, allocator: Allocator) bitcode_writer.Error![]const u32 {
12046 const BitcodeWriter = bitcode_writer.BitcodeWriter(&.{ Type, FunctionAttributes });
12047 var bitcode = BitcodeWriter.init(allocator, &.{
12048 std.math.log2_int_ceil(usize, self.type_items.items.len - 1),
12049 std.math.log2_int_ceil(usize, self.function_attributes_set.count() - 1),
12050 });
12051 errdefer bitcode.deinit();
12052
12053 // Write LLVM IR magic
12054 try bitcode.writeBits(IR.MAGIC, 32);
12055
12056 var record = std.ArrayListUnmanaged(u64){};
12057 defer record.deinit(self.gpa);
12058
12059 // IDENTIFICATION_BLOCK
12060 {
12061 const Identification = IR.Identification;
12062 var identification_block = try bitcode.enterTopBlock(Identification);
12063
12064 const producer = try std.fmt.allocPrint(self.gpa, "zig {d}.{d}.{d}", .{
12065 build_options.semver.major,
12066 build_options.semver.minor,
12067 build_options.semver.patch,
12068 });
12069 defer self.gpa.free(producer);
12070
12071 try identification_block.writeAbbrev(Identification.Version{ .string = producer });
12072 try identification_block.writeAbbrev(Identification.Epoch{ .epoch = 0 });
12073
12074 try identification_block.end();
12075 }
12076
12077 // MODULE_BLOCK
12078 {
12079 const Module = IR.Module;
12080 var module_block = try bitcode.enterTopBlock(Module);
12081
12082 try module_block.writeAbbrev(Module.Version{});
12083
12084 if (self.target_triple.slice(self)) |triple| {
12085 try module_block.writeAbbrev(Module.String{
12086 .code = 2,
12087 .string = triple,
12088 });
12089 }
12090
12091 if (self.data_layout.slice(self)) |data_layout| {
12092 try module_block.writeAbbrev(Module.String{
12093 .code = 3,
12094 .string = data_layout,
12095 });
12096 }
12097
12098 if (self.source_filename.slice(self)) |source_filename| {
12099 try module_block.writeAbbrev(Module.String{
12100 .code = 16,
12101 .string = source_filename,
12102 });
12103 }
12104
12105 if (self.module_asm.items.len != 0) {
12106 try module_block.writeAbbrev(Module.String{
12107 .code = 4,
12108 .string = self.module_asm.items,
12109 });
12110 }
12111
12112 // TYPE_BLOCK
12113 {
12114 var type_block = try module_block.enterSubBlock(IR.Type);
12115
12116 try type_block.writeAbbrev(IR.Type.NumEntry{ .num = @intCast(self.type_items.items.len) });
12117
12118 for (self.type_items.items, 0..) |item, i| {
12119 const ty: Type = @enumFromInt(i);
12120
12121 switch (item.tag) {
12122 .simple => try type_block.writeAbbrev(IR.Type.Simple{ .code = @truncate(item.data) }),
12123 .integer => try type_block.writeAbbrev(IR.Type.Integer{ .width = item.data }),
12124 .structure,
12125 .packed_structure,
12126 => |kind| {
12127 const is_packed = switch (kind) {
12128 .structure => false,
12129 .packed_structure => true,
12130 else => unreachable,
12131 };
12132 var extra = self.typeExtraDataTrail(Type.Structure, item.data);
12133 try type_block.writeAbbrev(IR.Type.StructAnon{
12134 .is_packed = is_packed,
12135 .types = extra.trail.next(extra.data.fields_len, Type, self),
12136 });
12137 },
12138 .named_structure => {
12139 const extra = self.typeExtraData(Type.NamedStructure, item.data);
12140 try type_block.writeAbbrev(IR.Type.StructName{
12141 .string = extra.id.slice(self).?,
12142 });
12143
12144 const real_struct = self.type_items.items[@intFromEnum(extra.body)];
12145 const is_packed: bool = switch (real_struct.tag) {
12146 .structure => false,
12147 .packed_structure => true,
12148 else => unreachable,
12149 };
12150
12151 var real_extra = self.typeExtraDataTrail(Type.Structure, real_struct.data);
12152 try type_block.writeAbbrev(IR.Type.StructNamed{
12153 .is_packed = is_packed,
12154 .types = real_extra.trail.next(real_extra.data.fields_len, Type, self),
12155 });
12156 },
12157 .array,
12158 .small_array,
12159 => try type_block.writeAbbrev(IR.Type.Array{
12160 .len = ty.aggregateLen(self),
12161 .child = ty.childType(self),
12162 }),
12163 .vector,
12164 .scalable_vector,
12165 => try type_block.writeAbbrev(IR.Type.Vector{
12166 .len = ty.aggregateLen(self),
12167 .child = ty.childType(self),
12168 }),
12169 .pointer => try type_block.writeAbbrev(IR.Type.Pointer{
12170 .addr_space = ty.pointerAddrSpace(self),
12171 }),
12172 .target => {
12173 var extra = self.typeExtraDataTrail(Type.Target, item.data);
12174 try type_block.writeAbbrev(IR.Type.StructName{
12175 .string = extra.data.name.slice(self).?,
12176 });
12177
12178 const types = extra.trail.next(extra.data.types_len, Type, self);
12179 const ints = extra.trail.next(extra.data.ints_len, u32, self);
12180
12181 try type_block.writeAbbrev(IR.Type.Target{
12182 .num_types = extra.data.types_len,
12183 .types = types,
12184 .ints = ints,
12185 });
12186 },
12187 .function, .vararg_function => |kind| {
12188 const is_vararg = switch (kind) {
12189 .function => false,
12190 .vararg_function => true,
12191 else => unreachable,
12192 };
12193 var extra = self.typeExtraDataTrail(Type.Function, item.data);
12194 try type_block.writeAbbrev(IR.Type.Function{
12195 .is_vararg = is_vararg,
12196 .return_type = extra.data.ret,
12197 .param_types = extra.trail.next(extra.data.params_len, Type, self),
12198 });
12199 },
12200 }
12201 }
12202
12203 try type_block.end();
12204 }
12205
12206 var attributes_set: std.AutoArrayHashMapUnmanaged(struct {
12207 attributes: Attributes,
12208 index: u32,
12209 }, void) = .{};
12210 defer attributes_set.deinit(self.gpa);
12211
12212 // PARAMATTR_GROUP_BLOCK
12213 {
12214 const ParamattrGroup = IR.ParamattrGroup;
12215
12216 var paramattr_group_block = try module_block.enterSubBlock(ParamattrGroup);
12217
12218 for (self.function_attributes_set.keys()) |func_attributes| {
12219 for (func_attributes.slice(self), 0..) |attributes, i| {
12220 const attributes_slice = attributes.slice(self);
12221 if (attributes_slice.len == 0) continue;
12222
12223 const attr_gop = try attributes_set.getOrPut(self.gpa, .{
12224 .attributes = attributes,
12225 .index = @intCast(i),
12226 });
12227
12228 if (attr_gop.found_existing) continue;
12229
12230 record.clearRetainingCapacity();
12231 try record.ensureUnusedCapacity(self.gpa, 2);
12232
12233 record.appendAssumeCapacity(attr_gop.index);
12234 record.appendAssumeCapacity(switch (i) {
12235 0 => 0xffffffff,
12236 else => i - 1,
12237 });
12238
12239 for (attributes_slice) |attr_index| {
12240 const kind = attr_index.getKind(self);
12241 switch (attr_index.toAttribute(self)) {
12242 .zeroext,
12243 .signext,
12244 .inreg,
12245 .@"noalias",
12246 .nocapture,
12247 .nofree,
12248 .nest,
12249 .returned,
12250 .nonnull,
12251 .swiftself,
12252 .swiftasync,
12253 .swifterror,
12254 .immarg,
12255 .noundef,
12256 .allocalign,
12257 .allocptr,
12258 .readnone,
12259 .readonly,
12260 .writeonly,
12261 .alwaysinline,
12262 .builtin,
12263 .cold,
12264 .convergent,
12265 .disable_sanitizer_information,
12266 .fn_ret_thunk_extern,
12267 .hot,
12268 .inlinehint,
12269 .jumptable,
12270 .minsize,
12271 .naked,
12272 .nobuiltin,
12273 .nocallback,
12274 .noduplicate,
12275 .noimplicitfloat,
12276 .@"noinline",
12277 .nomerge,
12278 .nonlazybind,
12279 .noprofile,
12280 .skipprofile,
12281 .noredzone,
12282 .noreturn,
12283 .norecurse,
12284 .willreturn,
12285 .nosync,
12286 .nounwind,
12287 .nosanitize_bounds,
12288 .nosanitize_coverage,
12289 .null_pointer_is_valid,
12290 .optforfuzzing,
12291 .optnone,
12292 .optsize,
12293 .returns_twice,
12294 .safestack,
12295 .sanitize_address,
12296 .sanitize_memory,
12297 .sanitize_thread,
12298 .sanitize_hwaddress,
12299 .sanitize_memtag,
12300 .speculative_load_hardening,
12301 .speculatable,
12302 .ssp,
12303 .sspstrong,
12304 .sspreq,
12305 .strictfp,
12306 .nocf_check,
12307 .shadowcallstack,
12308 .mustprogress,
12309 .no_sanitize_address,
12310 .no_sanitize_hwaddress,
12311 .sanitize_address_dyninit,
12312 => {
12313 try record.ensureUnusedCapacity(self.gpa, 2);
12314 record.appendAssumeCapacity(0);
12315 record.appendAssumeCapacity(@intFromEnum(kind));
12316 },
12317 .byval,
12318 .byref,
12319 .preallocated,
12320 .inalloca,
12321 .sret,
12322 .elementtype,
12323 => |ty| {
12324 try record.ensureUnusedCapacity(self.gpa, 3);
12325 record.appendAssumeCapacity(6);
12326 record.appendAssumeCapacity(@intFromEnum(kind));
12327 record.appendAssumeCapacity(@intFromEnum(ty));
12328 },
12329 .@"align",
12330 .alignstack,
12331 => |alignment| {
12332 try record.ensureUnusedCapacity(self.gpa, 3);
12333 record.appendAssumeCapacity(1);
12334 record.appendAssumeCapacity(@intFromEnum(kind));
12335 record.appendAssumeCapacity(alignment.toByteUnits() orelse 0);
12336 },
12337 .dereferenceable,
12338 .dereferenceable_or_null,
12339 => |size| {
12340 try record.ensureUnusedCapacity(self.gpa, 3);
12341 record.appendAssumeCapacity(1);
12342 record.appendAssumeCapacity(@intFromEnum(kind));
12343 record.appendAssumeCapacity(size);
12344 },
12345 .nofpclass => |fpclass| {
12346 try record.ensureUnusedCapacity(self.gpa, 3);
12347 record.appendAssumeCapacity(1);
12348 record.appendAssumeCapacity(@intFromEnum(kind));
12349 record.appendAssumeCapacity(@as(u32, @bitCast(fpclass)));
12350 },
12351 .allockind => |allockind| {
12352 try record.ensureUnusedCapacity(self.gpa, 3);
12353 record.appendAssumeCapacity(1);
12354 record.appendAssumeCapacity(@intFromEnum(kind));
12355 record.appendAssumeCapacity(@as(u32, @bitCast(allockind)));
12356 },
12357
12358 .allocsize => |allocsize| {
12359 try record.ensureUnusedCapacity(self.gpa, 3);
12360 record.appendAssumeCapacity(1);
12361 record.appendAssumeCapacity(@intFromEnum(kind));
12362 record.appendAssumeCapacity(@bitCast(allocsize.toLlvm()));
12363 },
12364 .memory => |memory| {
12365 try record.ensureUnusedCapacity(self.gpa, 3);
12366 record.appendAssumeCapacity(1);
12367 record.appendAssumeCapacity(@intFromEnum(kind));
12368 record.appendAssumeCapacity(@as(u32, @bitCast(memory)));
12369 },
12370 .uwtable => |uwtable| if (uwtable != .none) {
12371 try record.ensureUnusedCapacity(self.gpa, 3);
12372 record.appendAssumeCapacity(1);
12373 record.appendAssumeCapacity(@intFromEnum(kind));
12374 record.appendAssumeCapacity(@intFromEnum(uwtable));
12375 },
12376 .vscale_range => |vscale_range| {
12377 try record.ensureUnusedCapacity(self.gpa, 3);
12378 record.appendAssumeCapacity(1);
12379 record.appendAssumeCapacity(@intFromEnum(kind));
12380 record.appendAssumeCapacity(@bitCast(vscale_range.toLlvm()));
12381 },
12382 .string => |string_attr| {
12383 const string_attr_kind_slice = string_attr.kind.slice(self).?;
12384 const string_attr_value_slice = if (string_attr.value != .none)
12385 string_attr.value.slice(self).?
12386 else
12387 null;
12388
12389 try record.ensureUnusedCapacity(
12390 self.gpa,
12391 2 + string_attr_kind_slice.len + if (string_attr_value_slice) |slice| slice.len + 1 else 0,
12392 );
12393 record.appendAssumeCapacity(if (string_attr.value == .none) 3 else 4);
12394 for (string_attr.kind.slice(self).?) |c| {
12395 record.appendAssumeCapacity(c);
12396 }
12397 record.appendAssumeCapacity(0);
12398 if (string_attr_value_slice) |slice| {
12399 for (slice) |c| {
12400 record.appendAssumeCapacity(c);
12401 }
12402 record.appendAssumeCapacity(0);
12403 }
12404 },
12405 .none => unreachable,
12406 }
12407 }
12408
12409 try paramattr_group_block.writeUnabbrev(3, record.items);
12410 }
12411 }
12412
12413 try paramattr_group_block.end();
12414 }
12415
12416 // PARAMATTR_BLOCK
12417 {
12418 const Paramattr = IR.Paramattr;
12419 var paramattr_block = try module_block.enterSubBlock(Paramattr);
12420
12421 for (self.function_attributes_set.keys()) |func_attributes| {
12422 const func_attributes_slice = func_attributes.slice(self);
12423 record.clearRetainingCapacity();
12424 try record.ensureUnusedCapacity(self.gpa, func_attributes_slice.len);
12425 for (func_attributes_slice, 0..) |attributes, i| {
12426 const attributes_slice = attributes.slice(self);
12427 if (attributes_slice.len == 0) continue;
12428
12429 const group_index = attributes_set.getIndex(.{
12430 .attributes = attributes,
12431 .index = @intCast(i),
12432 }) orelse unreachable;
12433 record.appendAssumeCapacity(@intCast(group_index));
12434 }
12435
12436 try paramattr_block.writeAbbrev(Paramattr.Entry{ .group_indices = record.items });
12437 }
12438
12439 try paramattr_block.end();
12440 }
12441
12442 var globals = std.AutoArrayHashMapUnmanaged(Global.Index, void){};
12443 defer globals.deinit(self.gpa);
12444 try globals.ensureUnusedCapacity(
12445 self.gpa,
12446 self.variables.items.len +
12447 self.functions.items.len +
12448 self.aliases.items.len,
12449 );
12450
12451 for (self.variables.items) |variable| {
12452 if (variable.global.getReplacement(self) != .none) continue;
12453
12454 globals.putAssumeCapacity(variable.global, {});
12455 }
12456
12457 for (self.functions.items) |function| {
12458 if (function.global.getReplacement(self) != .none) continue;
12459
12460 globals.putAssumeCapacity(function.global, {});
12461 }
12462
12463 for (self.aliases.items) |alias| {
12464 if (alias.global.getReplacement(self) != .none) continue;
12465
12466 globals.putAssumeCapacity(alias.global, {});
12467 }
12468
12469 const ConstantAdapter = struct {
12470 const ConstantAdapter = @This();
12471 builder: *const Builder,
12472 globals: *const std.AutoArrayHashMapUnmanaged(Global.Index, void),
12473
12474 pub fn get(adapter: @This(), param: anytype, comptime field_name: []const u8) @TypeOf(param) {
12475 _ = field_name;
12476 return switch (@TypeOf(param)) {
12477 Constant => @enumFromInt(adapter.getConstantIndex(param)),
12478 else => param,
12479 };
12480 }
12481
12482 pub fn getConstantIndex(adapter: ConstantAdapter, constant: Constant) u32 {
12483 return switch (constant.unwrap()) {
12484 .constant => |c| c + adapter.numGlobals(),
12485 .global => |global| @intCast(adapter.globals.getIndex(global.unwrap(adapter.builder)).?),
12486 };
12487 }
12488
12489 pub fn numConstants(adapter: ConstantAdapter) u32 {
12490 return @intCast(adapter.globals.count() + adapter.builder.constant_items.len);
12491 }
12492
12493 pub fn numGlobals(adapter: ConstantAdapter) u32 {
12494 return @intCast(adapter.globals.count());
12495 }
12496 };
12497
12498 const constant_adapter = ConstantAdapter{
12499 .builder = self,
12500 .globals = &globals,
12501 };
12502
12503 // Globals
12504 {
12505 var section_map: std.AutoArrayHashMapUnmanaged(String, void) = .{};
12506 defer section_map.deinit(self.gpa);
12507 try section_map.ensureUnusedCapacity(self.gpa, globals.count());
12508
12509 for (self.variables.items) |variable| {
12510 if (variable.global.getReplacement(self) != .none) continue;
12511
12512 const section = blk: {
12513 if (variable.section == .none) break :blk 0;
12514 const gop = section_map.getOrPutAssumeCapacity(variable.section);
12515 if (!gop.found_existing) {
12516 try module_block.writeAbbrev(Module.String{
12517 .code = 5,
12518 .string = variable.section.slice(self) orelse unreachable,
12519 });
12520 }
12521 break :blk gop.index + 1;
12522 };
12523
12524 const initid = if (variable.init == .no_init)
12525 0
12526 else
12527 (constant_adapter.getConstantIndex(variable.init) + 1);
12528
12529 const strtab = variable.global.strtab(self);
12530
12531 const global = variable.global.ptrConst(self);
12532 try module_block.writeAbbrev(Module.Variable{
12533 .strtab_offset = strtab.offset,
12534 .strtab_size = strtab.size,
12535 .type_index = global.type,
12536 .is_const = .{
12537 .is_const = switch (variable.mutability) {
12538 .global => false,
12539 .constant => true,
12540 },
12541 .addr_space = global.addr_space,
12542 },
12543 .initid = initid,
12544 .linkage = global.linkage,
12545 .alignment = variable.alignment.toLlvm(),
12546 .section = section,
12547 .visibility = global.visibility,
12548 .thread_local = variable.thread_local,
12549 .unnamed_addr = global.unnamed_addr,
12550 .externally_initialized = global.externally_initialized,
12551 .dllstorageclass = global.dll_storage_class,
12552 .preemption = global.preemption,
12553 });
12554 }
12555
12556 for (self.functions.items) |func| {
12557 if (func.global.getReplacement(self) != .none) continue;
12558
12559 const section = blk: {
12560 if (func.section == .none) break :blk 0;
12561 const gop = section_map.getOrPutAssumeCapacity(func.section);
12562 if (!gop.found_existing) {
12563 try module_block.writeAbbrev(Module.String{
12564 .code = 5,
12565 .string = func.section.slice(self) orelse unreachable,
12566 });
12567 }
12568 break :blk gop.index + 1;
12569 };
12570
12571 const paramattr_index = if (self.function_attributes_set.getIndex(func.attributes)) |index|
12572 index + 1
12573 else
12574 0;
12575
12576 const strtab = func.global.strtab(self);
12577
12578 const global = func.global.ptrConst(self);
12579 try module_block.writeAbbrev(Module.Function{
12580 .strtab_offset = strtab.offset,
12581 .strtab_size = strtab.size,
12582 .type_index = global.type,
12583 .call_conv = func.call_conv,
12584 .is_proto = func.instructions.len == 0,
12585 .linkage = global.linkage,
12586 .paramattr = paramattr_index,
12587 .alignment = func.alignment.toLlvm(),
12588 .section = section,
12589 .visibility = global.visibility,
12590 .unnamed_addr = global.unnamed_addr,
12591 .dllstorageclass = global.dll_storage_class,
12592 .preemption = global.preemption,
12593 .addr_space = global.addr_space,
12594 });
12595 }
12596
12597 for (self.aliases.items) |alias| {
12598 if (alias.global.getReplacement(self) != .none) continue;
12599
12600 const strtab = alias.global.strtab(self);
12601
12602 const global = alias.global.ptrConst(self);
12603 try module_block.writeAbbrev(Module.Alias{
12604 .strtab_offset = strtab.offset,
12605 .strtab_size = strtab.size,
12606 .type_index = global.type,
12607 .addr_space = global.addr_space,
12608 .aliasee = constant_adapter.getConstantIndex(alias.aliasee),
12609 .linkage = global.linkage,
12610 .visibility = global.visibility,
12611 .thread_local = alias.thread_local,
12612 .unnamed_addr = global.unnamed_addr,
12613 .dllstorageclass = global.dll_storage_class,
12614 .preemption = global.preemption,
12615 });
12616 }
12617 }
12618
12619 // CONSTANTS_BLOCK
12620 {
12621 const Constants = IR.Constants;
12622 var constants_block = try module_block.enterSubBlock(Constants);
12623
12624 var current_type: Type = .none;
12625 const tags = self.constant_items.items(.tag);
12626 const datas = self.constant_items.items(.data);
12627 for (0..self.constant_items.len) |index| {
12628 record.clearRetainingCapacity();
12629 const constant: Constant = @enumFromInt(index);
12630 const constant_type = constant.typeOf(self);
12631 if (constant_type != current_type) {
12632 try constants_block.writeAbbrev(Constants.SetType{ .type_id = constant_type });
12633 current_type = constant_type;
12634 }
12635 const data = datas[index];
12636 switch (tags[index]) {
12637 .null,
12638 .zeroinitializer,
12639 .none,
12640 => try constants_block.writeAbbrev(Constants.Null{}),
12641 .undef => try constants_block.writeAbbrev(Constants.Undef{}),
12642 .poison => try constants_block.writeAbbrev(Constants.Poison{}),
12643 .positive_integer,
12644 .negative_integer,
12645 => |tag| {
12646 const extra: *align(@alignOf(std.math.big.Limb)) Constant.Integer =
12647 @ptrCast(self.constant_limbs.items[data..][0..Constant.Integer.limbs]);
12648 const limbs = self.constant_limbs
12649 .items[data + Constant.Integer.limbs ..][0..extra.limbs_len];
12650 const bigint = std.math.big.int.Const{
12651 .limbs = limbs,
12652 .positive = tag == .positive_integer,
12653 };
12654
12655 const bit_count = extra.type.scalarBits(self);
12656 if (bit_count <= 64) {
12657 const val = bigint.to(i64) catch unreachable;
12658 const emit_val = if (tag == .positive_integer)
12659 @shlWithOverflow(val, 1)[0]
12660 else
12661 (@shlWithOverflow(@addWithOverflow(~val, 1)[0], 1)[0] | 1);
12662 try constants_block.writeAbbrev(Constants.Integer{ .value = @bitCast(emit_val) });
12663 } else {
12664 const word_count = std.mem.alignForward(u24, bit_count, 64) / 64;
12665 try record.ensureUnusedCapacity(self.gpa, word_count);
12666 const buffer: [*]u8 = @ptrCast(record.items.ptr);
12667 bigint.writeTwosComplement(buffer[0..(word_count * 8)], .little);
12668
12669 const signed_buffer: [*]i64 = @ptrCast(record.items.ptr);
12670 for (signed_buffer[0..word_count], 0..) |val, i| {
12671 signed_buffer[i] = if (val >= 0)
12672 @shlWithOverflow(val, 1)[0]
12673 else
12674 (@shlWithOverflow(@addWithOverflow(~val, 1)[0], 1)[0] | 1);
12675 }
12676
12677 try constants_block.writeUnabbrev(5, record.items.ptr[0..word_count]);
12678 }
12679 },
12680 .half,
12681 .bfloat,
12682 => try constants_block.writeAbbrev(Constants.Half{ .value = @truncate(data) }),
12683 .float => try constants_block.writeAbbrev(Constants.Float{ .value = data }),
12684 .double => {
12685 const extra = self.constantExtraData(Constant.Double, data);
12686 try constants_block.writeAbbrev(Constants.Double{
12687 .value = (@as(u64, extra.hi) << 32) | extra.lo,
12688 });
12689 },
12690 .x86_fp80 => {
12691 const extra = self.constantExtraData(Constant.Fp80, data);
12692 try constants_block.writeAbbrev(Constants.Fp80{
12693 .lo = @as(u64, extra.lo_hi) << 32 | @as(u64, extra.lo_lo),
12694 .hi = @intCast(extra.hi),
12695 });
12696 },
12697 .fp128,
12698 .ppc_fp128,
12699 => {
12700 const extra = self.constantExtraData(Constant.Fp128, data);
12701 try constants_block.writeAbbrev(Constants.Fp128{
12702 .lo = @as(u64, extra.lo_hi) << 32 | @as(u64, extra.lo_lo),
12703 .hi = @as(u64, extra.hi_hi) << 32 | @as(u64, extra.hi_lo),
12704 });
12705 },
12706 .array,
12707 .vector,
12708 .structure,
12709 .packed_structure,
12710 => {
12711 var extra = self.constantExtraDataTrail(Constant.Aggregate, data);
12712 const len: u32 = @intCast(extra.data.type.aggregateLen(self));
12713 const values = extra.trail.next(len, Constant, self);
12714
12715 try constants_block.writeAbbrevAdapted(
12716 Constants.Aggregate{ .values = values },
12717 constant_adapter,
12718 );
12719 },
12720 .splat => {
12721 const ConstantsWriter = @TypeOf(constants_block);
12722 const extra = self.constantExtraData(Constant.Splat, data);
12723 const vector_len = extra.type.vectorLen(self);
12724 const c = constant_adapter.getConstantIndex(extra.value);
12725
12726 try bitcode.writeBits(
12727 ConstantsWriter.abbrevId(Constants.Aggregate),
12728 ConstantsWriter.abbrev_len,
12729 );
12730 try bitcode.writeVBR(vector_len, 6);
12731 for (0..vector_len) |_| {
12732 try bitcode.writeBits(c, Constants.Aggregate.ops[1].array_fixed);
12733 }
12734 },
12735 .string,
12736 .string_null,
12737 => {
12738 const str: String = @enumFromInt(data);
12739 if (str == .none) {
12740 try constants_block.writeAbbrev(Constants.Null{});
12741 } else {
12742 const slice = str.slice(self) orelse unreachable;
12743 switch (tags[index]) {
12744 .string => try constants_block.writeAbbrev(Constants.String{ .string = slice }),
12745 .string_null => try constants_block.writeAbbrev(Constants.CString{ .string = slice }),
12746 else => unreachable,
12747 }
12748 }
12749 },
12750 .bitcast,
12751 .inttoptr,
12752 .ptrtoint,
12753 .fptosi,
12754 .fptoui,
12755 .sitofp,
12756 .uitofp,
12757 .addrspacecast,
12758 .fptrunc,
12759 .trunc,
12760 .fpext,
12761 .sext,
12762 .zext,
12763 => |tag| {
12764 const extra = self.constantExtraData(Constant.Cast, data);
12765 try constants_block.writeAbbrevAdapted(Constants.Cast{
12766 .type_index = extra.type,
12767 .val = extra.val,
12768 .opcode = tag.toCastOpcode(),
12769 }, constant_adapter);
12770 },
12771 .add,
12772 .@"add nsw",
12773 .@"add nuw",
12774 .sub,
12775 .@"sub nsw",
12776 .@"sub nuw",
12777 .mul,
12778 .@"mul nsw",
12779 .@"mul nuw",
12780 .shl,
12781 .lshr,
12782 .ashr,
12783 .@"and",
12784 .@"or",
12785 .xor,
12786 => |tag| {
12787 const extra = self.constantExtraData(Constant.Binary, data);
12788 try constants_block.writeAbbrevAdapted(Constants.Binary{
12789 .opcode = tag.toBinaryOpcode(),
12790 .lhs = extra.lhs,
12791 .rhs = extra.rhs,
12792 }, constant_adapter);
12793 },
12794 .icmp,
12795 .fcmp,
12796 => {
12797 const extra = self.constantExtraData(Constant.Compare, data);
12798 try constants_block.writeAbbrevAdapted(Constants.Cmp{
12799 .ty = extra.lhs.typeOf(self),
12800 .lhs = extra.lhs,
12801 .rhs = extra.rhs,
12802 .pred = extra.cond,
12803 }, constant_adapter);
12804 },
12805 .extractelement => {
12806 const extra = self.constantExtraData(Constant.ExtractElement, data);
12807 try constants_block.writeAbbrevAdapted(Constants.ExtractElement{
12808 .val_type = extra.val.typeOf(self),
12809 .val = extra.val,
12810 .index_type = extra.index.typeOf(self),
12811 .index = extra.index,
12812 }, constant_adapter);
12813 },
12814 .insertelement => {
12815 const extra = self.constantExtraData(Constant.InsertElement, data);
12816 try constants_block.writeAbbrevAdapted(Constants.InsertElement{
12817 .val = extra.val,
12818 .elem = extra.elem,
12819 .index_type = extra.index.typeOf(self),
12820 .index = extra.index,
12821 }, constant_adapter);
12822 },
12823 .shufflevector => {
12824 const extra = self.constantExtraData(Constant.ShuffleVector, data);
12825 const ty = constant.typeOf(self);
12826 const lhs_type = extra.lhs.typeOf(self);
12827 // Check if instruction is widening, truncating or not
12828 if (ty == lhs_type) {
12829 try constants_block.writeAbbrevAdapted(Constants.ShuffleVector{
12830 .lhs = extra.lhs,
12831 .rhs = extra.rhs,
12832 .mask = extra.mask,
12833 }, constant_adapter);
12834 } else {
12835 try constants_block.writeAbbrevAdapted(Constants.ShuffleVectorEx{
12836 .ty = ty,
12837 .lhs = extra.lhs,
12838 .rhs = extra.rhs,
12839 .mask = extra.mask,
12840 }, constant_adapter);
12841 }
12842 },
12843 .getelementptr,
12844 .@"getelementptr inbounds",
12845 => |tag| {
12846 var extra = self.constantExtraDataTrail(Constant.GetElementPtr, data);
12847 const indices = extra.trail.next(extra.data.info.indices_len, Constant, self);
12848 try record.ensureUnusedCapacity(self.gpa, 1 + 2 + 2 * indices.len);
12849
12850 record.appendAssumeCapacity(@intFromEnum(extra.data.type));
12851
12852 record.appendAssumeCapacity(@intFromEnum(extra.data.base.typeOf(self)));
12853 record.appendAssumeCapacity(constant_adapter.getConstantIndex(extra.data.base));
12854
12855 for (indices) |i| {
12856 record.appendAssumeCapacity(@intFromEnum(i.typeOf(self)));
12857 record.appendAssumeCapacity(constant_adapter.getConstantIndex(i));
12858 }
12859
12860 try constants_block.writeUnabbrev(switch (tag) {
12861 .getelementptr => 12,
12862 .@"getelementptr inbounds" => 20,
12863 else => unreachable,
12864 }, record.items);
12865 },
12866 .@"asm",
12867 .@"asm sideeffect",
12868 .@"asm alignstack",
12869 .@"asm sideeffect alignstack",
12870 .@"asm inteldialect",
12871 .@"asm sideeffect inteldialect",
12872 .@"asm alignstack inteldialect",
12873 .@"asm sideeffect alignstack inteldialect",
12874 .@"asm unwind",
12875 .@"asm sideeffect unwind",
12876 .@"asm alignstack unwind",
12877 .@"asm sideeffect alignstack unwind",
12878 .@"asm inteldialect unwind",
12879 .@"asm sideeffect inteldialect unwind",
12880 .@"asm alignstack inteldialect unwind",
12881 .@"asm sideeffect alignstack inteldialect unwind",
12882 => |tag| {
12883 const extra = self.constantExtraData(Constant.Assembly, data);
12884
12885 const assembly_slice = extra.assembly.slice(self) orelse unreachable;
12886 const constraints_slice = extra.constraints.slice(self) orelse unreachable;
12887
12888 try record.ensureUnusedCapacity(self.gpa, 4 + assembly_slice.len + constraints_slice.len);
12889
12890 record.appendAssumeCapacity(@intFromEnum(extra.type));
12891 record.appendAssumeCapacity(switch (tag) {
12892 .@"asm" => 0,
12893 .@"asm sideeffect" => 0b0001,
12894 .@"asm sideeffect alignstack" => 0b0011,
12895 .@"asm sideeffect inteldialect" => 0b0101,
12896 .@"asm sideeffect alignstack inteldialect" => 0b0111,
12897 .@"asm sideeffect unwind" => 0b1001,
12898 .@"asm sideeffect alignstack unwind" => 0b1011,
12899 .@"asm sideeffect inteldialect unwind" => 0b1101,
12900 .@"asm sideeffect alignstack inteldialect unwind" => 0b1111,
12901 .@"asm alignstack" => 0b0010,
12902 .@"asm inteldialect" => 0b0100,
12903 .@"asm alignstack inteldialect" => 0b0110,
12904 .@"asm unwind" => 0b1000,
12905 .@"asm alignstack unwind" => 0b1010,
12906 .@"asm inteldialect unwind" => 0b1100,
12907 .@"asm alignstack inteldialect unwind" => 0b1110,
12908 else => unreachable,
12909 });
12910
12911 record.appendAssumeCapacity(assembly_slice.len);
12912 for (assembly_slice) |c| record.appendAssumeCapacity(c);
12913
12914 record.appendAssumeCapacity(constraints_slice.len);
12915 for (constraints_slice) |c| record.appendAssumeCapacity(c);
12916
12917 try constants_block.writeUnabbrev(30, record.items);
12918 },
12919 .blockaddress => {
12920 const extra = self.constantExtraData(Constant.BlockAddress, data);
12921 try constants_block.writeAbbrev(Constants.BlockAddress{
12922 .type_id = extra.function.typeOf(self),
12923 .function = constant_adapter.getConstantIndex(extra.function.toConst(self)),
12924 .block = @intFromEnum(extra.block),
12925 });
12926 },
12927 .dso_local_equivalent,
12928 .no_cfi,
12929 => |tag| {
12930 const function: Function.Index = @enumFromInt(data);
12931 try constants_block.writeAbbrev(Constants.DsoLocalEquivalentOrNoCfi{
12932 .code = switch (tag) {
12933 .dso_local_equivalent => 27,
12934 .no_cfi => 29,
12935 else => unreachable,
12936 },
12937 .type_id = function.typeOf(self),
12938 .function = constant_adapter.getConstantIndex(function.toConst(self)),
12939 });
12940 },
12941 }
12942 }
12943
12944 try constants_block.end();
12945 }
12946
12947 // FUNCTION_BLOCKS
12948 {
12949 const FunctionAdapter = struct {
12950 constant_adapter: ConstantAdapter,
12951 func: *const Function,
12952 instruction_index: u32 = 0,
12953
12954 pub fn init(
12955 const_adapter: ConstantAdapter,
12956 func: *const Function,
12957 ) @This() {
12958 return .{
12959 .constant_adapter = const_adapter,
12960 .func = func,
12961 .instruction_index = 0,
12962 };
12963 }
12964
12965 pub fn get(adapter: @This(), value: anytype, comptime field_name: []const u8) @TypeOf(value) {
12966 _ = field_name;
12967 const Ty = @TypeOf(value);
12968 return switch (Ty) {
12969 Value => @enumFromInt(adapter.getOffsetValueIndex(value)),
12970 Constant => @enumFromInt(adapter.getOffsetConstantIndex(value)),
12971 FunctionAttributes => @enumFromInt(if (value == .none) 0 else (adapter.constant_adapter.builder.function_attributes_set.getIndex(value) orelse unreachable) + 1),
12972 else => value,
12973 };
12974 }
12975
12976 pub fn getValueIndex(adapter: @This(), value: Value) u32 {
12977 return @intCast(switch (value.unwrap()) {
12978 .instruction => |instruction| instruction.valueIndex(adapter.func) + adapter.firstInstr(),
12979 .constant => |constant| adapter.constant_adapter.getConstantIndex(constant),
12980 });
12981 }
12982
12983 pub fn getOffsetValueIndex(adapter: @This(), value: Value) u32 {
12984 return adapter.offset() - adapter.getValueIndex(value);
12985 }
12986
12987 pub fn getOffsetValueSignedIndex(adapter: @This(), value: Value) i32 {
12988 const signed_offset: i32 = @intCast(adapter.offset());
12989 const signed_value: i32 = @intCast(adapter.getValueIndex(value));
12990 return signed_offset - signed_value;
12991 }
12992
12993 pub fn getOffsetConstantIndex(adapter: @This(), constant: Constant) u32 {
12994 return adapter.offset() - adapter.constant_adapter.getConstantIndex(constant);
12995 }
12996
12997 pub fn offset(adapter: @This()) u32 {
12998 return @as(
12999 Function.Instruction.Index,
13000 @enumFromInt(adapter.instruction_index),
13001 ).valueIndex(adapter.func) + adapter.firstInstr();
13002 }
13003
13004 fn firstInstr(adapter: @This()) u32 {
13005 return adapter.constant_adapter.numConstants();
13006 }
13007
13008 pub fn next(adapter: *@This()) void {
13009 adapter.instruction_index += 1;
13010 }
13011 };
13012
13013 for (self.functions.items, 0..) |func, func_index| {
13014 const FunctionBlock = IR.FunctionBlock;
13015 if (func.global.getReplacement(self) != .none) continue;
13016
13017 if (func.instructions.len == 0) continue;
13018
13019 var function_block = try module_block.enterSubBlock(FunctionBlock);
13020
13021 try function_block.writeAbbrev(FunctionBlock.DeclareBlocks{ .num_blocks = func.blocks.len });
13022
13023 var adapter = FunctionAdapter.init(constant_adapter, &func);
13024
13025 const tags = func.instructions.items(.tag);
13026 const datas = func.instructions.items(.data);
13027
13028 var block_incoming_len: u32 = undefined;
13029 for (0..func.instructions.len) |instr_index| {
13030 const tag = tags[instr_index];
13031
13032 record.clearRetainingCapacity();
13033
13034 switch (tag) {
13035 .block => block_incoming_len = datas[instr_index],
13036 .arg => {},
13037 .@"unreachable" => try function_block.writeAbbrev(FunctionBlock.Unreachable{}),
13038 .call,
13039 .@"musttail call",
13040 .@"notail call",
13041 .@"tail call",
13042 => |kind| {
13043 var extra = func.extraDataTrail(Function.Instruction.Call, datas[instr_index]);
13044
13045 const call_conv = extra.data.info.call_conv;
13046 const args = extra.trail.next(extra.data.args_len, Value, &func);
13047 try function_block.writeAbbrevAdapted(FunctionBlock.Call{
13048 .attributes = extra.data.attributes,
13049 .call_type = switch (kind) {
13050 .call => .{ .call_conv = call_conv },
13051 .@"tail call" => .{ .tail = true, .call_conv = call_conv },
13052 .@"musttail call" => .{ .must_tail = true, .call_conv = call_conv },
13053 .@"notail call" => .{ .no_tail = true, .call_conv = call_conv },
13054 else => unreachable,
13055 },
13056 .type_id = extra.data.ty,
13057 .callee = extra.data.callee,
13058 .args = args,
13059 }, adapter);
13060 },
13061 .@"call fast",
13062 .@"musttail call fast",
13063 .@"notail call fast",
13064 .@"tail call fast",
13065 => |kind| {
13066 var extra = func.extraDataTrail(Function.Instruction.Call, datas[instr_index]);
13067
13068 const call_conv = extra.data.info.call_conv;
13069 const args = extra.trail.next(extra.data.args_len, Value, &func);
13070 try function_block.writeAbbrevAdapted(FunctionBlock.CallFast{
13071 .attributes = extra.data.attributes,
13072 .call_type = switch (kind) {
13073 .call => .{ .call_conv = call_conv },
13074 .@"tail call" => .{ .tail = true, .call_conv = call_conv },
13075 .@"musttail call" => .{ .must_tail = true, .call_conv = call_conv },
13076 .@"notail call" => .{ .no_tail = true, .call_conv = call_conv },
13077 else => unreachable,
13078 },
13079 .fast_math = .{},
13080 .type_id = extra.data.ty,
13081 .callee = extra.data.callee,
13082 .args = args,
13083 }, adapter);
13084 },
13085 .add,
13086 .@"add nsw",
13087 .@"add nuw",
13088 .@"add nuw nsw",
13089 .@"and",
13090 .fadd,
13091 .fdiv,
13092 .fmul,
13093 .mul,
13094 .@"mul nsw",
13095 .@"mul nuw",
13096 .@"mul nuw nsw",
13097 .frem,
13098 .fsub,
13099 .sdiv,
13100 .@"sdiv exact",
13101 .sub,
13102 .@"sub nsw",
13103 .@"sub nuw",
13104 .@"sub nuw nsw",
13105 .udiv,
13106 .@"udiv exact",
13107 .xor,
13108 .shl,
13109 .@"shl nsw",
13110 .@"shl nuw",
13111 .@"shl nuw nsw",
13112 .lshr,
13113 .@"lshr exact",
13114 .@"or",
13115 .urem,
13116 .srem,
13117 .ashr,
13118 .@"ashr exact",
13119 => {
13120 const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
13121 try function_block.writeAbbrev(FunctionBlock.Binary{
13122 .opcode = tag.toBinaryOpcode(),
13123 .lhs = adapter.getOffsetValueIndex(extra.lhs),
13124 .rhs = adapter.getOffsetValueIndex(extra.rhs),
13125 });
13126 },
13127 .@"fadd fast",
13128 .@"fdiv fast",
13129 .@"fmul fast",
13130 .@"frem fast",
13131 .@"fsub fast",
13132 => {
13133 const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
13134 try function_block.writeAbbrev(FunctionBlock.BinaryFast{
13135 .opcode = tag.toBinaryOpcode(),
13136 .lhs = adapter.getOffsetValueIndex(extra.lhs),
13137 .rhs = adapter.getOffsetValueIndex(extra.rhs),
13138 .fast_math = .{},
13139 });
13140 },
13141 .alloca,
13142 .@"alloca inalloca",
13143 => |kind| {
13144 const extra = func.extraData(Function.Instruction.Alloca, datas[instr_index]);
13145 const alignment = extra.info.alignment.toLlvm();
13146 try function_block.writeAbbrev(FunctionBlock.Alloca{
13147 .inst_type = extra.type,
13148 .len_type = if (extra.len == .none) .i1 else extra.len.typeOf(@enumFromInt(func_index), self),
13149 .len_value = adapter.getValueIndex(if (extra.len == .none) Constant.true.toValue() else extra.len),
13150 .flags = .{
13151 .align_lower = @truncate(alignment),
13152 .inalloca = kind == .@"alloca inalloca",
13153 .explicit_type = true,
13154 .swift_error = false,
13155 .align_upper = @truncate(alignment << 5),
13156 },
13157 });
13158 },
13159 .bitcast,
13160 .inttoptr,
13161 .ptrtoint,
13162 .fptosi,
13163 .fptoui,
13164 .sitofp,
13165 .uitofp,
13166 .addrspacecast,
13167 .fptrunc,
13168 .trunc,
13169 .fpext,
13170 .sext,
13171 .zext,
13172 => {
13173 const extra = func.extraData(Function.Instruction.Cast, datas[instr_index]);
13174 try function_block.writeAbbrev(FunctionBlock.Cast{
13175 .val = adapter.getOffsetValueIndex(extra.val),
13176 .type_index = extra.type,
13177 .opcode = tag.toCastOpcode(),
13178 });
13179 },
13180 .@"fcmp false",
13181 .@"fcmp oeq",
13182 .@"fcmp oge",
13183 .@"fcmp ogt",
13184 .@"fcmp ole",
13185 .@"fcmp olt",
13186 .@"fcmp one",
13187 .@"fcmp ord",
13188 .@"fcmp true",
13189 .@"fcmp ueq",
13190 .@"fcmp uge",
13191 .@"fcmp ugt",
13192 .@"fcmp ule",
13193 .@"fcmp ult",
13194 .@"fcmp une",
13195 .@"fcmp uno",
13196 .@"icmp eq",
13197 .@"icmp ne",
13198 .@"icmp sge",
13199 .@"icmp sgt",
13200 .@"icmp sle",
13201 .@"icmp slt",
13202 .@"icmp uge",
13203 .@"icmp ugt",
13204 .@"icmp ule",
13205 .@"icmp ult",
13206 => {
13207 const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
13208 try function_block.writeAbbrev(FunctionBlock.Cmp{
13209 .lhs = adapter.getOffsetValueIndex(extra.lhs),
13210 .rhs = adapter.getOffsetValueIndex(extra.rhs),
13211 .pred = tag.toCmpPredicate(),
13212 });
13213 },
13214 .@"fcmp fast false",
13215 .@"fcmp fast oeq",
13216 .@"fcmp fast oge",
13217 .@"fcmp fast ogt",
13218 .@"fcmp fast ole",
13219 .@"fcmp fast olt",
13220 .@"fcmp fast one",
13221 .@"fcmp fast ord",
13222 .@"fcmp fast true",
13223 .@"fcmp fast ueq",
13224 .@"fcmp fast uge",
13225 .@"fcmp fast ugt",
13226 .@"fcmp fast ule",
13227 .@"fcmp fast ult",
13228 .@"fcmp fast une",
13229 .@"fcmp fast uno",
13230 => {
13231 const extra = func.extraData(Function.Instruction.Binary, datas[instr_index]);
13232 try function_block.writeAbbrev(FunctionBlock.CmpFast{
13233 .lhs = adapter.getOffsetValueIndex(extra.lhs),
13234 .rhs = adapter.getOffsetValueIndex(extra.rhs),
13235 .pred = tag.toCmpPredicate(),
13236 .fast_math = .{},
13237 });
13238 },
13239 .fneg => try function_block.writeAbbrev(FunctionBlock.FNeg{
13240 .val = adapter.getOffsetValueIndex(@enumFromInt(datas[instr_index])),
13241 }),
13242 .@"fneg fast" => try function_block.writeAbbrev(FunctionBlock.FNegFast{
13243 .val = adapter.getOffsetValueIndex(@enumFromInt(datas[instr_index])),
13244 .fast_math = .{},
13245 }),
13246 .extractvalue => {
13247 var extra = func.extraDataTrail(Function.Instruction.ExtractValue, datas[instr_index]);
13248 const indices = extra.trail.next(extra.data.indices_len, u32, &func);
13249 try function_block.writeAbbrev(FunctionBlock.ExtractValue{
13250 .val = adapter.getOffsetValueIndex(extra.data.val),
13251 .indices = indices,
13252 });
13253 },
13254 .insertvalue => {
13255 var extra = func.extraDataTrail(Function.Instruction.InsertValue, datas[instr_index]);
13256 const indices = extra.trail.next(extra.data.indices_len, u32, &func);
13257 try function_block.writeAbbrev(FunctionBlock.InsertValue{
13258 .val = adapter.getOffsetValueIndex(extra.data.val),
13259 .elem = adapter.getOffsetValueIndex(extra.data.elem),
13260 .indices = indices,
13261 });
13262 },
13263 .extractelement => {
13264 const extra = func.extraData(Function.Instruction.ExtractElement, datas[instr_index]);
13265 try function_block.writeAbbrev(FunctionBlock.ExtractElement{
13266 .val = adapter.getOffsetValueIndex(extra.val),
13267 .index = adapter.getOffsetValueIndex(extra.index),
13268 });
13269 },
13270 .insertelement => {
13271 const extra = func.extraData(Function.Instruction.InsertElement, datas[instr_index]);
13272 try function_block.writeAbbrev(FunctionBlock.InsertElement{
13273 .val = adapter.getOffsetValueIndex(extra.val),
13274 .elem = adapter.getOffsetValueIndex(extra.elem),
13275 .index = adapter.getOffsetValueIndex(extra.index),
13276 });
13277 },
13278 .select => {
13279 const extra = func.extraData(Function.Instruction.Select, datas[instr_index]);
13280 try function_block.writeAbbrev(FunctionBlock.Select{
13281 .lhs = adapter.getOffsetValueIndex(extra.lhs),
13282 .rhs = adapter.getOffsetValueIndex(extra.rhs),
13283 .cond = adapter.getOffsetValueIndex(extra.cond),
13284 });
13285 },
13286 .@"select fast" => {
13287 const extra = func.extraData(Function.Instruction.Select, datas[instr_index]);
13288 try function_block.writeAbbrev(FunctionBlock.SelectFast{
13289 .lhs = adapter.getOffsetValueIndex(extra.lhs),
13290 .rhs = adapter.getOffsetValueIndex(extra.rhs),
13291 .cond = adapter.getOffsetValueIndex(extra.cond),
13292 .fast_math = .{},
13293 });
13294 },
13295 .shufflevector => {
13296 const extra = func.extraData(Function.Instruction.ShuffleVector, datas[instr_index]);
13297 try function_block.writeAbbrev(FunctionBlock.ShuffleVector{
13298 .lhs = adapter.getOffsetValueIndex(extra.lhs),
13299 .rhs = adapter.getOffsetValueIndex(extra.rhs),
13300 .mask = adapter.getOffsetValueIndex(extra.mask),
13301 });
13302 },
13303 .getelementptr,
13304 .@"getelementptr inbounds",
13305 => {
13306 var extra = func.extraDataTrail(Function.Instruction.GetElementPtr, datas[instr_index]);
13307 const indices = extra.trail.next(extra.data.indices_len, Value, &func);
13308 try function_block.writeAbbrevAdapted(
13309 FunctionBlock.GetElementPtr{
13310 .is_inbounds = tag == .@"getelementptr inbounds",
13311 .type_index = extra.data.type,
13312 .base = extra.data.base,
13313 .indices = indices,
13314 },
13315 adapter,
13316 );
13317 },
13318 .load => {
13319 const extra = func.extraData(Function.Instruction.Load, datas[instr_index]);
13320 try function_block.writeAbbrev(FunctionBlock.Load{
13321 .ptr = adapter.getOffsetValueIndex(extra.ptr),
13322 .ty = extra.type,
13323 .alignment = extra.info.alignment.toLlvm(),
13324 .is_volatile = extra.info.access_kind == .@"volatile",
13325 });
13326 },
13327 .@"load atomic" => {
13328 const extra = func.extraData(Function.Instruction.Load, datas[instr_index]);
13329 try function_block.writeAbbrev(FunctionBlock.LoadAtomic{
13330 .ptr = adapter.getOffsetValueIndex(extra.ptr),
13331 .ty = extra.type,
13332 .alignment = extra.info.alignment.toLlvm(),
13333 .is_volatile = extra.info.access_kind == .@"volatile",
13334 .success_ordering = extra.info.success_ordering,
13335 .sync_scope = extra.info.sync_scope,
13336 });
13337 },
13338 .store => {
13339 const extra = func.extraData(Function.Instruction.Store, datas[instr_index]);
13340 try function_block.writeAbbrev(FunctionBlock.Store{
13341 .ptr = adapter.getOffsetValueIndex(extra.ptr),
13342 .val = adapter.getOffsetValueIndex(extra.val),
13343 .alignment = extra.info.alignment.toLlvm(),
13344 .is_volatile = extra.info.access_kind == .@"volatile",
13345 });
13346 },
13347 .@"store atomic" => {
13348 const extra = func.extraData(Function.Instruction.Store, datas[instr_index]);
13349 try function_block.writeAbbrev(FunctionBlock.StoreAtomic{
13350 .ptr = adapter.getOffsetValueIndex(extra.ptr),
13351 .val = adapter.getOffsetValueIndex(extra.val),
13352 .alignment = extra.info.alignment.toLlvm(),
13353 .is_volatile = extra.info.access_kind == .@"volatile",
13354 .success_ordering = extra.info.success_ordering,
13355 .sync_scope = extra.info.sync_scope,
13356 });
13357 },
13358 .br => {
13359 try function_block.writeAbbrev(FunctionBlock.BrUnconditional{
13360 .block = datas[instr_index],
13361 });
13362 },
13363 .br_cond => {
13364 const extra = func.extraData(Function.Instruction.BrCond, datas[instr_index]);
13365 try function_block.writeAbbrev(FunctionBlock.BrConditional{
13366 .then_block = @intFromEnum(extra.then),
13367 .else_block = @intFromEnum(extra.@"else"),
13368 .condition = adapter.getOffsetValueIndex(extra.cond),
13369 });
13370 },
13371 .@"switch" => {
13372 var extra = func.extraDataTrail(Function.Instruction.Switch, datas[instr_index]);
13373
13374 try record.ensureUnusedCapacity(self.gpa, 3 + extra.data.cases_len * 2);
13375
13376 // Conditional type
13377 record.appendAssumeCapacity(@intFromEnum(extra.data.val.typeOf(@enumFromInt(func_index), self)));
13378
13379 // Conditional
13380 record.appendAssumeCapacity(adapter.getOffsetValueIndex(extra.data.val));
13381
13382 // Default block
13383 record.appendAssumeCapacity(@intFromEnum(extra.data.default));
13384
13385 const vals = extra.trail.next(extra.data.cases_len, Constant, &func);
13386 const blocks = extra.trail.next(extra.data.cases_len, Function.Block.Index, &func);
13387 for (vals, blocks) |val, block| {
13388 record.appendAssumeCapacity(adapter.constant_adapter.getConstantIndex(val));
13389 record.appendAssumeCapacity(@intFromEnum(block));
13390 }
13391
13392 try function_block.writeUnabbrev(12, record.items);
13393 },
13394 .va_arg => {
13395 const extra = func.extraData(Function.Instruction.VaArg, datas[instr_index]);
13396 try function_block.writeAbbrev(FunctionBlock.VaArg{
13397 .list_type = extra.list.typeOf(@enumFromInt(func_index), self),
13398 .list = adapter.getOffsetValueIndex(extra.list),
13399 .type = extra.type,
13400 });
13401 },
13402 .phi,
13403 .@"phi fast",
13404 => |kind| {
13405 var extra = func.extraDataTrail(Function.Instruction.Phi, datas[instr_index]);
13406 const vals = extra.trail.next(block_incoming_len, Value, &func);
13407 const blocks = extra.trail.next(block_incoming_len, Function.Block.Index, &func);
13408
13409 try record.ensureUnusedCapacity(
13410 self.gpa,
13411 1 + block_incoming_len * 2 + @intFromBool(kind == .@"phi fast"),
13412 );
13413
13414 record.appendAssumeCapacity(@intFromEnum(extra.data.type));
13415
13416 for (vals, blocks) |val, block| {
13417 const offset_value = adapter.getOffsetValueSignedIndex(val);
13418 const abs_value: u32 = @intCast(@abs(offset_value));
13419 const signed_vbr = if (offset_value > 0) abs_value << 1 else ((abs_value << 1) | 1);
13420 record.appendAssumeCapacity(signed_vbr);
13421 record.appendAssumeCapacity(@intFromEnum(block));
13422 }
13423
13424 if (kind == .@"phi fast") record.appendAssumeCapacity(@as(u8, @bitCast(FastMath{})));
13425
13426 try function_block.writeUnabbrev(16, record.items);
13427 },
13428 .ret => try function_block.writeAbbrev(FunctionBlock.Ret{
13429 .val = adapter.getOffsetValueIndex(@enumFromInt(datas[instr_index])),
13430 }),
13431 .@"ret void" => try function_block.writeAbbrev(FunctionBlock.RetVoid{}),
13432 .atomicrmw => {
13433 const extra = func.extraData(Function.Instruction.AtomicRmw, datas[instr_index]);
13434 try function_block.writeAbbrev(FunctionBlock.AtomicRmw{
13435 .ptr = adapter.getOffsetValueIndex(extra.ptr),
13436 .val = adapter.getOffsetValueIndex(extra.val),
13437 .operation = extra.info.atomic_rmw_operation,
13438 .is_volatile = extra.info.access_kind == .@"volatile",
13439 .success_ordering = extra.info.success_ordering,
13440 .sync_scope = extra.info.sync_scope,
13441 .alignment = extra.info.alignment.toLlvm(),
13442 });
13443 },
13444 .cmpxchg,
13445 .@"cmpxchg weak",
13446 => |kind| {
13447 const extra = func.extraData(Function.Instruction.CmpXchg, datas[instr_index]);
13448
13449 try function_block.writeAbbrev(FunctionBlock.CmpXchg{
13450 .ptr = adapter.getOffsetValueIndex(extra.ptr),
13451 .cmp = adapter.getOffsetValueIndex(extra.cmp),
13452 .new = adapter.getOffsetValueIndex(extra.new),
13453 .is_volatile = extra.info.access_kind == .@"volatile",
13454 .success_ordering = extra.info.success_ordering,
13455 .sync_scope = extra.info.sync_scope,
13456 .failure_ordering = extra.info.failure_ordering,
13457 .is_weak = kind == .@"cmpxchg weak",
13458 .alignment = extra.info.alignment.toLlvm(),
13459 });
13460 },
13461 .fence => {
13462 const info: MemoryAccessInfo = @bitCast(datas[instr_index]);
13463 try function_block.writeAbbrev(FunctionBlock.Fence{
13464 .ordering = info.success_ordering,
13465 .sync_scope = info.sync_scope,
13466 });
13467 },
13468 }
13469
13470 adapter.next();
13471 }
13472
13473 // VALUE_SYMTAB
13474 if (!self.strip) {
13475 const ValueSymbolTable = IR.FunctionValueSymbolTable;
13476
13477 var value_symtab_block = try function_block.enterSubBlock(ValueSymbolTable);
13478
13479 for (func.blocks, 0..) |block, block_index| {
13480 const name = block.instruction.name(&func);
13481
13482 if (name == .none or name == .empty) continue;
13483
13484 try value_symtab_block.writeAbbrev(ValueSymbolTable.BlockEntry{
13485 .value_id = @intCast(block_index),
13486 .string = name.slice(self).?,
13487 });
13488 }
13489
13490 // TODO: Emit non block entries if the builder ever starts assigning names to non blocks
13491
13492 try value_symtab_block.end();
13493 }
13494
13495 try function_block.end();
13496 }
13497 }
13498
13499 try module_block.end();
13500 }
13501
13502 // STRTAB_BLOCK
13503 {
13504 const Strtab = IR.Strtab;
13505 var strtab_block = try bitcode.enterTopBlock(Strtab);
13506
13507 try strtab_block.writeAbbrev(Strtab.Blob{ .blob = self.string_bytes.items });
13508
13509 try strtab_block.end();
13510 }
13511
13512 return bitcode.toSlice();
13513}
13514
12045const assert = std.debug.assert;13515const assert = std.debug.assert;
12046const build_options = @import("build_options");13516const build_options = @import("build_options");
12047const builtin = @import("builtin");13517const builtin = @import("builtin");
...@@ -12052,5 +13522,8 @@ else...@@ -12052,5 +13522,8 @@ else
12052const log = std.log.scoped(.llvm);13522const log = std.log.scoped(.llvm);
12053const std = @import("std");13523const std = @import("std");
1205413524
13525const bitcode_writer = @import("bitcode_writer.zig");
13526const IR = @import("IR.zig");
13527
12055const Allocator = std.mem.Allocator;13528const Allocator = std.mem.Allocator;
12056const Builder = @This();13529const Builder = @This();