authorgravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-10 10:52:17-04:00
committergravatar for jacobly@ziglang.orgJacob Young <jacobly@ziglang.org> 2023-07-19 23:38:40-04:00
logff8a49448c70ffe73826c7987522ed63fddd654f
tree36107c8b3539051f4539836d09145e231f260293
parent2cb52235b91f7e4bf5a4ebf77a5008adfc30c8b9

llvm: finish converting `lowerValue`


5 files changed, 2751 insertions(+), 902 deletions(-)

src/Module.zig+4-8
......@@ -835,10 +835,6 @@ pub const Decl = struct {
835835 assert(decl.has_tv);
836836 return @as(u32, @intCast(decl.alignment.toByteUnitsOptional() orelse decl.ty.abiAlignment(mod)));
837837 }
838
839 pub fn intern(decl: *Decl, mod: *Module) Allocator.Error!void {
840 decl.val = (try decl.val.intern(decl.ty, mod)).toValue();
841 }
842838};
843839
844840/// This state is attached to every Decl when Module emit_h is non-null.
......@@ -4204,7 +4200,7 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void {
42044200 try wip_captures.finalize();
42054201 for (comptime_mutable_decls.items) |decl_index| {
42064202 const decl = mod.declPtr(decl_index);
4207 try decl.intern(mod);
4203 _ = try decl.internValue(mod);
42084204 }
42094205 new_decl.analysis = .complete;
42104206 } else |err| switch (err) {
......@@ -4315,7 +4311,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool {
43154311 try wip_captures.finalize();
43164312 for (comptime_mutable_decls.items) |ct_decl_index| {
43174313 const ct_decl = mod.declPtr(ct_decl_index);
4318 try ct_decl.intern(mod);
4314 _ = try ct_decl.internValue(mod);
43194315 }
43204316 const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = 0 };
43214317 const section_src: LazySrcLoc = .{ .node_offset_var_decl_section = 0 };
......@@ -5362,7 +5358,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
53625358 try wip_captures.finalize();
53635359 for (comptime_mutable_decls.items) |ct_decl_index| {
53645360 const ct_decl = mod.declPtr(ct_decl_index);
5365 try ct_decl.intern(mod);
5361 _ = try ct_decl.internValue(mod);
53665362 }
53675363
53685364 // Copy the block into place and mark that as the main block.
......@@ -6369,7 +6365,7 @@ pub fn markDeclAlive(mod: *Module, decl: *Decl) Allocator.Error!void {
63696365 if (decl.alive) return;
63706366 decl.alive = true;
63716367
6372 try decl.intern(mod);
6368 _ = try decl.internValue(mod);
63736369
63746370 // This is the first time we are marking this Decl alive. We must
63756371 // therefore recurse into its value and mark any Decl it references
src/Sema.zig+4-4
......@@ -3899,7 +3899,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
38993899 try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
39003900
39013901 const decl = mod.declPtr(decl_index);
3902 if (iac.is_const) try decl.intern(mod);
3902 if (iac.is_const) _ = try decl.internValue(mod);
39033903 const final_elem_ty = decl.ty;
39043904 const final_ptr_ty = try mod.ptrType(.{
39053905 .child = final_elem_ty.toIntern(),
......@@ -33577,7 +33577,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
3357733577 try wip_captures.finalize();
3357833578 for (comptime_mutable_decls.items) |ct_decl_index| {
3357933579 const ct_decl = mod.declPtr(ct_decl_index);
33580 try ct_decl.intern(mod);
33580 _ = try ct_decl.internValue(mod);
3358133581 }
3358233582 } else {
3358333583 if (fields_bit_sum > std.math.maxInt(u16)) {
......@@ -34645,7 +34645,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
3464534645 try wip_captures.finalize();
3464634646 for (comptime_mutable_decls.items) |ct_decl_index| {
3464734647 const ct_decl = mod.declPtr(ct_decl_index);
34648 try ct_decl.intern(mod);
34648 _ = try ct_decl.internValue(mod);
3464934649 }
3465034650
3465134651 struct_obj.have_field_inits = true;
......@@ -34744,7 +34744,7 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
3474434744 try wip_captures.finalize();
3474534745 for (comptime_mutable_decls.items) |ct_decl_index| {
3474634746 const ct_decl = mod.declPtr(ct_decl_index);
34747 try ct_decl.intern(mod);
34747 _ = try ct_decl.internValue(mod);
3474834748 }
3474934749
3475034750 try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len);
src/codegen/llvm.zig+814-703
......@@ -579,7 +579,7 @@ pub const Object = struct {
579579 /// The LLVM global table which holds the names corresponding to Zig errors.
580580 /// Note that the values are not added until flushModule, when all errors in
581581 /// the compilation are known.
582 error_name_table: ?*llvm.Value,
582 error_name_table: Builder.Variable.Index,
583583 /// This map is usually very close to empty. It tracks only the cases when a
584584 /// second extern Decl could not be emitted with the correct name due to a
585585 /// name collision.
......@@ -763,7 +763,7 @@ pub const Object = struct {
763763 .named_enum_map = .{},
764764 .type_map = .{},
765765 .di_type_map = .{},
766 .error_name_table = null,
766 .error_name_table = .none,
767767 .extern_collisions = .{},
768768 .null_opt_addr = null,
769769 };
......@@ -803,51 +803,85 @@ pub const Object = struct {
803803 return slice.ptr;
804804 }
805805
806 fn genErrorNameTable(o: *Object) !void {
806 fn genErrorNameTable(o: *Object) Allocator.Error!void {
807807 // If o.error_name_table is null, there was no instruction that actually referenced the error table.
808 const error_name_table_ptr_global = o.error_name_table orelse return;
808 const error_name_table_ptr_global = o.error_name_table;
809 if (error_name_table_ptr_global == .none) return;
809810
810811 const mod = o.module;
811812
813 const error_name_list = mod.global_error_set.keys();
814 const llvm_errors = try mod.gpa.alloc(Builder.Constant, error_name_list.len);
815 defer mod.gpa.free(llvm_errors);
816
812817 // TODO: Address space
813 const llvm_usize_ty = try o.lowerType(Type.usize);
814 const llvm_slice_ty = (try o.builder.structType(.normal, &.{ .ptr, llvm_usize_ty })).toLlvm(&o.builder);
815818 const slice_ty = Type.slice_const_u8_sentinel_0;
816819 const slice_alignment = slice_ty.abiAlignment(mod);
820 const llvm_usize_ty = try o.lowerType(Type.usize);
821 const llvm_slice_ty = try o.lowerType(slice_ty);
822 const llvm_table_ty = try o.builder.arrayType(error_name_list.len, llvm_slice_ty);
817823
818 const error_name_list = mod.global_error_set.keys();
819 const llvm_errors = try mod.gpa.alloc(*llvm.Value, error_name_list.len);
820 defer mod.gpa.free(llvm_errors);
821
822 llvm_errors[0] = llvm_slice_ty.getUndef();
824 llvm_errors[0] = try o.builder.undefConst(llvm_slice_ty);
823825 for (llvm_errors[1..], error_name_list[1..]) |*llvm_error, name_nts| {
824 const name = mod.intern_pool.stringToSlice(name_nts);
825 const str_init = o.context.constString(name.ptr, @as(c_uint, @intCast(name.len)), .False);
826 const str_global = o.llvm_module.addGlobal(str_init.typeOf(), "");
827 str_global.setInitializer(str_init);
826 const name = try o.builder.string(mod.intern_pool.stringToSlice(name_nts));
827 const str_init = try o.builder.stringNullConst(name);
828 const str_ty = str_init.typeOf(&o.builder);
829 const str_global = o.llvm_module.addGlobal(str_ty.toLlvm(&o.builder), "");
830 str_global.setInitializer(str_init.toLlvm(&o.builder));
828831 str_global.setLinkage(.Private);
829832 str_global.setGlobalConstant(.True);
830833 str_global.setUnnamedAddr(.True);
831834 str_global.setAlignment(1);
832835
833 const slice_fields = [_]*llvm.Value{
834 str_global,
835 (try o.builder.intConst(llvm_usize_ty, name.len)).toLlvm(&o.builder),
836 var global = Builder.Global{
837 .linkage = .private,
838 .unnamed_addr = .unnamed_addr,
839 .type = str_ty,
840 .alignment = comptime Builder.Alignment.fromByteUnits(1),
841 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
836842 };
837 llvm_error.* = llvm_slice_ty.constNamedStruct(&slice_fields, slice_fields.len);
838 }
843 var variable = Builder.Variable{
844 .global = @enumFromInt(o.builder.globals.count()),
845 .mutability = .constant,
846 .init = str_init,
847 };
848 try o.builder.llvm_globals.append(o.gpa, str_global);
849 const str_global_index = try o.builder.addGlobal(.none, global);
850 try o.builder.variables.append(o.gpa, variable);
839851
840 const error_name_table_init = llvm_slice_ty.constArray(llvm_errors.ptr, @as(c_uint, @intCast(error_name_list.len)));
852 llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
853 str_global_index.toConst(),
854 try o.builder.intConst(llvm_usize_ty, name.toSlice(&o.builder).?.len),
855 });
856 }
841857
842 const error_name_table_global = o.llvm_module.addGlobal(error_name_table_init.typeOf(), "");
843 error_name_table_global.setInitializer(error_name_table_init);
858 const error_name_table_init = try o.builder.arrayConst(llvm_table_ty, llvm_errors);
859 const error_name_table_global = o.llvm_module.addGlobal(llvm_table_ty.toLlvm(&o.builder), "");
860 error_name_table_global.setInitializer(error_name_table_init.toLlvm(&o.builder));
844861 error_name_table_global.setLinkage(.Private);
845862 error_name_table_global.setGlobalConstant(.True);
846863 error_name_table_global.setUnnamedAddr(.True);
847864 error_name_table_global.setAlignment(slice_alignment); // TODO: Dont hardcode
848865
866 var global = Builder.Global{
867 .linkage = .private,
868 .unnamed_addr = .unnamed_addr,
869 .type = llvm_table_ty,
870 .alignment = Builder.Alignment.fromByteUnits(slice_alignment),
871 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
872 };
873 var variable = Builder.Variable{
874 .global = @enumFromInt(o.builder.globals.count()),
875 .mutability = .constant,
876 .init = error_name_table_init,
877 };
878 try o.builder.llvm_globals.append(o.gpa, error_name_table_global);
879 _ = try o.builder.addGlobal(.none, global);
880 try o.builder.variables.append(o.gpa, variable);
881
849882 const error_name_table_ptr = error_name_table_global;
850 error_name_table_ptr_global.setInitializer(error_name_table_ptr);
883 error_name_table_ptr_global.ptr(&o.builder).init = variable.global.toConst();
884 error_name_table_ptr_global.toLlvm(&o.builder).setInitializer(error_name_table_ptr);
851885 }
852886
853887 fn genCmpLtErrorsLenFunction(object: *Object) !void {
......@@ -1116,9 +1150,9 @@ pub const Object = struct {
11161150 .err_msg = null,
11171151 };
11181152
1119 const function_index = try o.resolveLlvmFunction(decl_index);
1120 const function = function_index.ptr(&o.builder);
1121 const llvm_func = function.global.toLlvm(&o.builder);
1153 const function = try o.resolveLlvmFunction(decl_index);
1154 const global = function.ptrConst(&o.builder).global;
1155 const llvm_func = global.toLlvm(&o.builder);
11221156
11231157 if (func.analysis(ip).is_noinline) {
11241158 o.addFnAttr(llvm_func, "noinline");
......@@ -1155,8 +1189,10 @@ pub const Object = struct {
11551189 o.addFnAttrString(llvm_func, "no-stack-arg-probe", "");
11561190 }
11571191
1158 if (ip.stringToSliceUnwrap(decl.@"linksection")) |section|
1192 if (ip.stringToSliceUnwrap(decl.@"linksection")) |section| {
1193 global.ptr(&o.builder).section = try o.builder.string(section);
11591194 llvm_func.setSection(section);
1195 }
11601196
11611197 // Remove all the basic blocks of a function in order to start over, generating
11621198 // LLVM IR from an empty function body.
......@@ -1166,7 +1202,7 @@ pub const Object = struct {
11661202
11671203 const builder = o.context.createBuilder();
11681204
1169 function.body = {};
1205 function.ptr(&o.builder).body = {};
11701206 const entry_block = o.context.appendBasicBlock(llvm_func, "Entry");
11711207 builder.positionBuilderAtEnd(entry_block);
11721208
......@@ -1487,8 +1523,8 @@ pub const Object = struct {
14871523 const gpa = mod.gpa;
14881524 // If the module does not already have the function, we ignore this function call
14891525 // because we call `updateDeclExports` at the end of `updateFunc` and `updateDecl`.
1490 const global_index = self.decl_map.get(decl_index) orelse return;
1491 const llvm_global = global_index.toLlvm(&self.builder);
1526 const global = self.decl_map.get(decl_index) orelse return;
1527 const llvm_global = global.toLlvm(&self.builder);
14921528 const decl = mod.declPtr(decl_index);
14931529 if (decl.isExtern(mod)) {
14941530 const decl_name = decl_name: {
......@@ -1511,18 +1547,17 @@ pub const Object = struct {
15111547 }
15121548 }
15131549
1514 try global_index.rename(&self.builder, decl_name);
1515 const decl_name_slice = decl_name.toSlice(&self.builder).?;
1516 const global = global_index.ptr(&self.builder);
1517 global.unnamed_addr = .default;
1550 try global.rename(&self.builder, decl_name);
1551 global.ptr(&self.builder).unnamed_addr = .default;
15181552 llvm_global.setUnnamedAddr(.False);
1519 global.linkage = .external;
1553 global.ptr(&self.builder).linkage = .external;
15201554 llvm_global.setLinkage(.External);
15211555 if (mod.wantDllExports()) {
1522 global.dll_storage_class = .default;
1556 global.ptr(&self.builder).dll_storage_class = .default;
15231557 llvm_global.setDLLStorageClass(.Default);
15241558 }
15251559 if (self.di_map.get(decl)) |di_node| {
1560 const decl_name_slice = decl_name.toSlice(&self.builder).?;
15261561 if (try decl.isFunction(mod)) {
15271562 const di_func = @as(*llvm.DISubprogram, @ptrCast(di_node));
15281563 const linkage_name = llvm.MDString.get(self.context, decl_name_slice.ptr, decl_name_slice.len);
......@@ -1533,21 +1568,31 @@ pub const Object = struct {
15331568 di_global.replaceLinkageName(linkage_name);
15341569 }
15351570 }
1536 if (decl.val.getVariable(mod)) |variable| {
1537 if (variable.is_threadlocal) {
1571 if (decl.val.getVariable(mod)) |decl_var| {
1572 if (decl_var.is_threadlocal) {
1573 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1574 .generaldynamic;
15381575 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
15391576 } else {
1577 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1578 .default;
15401579 llvm_global.setThreadLocalMode(.NotThreadLocal);
15411580 }
1542 if (variable.is_weak_linkage) {
1581 if (decl_var.is_weak_linkage) {
1582 global.ptr(&self.builder).linkage = .extern_weak;
15431583 llvm_global.setLinkage(.ExternalWeak);
15441584 }
15451585 }
1586 global.ptr(&self.builder).updateAttributes();
15461587 } else if (exports.len != 0) {
15471588 const exp_name = try self.builder.string(mod.intern_pool.stringToSlice(exports[0].opts.name));
1548 try global_index.rename(&self.builder, exp_name);
1589 try global.rename(&self.builder, exp_name);
1590 global.ptr(&self.builder).unnamed_addr = .default;
15491591 llvm_global.setUnnamedAddr(.False);
1550 if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.DLLExport);
1592 if (mod.wantDllExports()) {
1593 global.ptr(&self.builder).dll_storage_class = .dllexport;
1594 llvm_global.setDLLStorageClass(.DLLExport);
1595 }
15511596 if (self.di_map.get(decl)) |di_node| {
15521597 const exp_name_slice = exp_name.toSlice(&self.builder).?;
15531598 if (try decl.isFunction(mod)) {
......@@ -1562,23 +1607,45 @@ pub const Object = struct {
15621607 }
15631608 switch (exports[0].opts.linkage) {
15641609 .Internal => unreachable,
1565 .Strong => llvm_global.setLinkage(.External),
1566 .Weak => llvm_global.setLinkage(.WeakODR),
1567 .LinkOnce => llvm_global.setLinkage(.LinkOnceODR),
1610 .Strong => {
1611 global.ptr(&self.builder).linkage = .external;
1612 llvm_global.setLinkage(.External);
1613 },
1614 .Weak => {
1615 global.ptr(&self.builder).linkage = .weak_odr;
1616 llvm_global.setLinkage(.WeakODR);
1617 },
1618 .LinkOnce => {
1619 global.ptr(&self.builder).linkage = .linkonce_odr;
1620 llvm_global.setLinkage(.LinkOnceODR);
1621 },
15681622 }
15691623 switch (exports[0].opts.visibility) {
1570 .default => llvm_global.setVisibility(.Default),
1571 .hidden => llvm_global.setVisibility(.Hidden),
1572 .protected => llvm_global.setVisibility(.Protected),
1624 .default => {
1625 global.ptr(&self.builder).visibility = .default;
1626 llvm_global.setVisibility(.Default);
1627 },
1628 .hidden => {
1629 global.ptr(&self.builder).visibility = .hidden;
1630 llvm_global.setVisibility(.Hidden);
1631 },
1632 .protected => {
1633 global.ptr(&self.builder).visibility = .protected;
1634 llvm_global.setVisibility(.Protected);
1635 },
15731636 }
15741637 if (mod.intern_pool.stringToSliceUnwrap(exports[0].opts.section)) |section| {
1638 global.ptr(&self.builder).section = try self.builder.string(section);
15751639 llvm_global.setSection(section);
15761640 }
1577 if (decl.val.getVariable(mod)) |variable| {
1578 if (variable.is_threadlocal) {
1641 if (decl.val.getVariable(mod)) |decl_var| {
1642 if (decl_var.is_threadlocal) {
1643 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1644 .generaldynamic;
15791645 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
15801646 }
15811647 }
1648 global.ptr(&self.builder).updateAttributes();
15821649
15831650 // If a Decl is exported more than one time (which is rare),
15841651 // we add aliases for all but the first export.
......@@ -1602,18 +1669,28 @@ pub const Object = struct {
16021669 }
16031670 } else {
16041671 const fqn = try self.builder.string(mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)));
1605 try global_index.rename(&self.builder, fqn);
1672 try global.rename(&self.builder, fqn);
1673 global.ptr(&self.builder).linkage = .internal;
16061674 llvm_global.setLinkage(.Internal);
1607 if (mod.wantDllExports()) llvm_global.setDLLStorageClass(.Default);
1675 if (mod.wantDllExports()) {
1676 global.ptr(&self.builder).dll_storage_class = .default;
1677 llvm_global.setDLLStorageClass(.Default);
1678 }
1679 global.ptr(&self.builder).unnamed_addr = .unnamed_addr;
16081680 llvm_global.setUnnamedAddr(.True);
1609 if (decl.val.getVariable(mod)) |variable| {
1681 if (decl.val.getVariable(mod)) |decl_var| {
16101682 const single_threaded = mod.comp.bin_file.options.single_threaded;
1611 if (variable.is_threadlocal and !single_threaded) {
1683 if (decl_var.is_threadlocal and !single_threaded) {
1684 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1685 .generaldynamic;
16121686 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
16131687 } else {
1688 global.ptrConst(&self.builder).kind.variable.ptr(&self.builder).thread_local =
1689 .default;
16141690 llvm_global.setThreadLocalMode(.NotThreadLocal);
16151691 }
16161692 }
1693 global.ptr(&self.builder).updateAttributes();
16171694 }
16181695 }
16191696
......@@ -2658,31 +2735,44 @@ pub const Object = struct {
26582735 const mod = o.module;
26592736 const target = mod.getTarget();
26602737 const ty = try mod.intern(.{ .opt_type = .usize_type });
2661 const null_opt_usize = try mod.intern(.{ .opt = .{
2738
2739 const llvm_init = try o.lowerValue(try mod.intern(.{ .opt = .{
26622740 .ty = ty,
26632741 .val = .none,
2664 } });
2665
2666 const llvm_init = try o.lowerValue(.{
2667 .ty = ty.toType(),
2668 .val = null_opt_usize.toValue(),
2669 });
2742 } }));
2743 const llvm_ty = llvm_init.typeOf(&o.builder);
26702744 const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target);
26712745 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target);
2672 const global = o.llvm_module.addGlobalInAddressSpace(
2673 llvm_init.typeOf(),
2746 const llvm_alignment = ty.toType().abiAlignment(mod);
2747 const llvm_global = o.llvm_module.addGlobalInAddressSpace(
2748 llvm_ty.toLlvm(&o.builder),
26742749 "",
26752750 @intFromEnum(llvm_actual_addrspace),
26762751 );
2677 global.setLinkage(.Internal);
2678 global.setUnnamedAddr(.True);
2679 global.setAlignment(ty.toType().abiAlignment(mod));
2680 global.setInitializer(llvm_init);
2752 llvm_global.setLinkage(.Internal);
2753 llvm_global.setUnnamedAddr(.True);
2754 llvm_global.setAlignment(llvm_alignment);
2755 llvm_global.setInitializer(llvm_init.toLlvm(&o.builder));
2756
2757 var global = Builder.Global{
2758 .linkage = .internal,
2759 .unnamed_addr = .unnamed_addr,
2760 .type = llvm_ty,
2761 .alignment = Builder.Alignment.fromByteUnits(llvm_alignment),
2762 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
2763 };
2764 var variable = Builder.Variable{
2765 .global = @enumFromInt(o.builder.globals.count()),
2766 .init = llvm_init,
2767 };
2768 try o.builder.llvm_globals.append(o.gpa, llvm_global);
2769 _ = try o.builder.addGlobal(.none, global);
2770 try o.builder.variables.append(o.gpa, variable);
26812771
26822772 const addrspace_casted_global = if (llvm_wanted_addrspace != llvm_actual_addrspace)
2683 global.constAddrSpaceCast(o.context.pointerType(@intFromEnum(llvm_wanted_addrspace)))
2773 llvm_global.constAddrSpaceCast((try o.builder.ptrType(llvm_wanted_addrspace)).toLlvm(&o.builder))
26842774 else
2685 global;
2775 llvm_global;
26862776
26872777 o.null_opt_addr = addrspace_casted_global;
26882778 return addrspace_casted_global;
......@@ -2691,7 +2781,7 @@ pub const Object = struct {
26912781 /// If the llvm function does not exist, create it.
26922782 /// Note that this can be called before the function's semantic analysis has
26932783 /// completed, so if any attributes rely on that, they must be done in updateFunc, not here.
2694 fn resolveLlvmFunction(o: *Object, decl_index: Module.Decl.Index) !Builder.Function.Index {
2784 fn resolveLlvmFunction(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Function.Index {
26952785 const mod = o.module;
26962786 const gpa = o.gpa;
26972787 const decl = mod.declPtr(decl_index);
......@@ -2722,7 +2812,9 @@ pub const Object = struct {
27222812
27232813 const is_extern = decl.isExtern(mod);
27242814 if (!is_extern) {
2815 global.linkage = .internal;
27252816 llvm_fn.setLinkage(.Internal);
2817 global.unnamed_addr = .unnamed_addr;
27262818 llvm_fn.setUnnamedAddr(.True);
27272819 } else {
27282820 if (target.isWasm()) {
......@@ -2767,7 +2859,8 @@ pub const Object = struct {
27672859 }
27682860
27692861 if (fn_info.alignment.toByteUnitsOptional()) |a| {
2770 llvm_fn.setAlignment(@as(c_uint, @intCast(a)));
2862 global.alignment = Builder.Alignment.fromByteUnits(a);
2863 llvm_fn.setAlignment(@intCast(a));
27712864 }
27722865
27732866 // Function attributes that are independent of analysis results of the function body.
......@@ -2864,9 +2957,9 @@ pub const Object = struct {
28642957 }
28652958 }
28662959
2867 fn resolveGlobalDecl(o: *Object, decl_index: Module.Decl.Index) Error!Builder.Object.Index {
2960 fn resolveGlobalDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Variable.Index {
28682961 const gop = try o.decl_map.getOrPut(o.gpa, decl_index);
2869 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.object;
2962 if (gop.found_existing) return gop.value_ptr.ptr(&o.builder).kind.variable;
28702963 errdefer assert(o.decl_map.remove(decl_index));
28712964
28722965 const mod = o.module;
......@@ -2880,9 +2973,9 @@ pub const Object = struct {
28802973 var global = Builder.Global{
28812974 .addr_space = toLlvmGlobalAddressSpace(decl.@"addrspace", target),
28822975 .type = try o.lowerType(decl.ty),
2883 .kind = .{ .object = @enumFromInt(o.builder.objects.items.len) },
2976 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
28842977 };
2885 var object = Builder.Object{
2978 var variable = Builder.Variable{
28862979 .global = @enumFromInt(o.builder.globals.count()),
28872980 };
28882981
......@@ -2903,16 +2996,16 @@ pub const Object = struct {
29032996 llvm_global.setUnnamedAddr(.False);
29042997 global.linkage = .external;
29052998 llvm_global.setLinkage(.External);
2906 if (decl.val.getVariable(mod)) |variable| {
2999 if (decl.val.getVariable(mod)) |decl_var| {
29073000 const single_threaded = mod.comp.bin_file.options.single_threaded;
2908 if (variable.is_threadlocal and !single_threaded) {
2909 object.thread_local = .generaldynamic;
3001 if (decl_var.is_threadlocal and !single_threaded) {
3002 variable.thread_local = .generaldynamic;
29103003 llvm_global.setThreadLocalMode(.GeneralDynamicTLSModel);
29113004 } else {
2912 object.thread_local = .default;
3005 variable.thread_local = .default;
29133006 llvm_global.setThreadLocalMode(.NotThreadLocal);
29143007 }
2915 if (variable.is_weak_linkage) {
3008 if (decl_var.is_weak_linkage) {
29163009 global.linkage = .extern_weak;
29173010 llvm_global.setLinkage(.ExternalWeak);
29183011 }
......@@ -2926,17 +3019,8 @@ pub const Object = struct {
29263019
29273020 try o.builder.llvm_globals.append(o.gpa, llvm_global);
29283021 gop.value_ptr.* = try o.builder.addGlobal(name, global);
2929 try o.builder.objects.append(o.gpa, object);
2930 return global.kind.object;
2931 }
2932
2933 fn isUnnamedType(o: *Object, ty: Type, val: *llvm.Value) bool {
2934 // Once `lowerType` succeeds, successive calls to it with the same Zig type
2935 // are guaranteed to succeed. So if a call to `lowerType` fails here it means
2936 // it is the first time lowering the type, which means the value can't possible
2937 // have that type.
2938 const llvm_ty = (o.lowerType(ty) catch return true).toLlvm(&o.builder);
2939 return val.typeOf() != llvm_ty;
3022 try o.builder.variables.append(o.gpa, variable);
3023 return global.kind.variable;
29403024 }
29413025
29423026 fn lowerType(o: *Object, t: Type) Allocator.Error!Builder.Type {
......@@ -3069,14 +3153,17 @@ pub const Object = struct {
30693153 => unreachable,
30703154 else => switch (mod.intern_pool.indexToKey(t.toIntern())) {
30713155 .int_type => |int_type| try o.builder.intType(int_type.bits),
3072 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
3073 .One, .Many, .C => try o.builder.ptrType(
3156 .ptr_type => |ptr_type| type: {
3157 const ptr_ty = try o.builder.ptrType(
30743158 toLlvmAddressSpace(ptr_type.flags.address_space, target),
3075 ),
3076 .Slice => try o.builder.structType(.normal, &.{
3077 .ptr,
3078 try o.lowerType(Type.usize),
3079 }),
3159 );
3160 break :type switch (ptr_type.flags.size) {
3161 .One, .Many, .C => ptr_ty,
3162 .Slice => try o.builder.structType(.normal, &.{
3163 ptr_ty,
3164 try o.lowerType(Type.usize),
3165 }),
3166 };
30803167 },
30813168 .array_type => |array_type| o.builder.arrayType(
30823169 array_type.len + @intFromBool(array_type.sentinel != .none),
......@@ -3094,13 +3181,16 @@ pub const Object = struct {
30943181 if (t.optionalReprIsPayload(mod)) return payload_ty;
30953182
30963183 comptime assert(optional_layout_version == 3);
3097 var fields_buf: [3]Builder.Type = .{ payload_ty, .i8, .none };
3184 var fields: [3]Builder.Type = .{ payload_ty, .i8, undefined };
3185 var fields_len: usize = 2;
30983186 const offset = child_ty.toType().abiSize(mod) + 1;
30993187 const abi_size = t.abiSize(mod);
3100 const padding = abi_size - offset;
3101 if (padding == 0) return o.builder.structType(.normal, fields_buf[0..2]);
3102 fields_buf[2] = try o.builder.arrayType(padding, .i8);
3103 return o.builder.structType(.normal, fields_buf[0..3]);
3188 const padding_len = abi_size - offset;
3189 if (padding_len > 0) {
3190 fields[2] = try o.builder.arrayType(padding_len, .i8);
3191 fields_len = 3;
3192 }
3193 return o.builder.structType(.normal, fields[0..fields_len]);
31043194 },
31053195 .anyframe_type => @panic("TODO implement lowerType for AnyFrame types"),
31063196 .error_union_type => |error_union_type| {
......@@ -3115,30 +3205,30 @@ pub const Object = struct {
31153205 const payload_size = error_union_type.payload_type.toType().abiSize(mod);
31163206 const error_size = Type.err_int.abiSize(mod);
31173207
3118 var fields_buf: [3]Builder.Type = undefined;
3119 if (error_align > payload_align) {
3120 fields_buf[0] = error_type;
3121 fields_buf[1] = payload_type;
3208 var fields: [3]Builder.Type = undefined;
3209 var fields_len: usize = 2;
3210 const padding_len = if (error_align > payload_align) pad: {
3211 fields[0] = error_type;
3212 fields[1] = payload_type;
31223213 const payload_end =
31233214 std.mem.alignForward(u64, error_size, payload_align) +
31243215 payload_size;
31253216 const abi_size = std.mem.alignForward(u64, payload_end, error_align);
3126 const padding = abi_size - payload_end;
3127 if (padding == 0) return o.builder.structType(.normal, fields_buf[0..2]);
3128 fields_buf[2] = try o.builder.arrayType(padding, .i8);
3129 return o.builder.structType(.normal, fields_buf[0..3]);
3130 } else {
3131 fields_buf[0] = payload_type;
3132 fields_buf[1] = error_type;
3217 break :pad abi_size - payload_end;
3218 } else pad: {
3219 fields[0] = payload_type;
3220 fields[1] = error_type;
31333221 const error_end =
31343222 std.mem.alignForward(u64, payload_size, error_align) +
31353223 error_size;
31363224 const abi_size = std.mem.alignForward(u64, error_end, payload_align);
3137 const padding = abi_size - error_end;
3138 if (padding == 0) return o.builder.structType(.normal, fields_buf[0..2]);
3139 fields_buf[2] = try o.builder.arrayType(padding, .i8);
3140 return o.builder.structType(.normal, fields_buf[0..3]);
3225 break :pad abi_size - error_end;
3226 };
3227 if (padding_len > 0) {
3228 fields[2] = try o.builder.arrayType(padding_len, .i8);
3229 fields_len = 3;
31413230 }
3231 return o.builder.structType(.normal, fields[0..fields_len]);
31423232 },
31433233 .simple_type => unreachable,
31443234 .struct_type => |struct_type| {
......@@ -3371,6 +3461,7 @@ pub const Object = struct {
33713461 fn lowerTypeFn(o: *Object, fn_info: InternPool.Key.FuncType) Allocator.Error!Builder.Type {
33723462 const mod = o.module;
33733463 const ip = &mod.intern_pool;
3464 const target = mod.getTarget();
33743465 const ret_ty = try lowerFnRetTy(o, fn_info);
33753466
33763467 var llvm_params = std.ArrayListUnmanaged(Builder.Type){};
......@@ -3404,7 +3495,11 @@ pub const Object = struct {
34043495 ));
34053496 },
34063497 .slice => {
3407 try llvm_params.appendSlice(o.gpa, &.{ .ptr, try o.lowerType(Type.usize) });
3498 const param_ty = fn_info.param_types.get(ip)[it.zig_index - 1].toType();
3499 try llvm_params.appendSlice(o.gpa, &.{
3500 try o.builder.ptrType(toLlvmAddressSpace(param_ty.ptrAddressSpace(mod), target)),
3501 try o.lowerType(Type.usize),
3502 });
34083503 },
34093504 .multiple_llvm_types => {
34103505 try llvm_params.appendSlice(o.gpa, it.types_buffer[0..it.types_len]);
......@@ -3433,20 +3528,23 @@ pub const Object = struct {
34333528 );
34343529 }
34353530
3436 fn lowerValue(o: *Object, arg_tv: TypedValue) Error!*llvm.Value {
3531 fn lowerValue(o: *Object, arg_val: InternPool.Index) Error!Builder.Constant {
34373532 const mod = o.module;
3438 const gpa = o.gpa;
34393533 const target = mod.getTarget();
3440 var tv = arg_tv;
3441 switch (mod.intern_pool.indexToKey(tv.val.toIntern())) {
3442 .runtime_value => |rt| tv.val = rt.val.toValue(),
3534
3535 var val = arg_val.toValue();
3536 const arg_val_key = mod.intern_pool.indexToKey(arg_val);
3537 switch (arg_val_key) {
3538 .runtime_value => |rt| val = rt.val.toValue(),
34433539 else => {},
34443540 }
3445 if (tv.val.isUndefDeep(mod)) {
3446 return (try o.lowerType(tv.ty)).toLlvm(&o.builder).getUndef();
3541 if (val.isUndefDeep(mod)) {
3542 return o.builder.undefConst(try o.lowerType(arg_val_key.typeOf().toType()));
34473543 }
34483544
3449 switch (mod.intern_pool.indexToKey(tv.val.toIntern())) {
3545 const val_key = mod.intern_pool.indexToKey(val.toIntern());
3546 const ty = val_key.typeOf().toType();
3547 return switch (val_key) {
34503548 .int_type,
34513549 .ptr_type,
34523550 .array_type,
......@@ -3474,8 +3572,8 @@ pub const Object = struct {
34743572 .@"unreachable",
34753573 .generic_poison,
34763574 => unreachable, // non-runtime values
3477 .false => return Builder.Constant.false.toLlvm(&o.builder),
3478 .true => return Builder.Constant.true.toLlvm(&o.builder),
3575 .false => .false,
3576 .true => .true,
34793577 },
34803578 .variable,
34813579 .enum_literal,
......@@ -3486,259 +3584,266 @@ pub const Object = struct {
34863584 const fn_decl = mod.declPtr(fn_decl_index);
34873585 try mod.markDeclAlive(fn_decl);
34883586 const function_index = try o.resolveLlvmFunction(fn_decl_index);
3489 return function_index.toLlvm(&o.builder);
3587 return function_index.ptrConst(&o.builder).global.toConst();
34903588 },
34913589 .func => |func| {
34923590 const fn_decl_index = func.owner_decl;
34933591 const fn_decl = mod.declPtr(fn_decl_index);
34943592 try mod.markDeclAlive(fn_decl);
34953593 const function_index = try o.resolveLlvmFunction(fn_decl_index);
3496 return function_index.toLlvm(&o.builder);
3594 return function_index.ptrConst(&o.builder).global.toConst();
34973595 },
34983596 .int => {
34993597 var bigint_space: Value.BigIntSpace = undefined;
3500 const bigint = tv.val.toBigInt(&bigint_space, mod);
3501 return lowerBigInt(o, tv.ty, bigint);
3598 const bigint = val.toBigInt(&bigint_space, mod);
3599 return lowerBigInt(o, ty, bigint);
35023600 },
35033601 .err => |err| {
35043602 const int = try mod.getErrorValue(err.name);
35053603 const llvm_int = try o.builder.intConst(Builder.Type.err_int, int);
3506 return llvm_int.toLlvm(&o.builder);
3604 return llvm_int;
35073605 },
35083606 .error_union => |error_union| {
3509 const err_tv: TypedValue = switch (error_union.val) {
3510 .err_name => |err_name| .{
3511 .ty = tv.ty.errorUnionSet(mod),
3512 .val = (try mod.intern(.{ .err = .{
3513 .ty = tv.ty.errorUnionSet(mod).toIntern(),
3514 .name = err_name,
3515 } })).toValue(),
3516 },
3517 .payload => .{
3518 .ty = Type.err_int,
3519 .val = try mod.intValue(Type.err_int, 0),
3520 },
3607 const err_val = switch (error_union.val) {
3608 .err_name => |err_name| try mod.intern(.{ .err = .{
3609 .ty = ty.errorUnionSet(mod).toIntern(),
3610 .name = err_name,
3611 } }),
3612 .payload => (try mod.intValue(Type.err_int, 0)).toIntern(),
35213613 };
3522 const payload_type = tv.ty.errorUnionPayload(mod);
3614 const payload_type = ty.errorUnionPayload(mod);
35233615 if (!payload_type.hasRuntimeBitsIgnoreComptime(mod)) {
35243616 // We use the error type directly as the type.
3525 return o.lowerValue(err_tv);
3617 return o.lowerValue(err_val);
35263618 }
35273619
35283620 const payload_align = payload_type.abiAlignment(mod);
3529 const error_align = err_tv.ty.abiAlignment(mod);
3530 const llvm_error_value = try o.lowerValue(err_tv);
3531 const llvm_payload_value = try o.lowerValue(.{
3532 .ty = payload_type,
3533 .val = switch (error_union.val) {
3534 .err_name => try mod.intern(.{ .undef = payload_type.toIntern() }),
3535 .payload => |payload| payload,
3536 }.toValue(),
3621 const error_align = Type.err_int.abiAlignment(mod);
3622 const llvm_error_value = try o.lowerValue(err_val);
3623 const llvm_payload_value = try o.lowerValue(switch (error_union.val) {
3624 .err_name => try mod.intern(.{ .undef = payload_type.toIntern() }),
3625 .payload => |payload| payload,
35373626 });
3538 var fields_buf: [3]*llvm.Value = undefined;
3539
3540 const llvm_ty = (try o.lowerType(tv.ty)).toLlvm(&o.builder);
3541 const llvm_field_count = llvm_ty.countStructElementTypes();
3542 if (llvm_field_count > 2) {
3543 assert(llvm_field_count == 3);
3544 fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef();
3545 }
35463627
3628 var fields: [3]Builder.Type = undefined;
3629 var vals: [3]Builder.Constant = undefined;
35473630 if (error_align > payload_align) {
3548 fields_buf[0] = llvm_error_value;
3549 fields_buf[1] = llvm_payload_value;
3550 return o.context.constStruct(&fields_buf, llvm_field_count, .False);
3631 vals[0] = llvm_error_value;
3632 vals[1] = llvm_payload_value;
35513633 } else {
3552 fields_buf[0] = llvm_payload_value;
3553 fields_buf[1] = llvm_error_value;
3554 return o.context.constStruct(&fields_buf, llvm_field_count, .False);
3634 vals[0] = llvm_payload_value;
3635 vals[1] = llvm_error_value;
3636 }
3637 fields[0] = vals[0].typeOf(&o.builder);
3638 fields[1] = vals[1].typeOf(&o.builder);
3639
3640 const llvm_ty = try o.lowerType(ty);
3641 const llvm_ty_fields = llvm_ty.structFields(&o.builder);
3642 if (llvm_ty_fields.len > 2) {
3643 assert(llvm_ty_fields.len == 3);
3644 fields[2] = llvm_ty_fields[2];
3645 vals[2] = try o.builder.undefConst(fields[2]);
35553646 }
3647 return o.builder.structConst(try o.builder.structType(
3648 llvm_ty.structKind(&o.builder),
3649 fields[0..llvm_ty_fields.len],
3650 ), vals[0..llvm_ty_fields.len]);
35563651 },
3557 .enum_tag => |enum_tag| return o.lowerValue(.{
3558 .ty = mod.intern_pool.typeOf(enum_tag.int).toType(),
3559 .val = enum_tag.int.toValue(),
3560 }),
3561 .float => return switch (tv.ty.floatBits(target)) {
3562 16 => int: {
3563 const repr: i16 = @bitCast(tv.val.toFloat(f16, mod));
3564 break :int try o.builder.intConst(.i16, repr);
3565 },
3566 32 => int: {
3567 const repr: i32 = @bitCast(tv.val.toFloat(f32, mod));
3568 break :int try o.builder.intConst(.i32, repr);
3569 },
3570 64 => int: {
3571 const repr: i64 = @bitCast(tv.val.toFloat(f64, mod));
3572 break :int try o.builder.intConst(.i64, repr);
3573 },
3574 80 => int: {
3575 const repr: i80 = @bitCast(tv.val.toFloat(f80, mod));
3576 break :int try o.builder.intConst(.i80, repr);
3577 },
3578 128 => int: {
3579 const repr: i128 = @bitCast(tv.val.toFloat(f128, mod));
3580 break :int try o.builder.intConst(.i128, repr);
3581 },
3652 .enum_tag => |enum_tag| o.lowerValue(enum_tag.int),
3653 .float => switch (ty.floatBits(target)) {
3654 16 => if (backendSupportsF16(target))
3655 try o.builder.halfConst(val.toFloat(f16, mod))
3656 else
3657 try o.builder.intConst(.i16, @as(i16, @bitCast(val.toFloat(f16, mod)))),
3658 32 => try o.builder.floatConst(val.toFloat(f32, mod)),
3659 64 => try o.builder.doubleConst(val.toFloat(f64, mod)),
3660 80 => if (backendSupportsF80(target))
3661 try o.builder.x86_fp80Const(val.toFloat(f80, mod))
3662 else
3663 try o.builder.intConst(.i80, @as(i80, @bitCast(val.toFloat(f80, mod)))),
3664 128 => try o.builder.fp128Const(val.toFloat(f128, mod)),
35823665 else => unreachable,
3583 }.toLlvm(&o.builder).constBitCast((try o.lowerType(tv.ty)).toLlvm(&o.builder)),
3666 },
35843667 .ptr => |ptr| {
3585 const ptr_tv: TypedValue = switch (ptr.len) {
3586 .none => tv,
3587 else => .{ .ty = tv.ty.slicePtrFieldType(mod), .val = tv.val.slicePtr(mod) },
3668 const ptr_ty = switch (ptr.len) {
3669 .none => ty,
3670 else => ty.slicePtrFieldType(mod),
35883671 };
3589 const llvm_ptr_val = switch (ptr.addr) {
3590 .decl => |decl| try o.lowerDeclRefValue(ptr_tv, decl),
3591 .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_tv, mut_decl.decl),
3592 .int => |int| try o.lowerIntAsPtr(int.toValue()),
3672 const ptr_val = switch (ptr.addr) {
3673 .decl => |decl| try o.lowerDeclRefValue(ptr_ty, decl),
3674 .mut_decl => |mut_decl| try o.lowerDeclRefValue(ptr_ty, mut_decl.decl),
3675 .int => |int| try o.lowerIntAsPtr(int),
35933676 .eu_payload,
35943677 .opt_payload,
35953678 .elem,
35963679 .field,
3597 => try o.lowerParentPtr(ptr_tv.val, ptr_tv.ty.ptrInfo(mod).packed_offset.bit_offset % 8 == 0),
3680 => try o.lowerParentPtr(val, ty.ptrInfo(mod).packed_offset.bit_offset % 8 == 0),
35983681 .comptime_field => unreachable,
35993682 };
36003683 switch (ptr.len) {
3601 .none => return llvm_ptr_val,
3602 else => {
3603 const fields: [2]*llvm.Value = .{
3604 llvm_ptr_val,
3605 try o.lowerValue(.{ .ty = Type.usize, .val = ptr.len.toValue() }),
3606 };
3607 return o.context.constStruct(&fields, fields.len, .False);
3608 },
3684 .none => return ptr_val,
3685 else => return o.builder.structConst(try o.lowerType(ty), &.{
3686 ptr_val, try o.lowerValue(ptr.len),
3687 }),
36093688 }
36103689 },
36113690 .opt => |opt| {
36123691 comptime assert(optional_layout_version == 3);
3613 const payload_ty = tv.ty.optionalChild(mod);
3692 const payload_ty = ty.optionalChild(mod);
36143693
3615 const non_null_bit = (try o.builder.intConst(.i8, @intFromBool(opt.val != .none))).toLlvm(&o.builder);
3694 const non_null_bit = try o.builder.intConst(.i8, @intFromBool(opt.val != .none));
36163695 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
36173696 return non_null_bit;
36183697 }
3619 const llvm_ty = (try o.lowerType(tv.ty)).toLlvm(&o.builder);
3620 if (tv.ty.optionalReprIsPayload(mod)) return switch (opt.val) {
3621 .none => llvm_ty.constNull(),
3622 else => |payload| o.lowerValue(.{ .ty = payload_ty, .val = payload.toValue() }),
3698 const llvm_ty = try o.lowerType(ty);
3699 if (ty.optionalReprIsPayload(mod)) return switch (opt.val) {
3700 .none => switch (llvm_ty.tag(&o.builder)) {
3701 .integer => try o.builder.intConst(llvm_ty, 0),
3702 .pointer => try o.builder.nullConst(llvm_ty),
3703 .structure => try o.builder.zeroInitConst(llvm_ty),
3704 else => unreachable,
3705 },
3706 else => |payload| try o.lowerValue(payload),
36233707 };
36243708 assert(payload_ty.zigTypeTag(mod) != .Fn);
36253709
3626 const llvm_field_count = llvm_ty.countStructElementTypes();
3627 var fields_buf: [3]*llvm.Value = undefined;
3628 fields_buf[0] = try o.lowerValue(.{
3629 .ty = payload_ty,
3630 .val = switch (opt.val) {
3631 .none => try mod.intern(.{ .undef = payload_ty.toIntern() }),
3632 else => |payload| payload,
3633 }.toValue(),
3710 var fields: [3]Builder.Type = undefined;
3711 var vals: [3]Builder.Constant = undefined;
3712 vals[0] = try o.lowerValue(switch (opt.val) {
3713 .none => try mod.intern(.{ .undef = payload_ty.toIntern() }),
3714 else => |payload| payload,
36343715 });
3635 fields_buf[1] = non_null_bit;
3636 if (llvm_field_count > 2) {
3637 assert(llvm_field_count == 3);
3638 fields_buf[2] = llvm_ty.structGetTypeAtIndex(2).getUndef();
3716 vals[1] = non_null_bit;
3717 fields[0] = vals[0].typeOf(&o.builder);
3718 fields[1] = vals[1].typeOf(&o.builder);
3719
3720 const llvm_ty_fields = llvm_ty.structFields(&o.builder);
3721 if (llvm_ty_fields.len > 2) {
3722 assert(llvm_ty_fields.len == 3);
3723 fields[2] = llvm_ty_fields[2];
3724 vals[2] = try o.builder.undefConst(fields[2]);
36393725 }
3640 return o.context.constStruct(&fields_buf, llvm_field_count, .False);
3726 return o.builder.structConst(try o.builder.structType(
3727 llvm_ty.structKind(&o.builder),
3728 fields[0..llvm_ty_fields.len],
3729 ), vals[0..llvm_ty_fields.len]);
36413730 },
3642 .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(tv.ty.toIntern())) {
3643 .array_type => switch (aggregate.storage) {
3644 .bytes => |bytes| return o.context.constString(
3645 bytes.ptr,
3646 @as(c_uint, @intCast(tv.ty.arrayLenIncludingSentinel(mod))),
3647 .True, // Don't null terminate. Bytes has the sentinel, if any.
3648 ),
3649 .elems => |elem_vals| {
3650 const elem_ty = tv.ty.childType(mod);
3651 const llvm_elems = try gpa.alloc(*llvm.Value, elem_vals.len);
3652 defer gpa.free(llvm_elems);
3731 .aggregate => |aggregate| switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3732 .array_type => |array_type| switch (aggregate.storage) {
3733 .bytes => |bytes| try o.builder.stringConst(try o.builder.string(bytes)),
3734 .elems => |elems| {
3735 const array_ty = try o.lowerType(ty);
3736 const elem_ty = array_ty.childType(&o.builder);
3737 assert(elems.len == array_ty.aggregateLen(&o.builder));
3738
3739 const ExpectedContents = extern struct {
3740 vals: [Builder.expected_fields_len]Builder.Constant,
3741 fields: [Builder.expected_fields_len]Builder.Type,
3742 };
3743 var stack align(@max(
3744 @alignOf(std.heap.StackFallbackAllocator(0)),
3745 @alignOf(ExpectedContents),
3746 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa);
3747 const allocator = stack.get();
3748 const vals = try allocator.alloc(Builder.Constant, elems.len);
3749 defer allocator.free(vals);
3750 const fields = try allocator.alloc(Builder.Type, elems.len);
3751 defer allocator.free(fields);
3752
36533753 var need_unnamed = false;
3654 for (elem_vals, 0..) |elem_val, i| {
3655 llvm_elems[i] = try o.lowerValue(.{ .ty = elem_ty, .val = elem_val.toValue() });
3656 need_unnamed = need_unnamed or o.isUnnamedType(elem_ty, llvm_elems[i]);
3657 }
3658 if (need_unnamed) {
3659 return o.context.constStruct(
3660 llvm_elems.ptr,
3661 @as(c_uint, @intCast(llvm_elems.len)),
3662 .True,
3663 );
3664 } else {
3665 const llvm_elem_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);
3666 return llvm_elem_ty.constArray(
3667 llvm_elems.ptr,
3668 @as(c_uint, @intCast(llvm_elems.len)),
3669 );
3754 for (vals, fields, elems) |*result_val, *result_field, elem| {
3755 result_val.* = try o.lowerValue(elem);
3756 result_field.* = result_val.typeOf(&o.builder);
3757 if (result_field.* != elem_ty) need_unnamed = true;
36703758 }
3759 return if (need_unnamed) try o.builder.structConst(
3760 try o.builder.structType(.normal, fields),
3761 vals,
3762 ) else try o.builder.arrayConst(array_ty, vals);
36713763 },
3672 .repeated_elem => |val| {
3673 const elem_ty = tv.ty.childType(mod);
3674 const sentinel = tv.ty.sentinel(mod);
3675 const len = @as(usize, @intCast(tv.ty.arrayLen(mod)));
3676 const len_including_sent = len + @intFromBool(sentinel != null);
3677 const llvm_elems = try gpa.alloc(*llvm.Value, len_including_sent);
3678 defer gpa.free(llvm_elems);
3764 .repeated_elem => |elem| {
3765 const len: usize = @intCast(array_type.len);
3766 const len_including_sentinel: usize =
3767 @intCast(len + @intFromBool(array_type.sentinel != .none));
3768 const array_ty = try o.lowerType(ty);
3769 const elem_ty = array_ty.childType(&o.builder);
3770
3771 const ExpectedContents = extern struct {
3772 vals: [Builder.expected_fields_len]Builder.Constant,
3773 fields: [Builder.expected_fields_len]Builder.Type,
3774 };
3775 var stack align(@max(
3776 @alignOf(std.heap.StackFallbackAllocator(0)),
3777 @alignOf(ExpectedContents),
3778 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa);
3779 const allocator = stack.get();
3780 const vals = try allocator.alloc(Builder.Constant, len_including_sentinel);
3781 defer allocator.free(vals);
3782 const fields = try allocator.alloc(Builder.Type, len_including_sentinel);
3783 defer allocator.free(fields);
36793784
36803785 var need_unnamed = false;
3681 if (len != 0) {
3682 for (llvm_elems[0..len]) |*elem| {
3683 elem.* = try o.lowerValue(.{ .ty = elem_ty, .val = val.toValue() });
3684 }
3685 need_unnamed = need_unnamed or o.isUnnamedType(elem_ty, llvm_elems[0]);
3686 }
3687
3688 if (sentinel) |sent| {
3689 llvm_elems[len] = try o.lowerValue(.{ .ty = elem_ty, .val = sent });
3690 need_unnamed = need_unnamed or o.isUnnamedType(elem_ty, llvm_elems[len]);
3786 @memset(vals[0..len], try o.lowerValue(elem));
3787 @memset(fields[0..len], vals[0].typeOf(&o.builder));
3788 if (fields[0] != elem_ty) need_unnamed = true;
3789
3790 if (array_type.sentinel != .none) {
3791 vals[len] = try o.lowerValue(array_type.sentinel);
3792 fields[len] = vals[len].typeOf(&o.builder);
3793 if (fields[len] != elem_ty) need_unnamed = true;
36913794 }
36923795
3693 if (need_unnamed) {
3694 return o.context.constStruct(
3695 llvm_elems.ptr,
3696 @as(c_uint, @intCast(llvm_elems.len)),
3697 .True,
3698 );
3699 } else {
3700 const llvm_elem_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);
3701 return llvm_elem_ty.constArray(
3702 llvm_elems.ptr,
3703 @as(c_uint, @intCast(llvm_elems.len)),
3704 );
3705 }
3796 return if (need_unnamed) try o.builder.structConst(
3797 try o.builder.structType(.@"packed", fields),
3798 vals,
3799 ) else try o.builder.arrayConst(array_ty, vals);
37063800 },
37073801 },
37083802 .vector_type => |vector_type| {
3709 const elem_ty = vector_type.child.toType();
3710 const llvm_elems = try gpa.alloc(*llvm.Value, vector_type.len);
3711 defer gpa.free(llvm_elems);
3712 for (llvm_elems, 0..) |*llvm_elem, i| {
3713 llvm_elem.* = switch (aggregate.storage) {
3714 .bytes => |bytes| (try o.builder.intConst(.i8, bytes[i])).toLlvm(&o.builder),
3715 .elems => |elems| try o.lowerValue(.{
3716 .ty = elem_ty,
3717 .val = elems[i].toValue(),
3718 }),
3719 .repeated_elem => |elem| try o.lowerValue(.{
3720 .ty = elem_ty,
3721 .val = elem.toValue(),
3722 }),
3723 };
3803 const ExpectedContents = [Builder.expected_fields_len]Builder.Constant;
3804 var stack align(@max(
3805 @alignOf(std.heap.StackFallbackAllocator(0)),
3806 @alignOf(ExpectedContents),
3807 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa);
3808 const allocator = stack.get();
3809 const vals = try allocator.alloc(Builder.Constant, vector_type.len);
3810 defer allocator.free(vals);
3811
3812 switch (aggregate.storage) {
3813 .bytes => |bytes| for (vals, bytes) |*result_val, byte| {
3814 result_val.* = try o.builder.intConst(.i8, byte);
3815 },
3816 .elems => |elems| for (vals, elems) |*result_val, elem| {
3817 result_val.* = try o.lowerValue(elem);
3818 },
3819 .repeated_elem => |elem| @memset(vals, try o.lowerValue(elem)),
37243820 }
3725 return llvm.constVector(
3726 llvm_elems.ptr,
3727 @as(c_uint, @intCast(llvm_elems.len)),
3728 );
3821 return o.builder.vectorConst(try o.lowerType(ty), vals);
37293822 },
37303823 .anon_struct_type => |tuple| {
3731 var llvm_fields: std.ArrayListUnmanaged(*llvm.Value) = .{};
3732 defer llvm_fields.deinit(gpa);
3824 const struct_ty = try o.lowerType(ty);
3825 const llvm_len = struct_ty.aggregateLen(&o.builder);
37333826
3734 try llvm_fields.ensureUnusedCapacity(gpa, tuple.types.len);
3827 const ExpectedContents = extern struct {
3828 vals: [Builder.expected_fields_len]Builder.Constant,
3829 fields: [Builder.expected_fields_len]Builder.Type,
3830 };
3831 var stack align(@max(
3832 @alignOf(std.heap.StackFallbackAllocator(0)),
3833 @alignOf(ExpectedContents),
3834 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa);
3835 const allocator = stack.get();
3836 const vals = try allocator.alloc(Builder.Constant, llvm_len);
3837 defer allocator.free(vals);
3838 const fields = try allocator.alloc(Builder.Type, llvm_len);
3839 defer allocator.free(fields);
37353840
37363841 comptime assert(struct_layout_version == 2);
3842 var llvm_index: usize = 0;
37373843 var offset: u64 = 0;
37383844 var big_align: u32 = 0;
37393845 var need_unnamed = false;
3740
3741 for (tuple.types, tuple.values, 0..) |field_ty, field_val, i| {
3846 for (tuple.types, tuple.values, 0..) |field_ty, field_val, field_index| {
37423847 if (field_val != .none) continue;
37433848 if (!field_ty.toType().hasRuntimeBitsIgnoreComptime(mod)) continue;
37443849
......@@ -3749,20 +3854,20 @@ pub const Object = struct {
37493854
37503855 const padding_len = offset - prev_offset;
37513856 if (padding_len > 0) {
3752 const llvm_array_ty = try o.builder.arrayType(padding_len, .i8);
37533857 // TODO make this and all other padding elsewhere in debug
37543858 // builds be 0xaa not undef.
3755 llvm_fields.appendAssumeCapacity(llvm_array_ty.toLlvm(&o.builder).getUndef());
3859 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
3860 vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]);
3861 assert(fields[llvm_index] == struct_ty.structFields(&o.builder)[llvm_index]);
3862 llvm_index += 1;
37563863 }
37573864
3758 const field_llvm_val = try o.lowerValue(.{
3759 .ty = field_ty.toType(),
3760 .val = try tv.val.fieldValue(mod, i),
3761 });
3762
3763 need_unnamed = need_unnamed or o.isUnnamedType(field_ty.toType(), field_llvm_val);
3764
3765 llvm_fields.appendAssumeCapacity(field_llvm_val);
3865 vals[llvm_index] =
3866 try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern());
3867 fields[llvm_index] = vals[llvm_index].typeOf(&o.builder);
3868 if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index])
3869 need_unnamed = true;
3870 llvm_index += 1;
37663871
37673872 offset += field_ty.toType().abiSize(mod);
37683873 }
......@@ -3771,73 +3876,71 @@ pub const Object = struct {
37713876 offset = std.mem.alignForward(u64, offset, big_align);
37723877 const padding_len = offset - prev_offset;
37733878 if (padding_len > 0) {
3774 const llvm_array_ty = try o.builder.arrayType(padding_len, .i8);
3775 llvm_fields.appendAssumeCapacity(llvm_array_ty.toLlvm(&o.builder).getUndef());
3879 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
3880 vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]);
3881 assert(fields[llvm_index] == struct_ty.structFields(&o.builder)[llvm_index]);
3882 llvm_index += 1;
37763883 }
37773884 }
3885 assert(llvm_index == llvm_len);
37783886
3779 if (need_unnamed) {
3780 return o.context.constStruct(
3781 llvm_fields.items.ptr,
3782 @as(c_uint, @intCast(llvm_fields.items.len)),
3783 .False,
3784 );
3785 } else {
3786 const llvm_struct_ty = (try o.lowerType(tv.ty)).toLlvm(&o.builder);
3787 return llvm_struct_ty.constNamedStruct(
3788 llvm_fields.items.ptr,
3789 @as(c_uint, @intCast(llvm_fields.items.len)),
3790 );
3791 }
3887 return try o.builder.structConst(if (need_unnamed)
3888 try o.builder.structType(struct_ty.structKind(&o.builder), fields)
3889 else
3890 struct_ty, vals);
37923891 },
37933892 .struct_type => |struct_type| {
37943893 const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
3795 const llvm_struct_ty = (try o.lowerType(tv.ty)).toLlvm(&o.builder);
3796
3894 assert(struct_obj.haveLayout());
3895 const struct_ty = try o.lowerType(ty);
37973896 if (struct_obj.layout == .Packed) {
3798 assert(struct_obj.haveLayout());
3799 const big_bits = struct_obj.backing_int_ty.bitSize(mod);
3800 const int_llvm_ty = try o.builder.intType(@intCast(big_bits));
3801 const fields = struct_obj.fields.values();
38023897 comptime assert(Type.packed_struct_layout_version == 2);
3803 var running_int = (try o.builder.intConst(int_llvm_ty, 0)).toLlvm(&o.builder);
3898 var running_int = try o.builder.intConst(struct_ty, 0);
38043899 var running_bits: u16 = 0;
3805 for (fields, 0..) |field, i| {
3900 for (struct_obj.fields.values(), 0..) |field, field_index| {
38063901 if (!field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
38073902
3808 const non_int_val = try o.lowerValue(.{
3809 .ty = field.ty,
3810 .val = try tv.val.fieldValue(mod, i),
3811 });
3812 const ty_bit_size = @as(u16, @intCast(field.ty.bitSize(mod)));
3813 const small_int_ty = (try o.builder.intType(@intCast(ty_bit_size))).toLlvm(&o.builder);
3814 const small_int_val = if (field.ty.isPtrAtRuntime(mod))
3815 non_int_val.constPtrToInt(small_int_ty)
3816 else
3817 non_int_val.constBitCast(small_int_ty);
3818 const shift_rhs = (try o.builder.intConst(int_llvm_ty, running_bits)).toLlvm(&o.builder);
3819 // If the field is as large as the entire packed struct, this
3820 // zext would go from, e.g. i16 to i16. This is legal with
3821 // constZExtOrBitCast but not legal with constZExt.
3822 const extended_int_val = small_int_val.constZExtOrBitCast(int_llvm_ty.toLlvm(&o.builder));
3823 const shifted = extended_int_val.constShl(shift_rhs);
3824 running_int = running_int.constOr(shifted);
3903 const non_int_val =
3904 try o.lowerValue((try val.fieldValue(mod, field_index)).toIntern());
3905 const ty_bit_size: u16 = @intCast(field.ty.bitSize(mod));
3906 const small_int_ty = try o.builder.intType(ty_bit_size);
3907 const small_int_val = try o.builder.castConst(
3908 if (field.ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast,
3909 non_int_val,
3910 small_int_ty,
3911 );
3912 const shift_rhs = try o.builder.intConst(struct_ty, running_bits);
3913 const extended_int_val =
3914 try o.builder.convConst(.unsigned, small_int_val, struct_ty);
3915 const shifted = try o.builder.binConst(.shl, extended_int_val, shift_rhs);
3916 running_int = try o.builder.binConst(.@"or", running_int, shifted);
38253917 running_bits += ty_bit_size;
38263918 }
38273919 return running_int;
38283920 }
3921 const llvm_len = struct_ty.aggregateLen(&o.builder);
38293922
3830 const llvm_field_count = llvm_struct_ty.countStructElementTypes();
3831 var llvm_fields = try std.ArrayListUnmanaged(*llvm.Value).initCapacity(gpa, llvm_field_count);
3832 defer llvm_fields.deinit(gpa);
3923 const ExpectedContents = extern struct {
3924 vals: [Builder.expected_fields_len]Builder.Constant,
3925 fields: [Builder.expected_fields_len]Builder.Type,
3926 };
3927 var stack align(@max(
3928 @alignOf(std.heap.StackFallbackAllocator(0)),
3929 @alignOf(ExpectedContents),
3930 )) = std.heap.stackFallback(@sizeOf(ExpectedContents), o.gpa);
3931 const allocator = stack.get();
3932 const vals = try allocator.alloc(Builder.Constant, llvm_len);
3933 defer allocator.free(vals);
3934 const fields = try allocator.alloc(Builder.Type, llvm_len);
3935 defer allocator.free(fields);
38333936
38343937 comptime assert(struct_layout_version == 2);
3938 var llvm_index: usize = 0;
38353939 var offset: u64 = 0;
38363940 var big_align: u32 = 0;
38373941 var need_unnamed = false;
3838
3839 var it = struct_obj.runtimeFieldIterator(mod);
3840 while (it.next()) |field_and_index| {
3942 var field_it = struct_obj.runtimeFieldIterator(mod);
3943 while (field_it.next()) |field_and_index| {
38413944 const field = field_and_index.field;
38423945 const field_align = field.alignment(mod, struct_obj.layout);
38433946 big_align = @max(big_align, field_align);
......@@ -3846,20 +3949,22 @@ pub const Object = struct {
38463949
38473950 const padding_len = offset - prev_offset;
38483951 if (padding_len > 0) {
3849 const llvm_array_ty = try o.builder.arrayType(padding_len, .i8);
38503952 // TODO make this and all other padding elsewhere in debug
38513953 // builds be 0xaa not undef.
3852 llvm_fields.appendAssumeCapacity(llvm_array_ty.toLlvm(&o.builder).getUndef());
3954 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
3955 vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]);
3956 assert(fields[llvm_index] ==
3957 struct_ty.structFields(&o.builder)[llvm_index]);
3958 llvm_index += 1;
38533959 }
38543960
3855 const field_llvm_val = try o.lowerValue(.{
3856 .ty = field.ty,
3857 .val = try tv.val.fieldValue(mod, field_and_index.index),
3858 });
3859
3860 need_unnamed = need_unnamed or o.isUnnamedType(field.ty, field_llvm_val);
3861
3862 llvm_fields.appendAssumeCapacity(field_llvm_val);
3961 vals[llvm_index] = try o.lowerValue(
3962 (try val.fieldValue(mod, field_and_index.index)).toIntern(),
3963 );
3964 fields[llvm_index] = vals[llvm_index].typeOf(&o.builder);
3965 if (fields[llvm_index] != struct_ty.structFields(&o.builder)[llvm_index])
3966 need_unnamed = true;
3967 llvm_index += 1;
38633968
38643969 offset += field.ty.abiSize(mod);
38653970 }
......@@ -3868,135 +3973,118 @@ pub const Object = struct {
38683973 offset = std.mem.alignForward(u64, offset, big_align);
38693974 const padding_len = offset - prev_offset;
38703975 if (padding_len > 0) {
3871 const llvm_array_ty = try o.builder.arrayType(padding_len, .i8);
3872 llvm_fields.appendAssumeCapacity(llvm_array_ty.toLlvm(&o.builder).getUndef());
3976 fields[llvm_index] = try o.builder.arrayType(padding_len, .i8);
3977 vals[llvm_index] = try o.builder.undefConst(fields[llvm_index]);
3978 assert(fields[llvm_index] == struct_ty.structFields(&o.builder)[llvm_index]);
3979 llvm_index += 1;
38733980 }
38743981 }
3982 assert(llvm_index == llvm_len);
38753983
3876 if (need_unnamed) {
3877 return o.context.constStruct(
3878 llvm_fields.items.ptr,
3879 @as(c_uint, @intCast(llvm_fields.items.len)),
3880 .False,
3881 );
3882 } else {
3883 return llvm_struct_ty.constNamedStruct(
3884 llvm_fields.items.ptr,
3885 @as(c_uint, @intCast(llvm_fields.items.len)),
3886 );
3887 }
3984 return try o.builder.structConst(if (need_unnamed)
3985 try o.builder.structType(struct_ty.structKind(&o.builder), fields)
3986 else
3987 struct_ty, vals);
38883988 },
38893989 else => unreachable,
38903990 },
3891 .un => {
3892 const llvm_union_ty = (try o.lowerType(tv.ty)).toLlvm(&o.builder);
3893 const tag_and_val: Value.Payload.Union.Data = switch (tv.val.toIntern()) {
3894 .none => tv.val.castTag(.@"union").?.data,
3895 else => switch (mod.intern_pool.indexToKey(tv.val.toIntern())) {
3896 .un => |un| .{ .tag = un.tag.toValue(), .val = un.val.toValue() },
3897 else => unreachable,
3898 },
3899 };
3900
3901 const layout = tv.ty.unionGetLayout(mod);
3991 .un => |un| {
3992 const union_ty = try o.lowerType(ty);
3993 const layout = ty.unionGetLayout(mod);
3994 if (layout.payload_size == 0) return o.lowerValue(un.tag);
39023995
3903 if (layout.payload_size == 0) {
3904 return lowerValue(o, .{
3905 .ty = tv.ty.unionTagTypeSafety(mod).?,
3906 .val = tag_and_val.tag,
3907 });
3908 }
3909 const union_obj = mod.typeToUnion(tv.ty).?;
3910 const field_index = tv.ty.unionTagFieldIndex(tag_and_val.tag, o.module).?;
3996 const union_obj = mod.typeToUnion(ty).?;
3997 const field_index = ty.unionTagFieldIndex(un.tag.toValue(), o.module).?;
39113998 assert(union_obj.haveFieldTypes());
39123999
39134000 const field_ty = union_obj.fields.values()[field_index].ty;
39144001 if (union_obj.layout == .Packed) {
3915 if (!field_ty.hasRuntimeBits(mod))
3916 return llvm_union_ty.constNull();
3917 const non_int_val = try lowerValue(o, .{ .ty = field_ty, .val = tag_and_val.val });
3918 const ty_bit_size = @as(u16, @intCast(field_ty.bitSize(mod)));
3919 const small_int_ty = (try o.builder.intType(@intCast(ty_bit_size))).toLlvm(&o.builder);
3920 const small_int_val = if (field_ty.isPtrAtRuntime(mod))
3921 non_int_val.constPtrToInt(small_int_ty)
3922 else
3923 non_int_val.constBitCast(small_int_ty);
3924 return small_int_val.constZExtOrBitCast(llvm_union_ty);
4002 if (!field_ty.hasRuntimeBits(mod)) return o.builder.intConst(union_ty, 0);
4003 const small_int_val = try o.builder.castConst(
4004 if (field_ty.isPtrAtRuntime(mod)) .ptrtoint else .bitcast,
4005 try o.lowerValue(un.val),
4006 try o.builder.intType(@intCast(field_ty.bitSize(mod))),
4007 );
4008 return o.builder.convConst(.unsigned, small_int_val, union_ty);
39254009 }
39264010
39274011 // Sometimes we must make an unnamed struct because LLVM does
39284012 // not support bitcasting our payload struct to the true union payload type.
39294013 // Instead we use an unnamed struct and every reference to the global
39304014 // must pointer cast to the expected type before accessing the union.
3931 var need_unnamed: bool = layout.most_aligned_field != field_index;
4015 var need_unnamed = layout.most_aligned_field != field_index;
39324016 const payload = p: {
39334017 if (!field_ty.hasRuntimeBitsIgnoreComptime(mod)) {
3934 const padding_len = @as(c_uint, @intCast(layout.payload_size));
3935 break :p (try o.builder.arrayType(padding_len, .i8)).toLlvm(&o.builder).getUndef();
4018 const padding_len = layout.payload_size;
4019 break :p try o.builder.undefConst(try o.builder.arrayType(padding_len, .i8));
39364020 }
3937 const field = try lowerValue(o, .{ .ty = field_ty, .val = tag_and_val.val });
3938 need_unnamed = need_unnamed or o.isUnnamedType(field_ty, field);
4021 const payload = try o.lowerValue(un.val);
4022 const payload_ty = payload.typeOf(&o.builder);
4023 if (payload_ty != union_ty.structFields(&o.builder)[
4024 @intFromBool(layout.tag_align >= layout.payload_align)
4025 ]) need_unnamed = true;
39394026 const field_size = field_ty.abiSize(mod);
3940 if (field_size == layout.payload_size) {
3941 break :p field;
3942 }
3943 const padding_len = @as(c_uint, @intCast(layout.payload_size - field_size));
3944 const fields: [2]*llvm.Value = .{
3945 field, (try o.builder.arrayType(padding_len, .i8)).toLlvm(&o.builder).getUndef(),
3946 };
3947 break :p o.context.constStruct(&fields, fields.len, .True);
4027 if (field_size == layout.payload_size) break :p payload;
4028 const padding_len = layout.payload_size - field_size;
4029 const padding_ty = try o.builder.arrayType(padding_len, .i8);
4030 break :p try o.builder.structConst(
4031 try o.builder.structType(.@"packed", &.{ payload_ty, padding_ty }),
4032 &.{ payload, try o.builder.undefConst(padding_ty) },
4033 );
39484034 };
4035 const payload_ty = payload.typeOf(&o.builder);
39494036
3950 if (layout.tag_size == 0) {
3951 const fields: [1]*llvm.Value = .{payload};
3952 if (need_unnamed) {
3953 return o.context.constStruct(&fields, fields.len, .False);
3954 } else {
3955 return llvm_union_ty.constNamedStruct(&fields, fields.len);
3956 }
3957 }
3958 const llvm_tag_value = try lowerValue(o, .{
3959 .ty = tv.ty.unionTagTypeSafety(mod).?,
3960 .val = tag_and_val.tag,
3961 });
3962 var fields: [3]*llvm.Value = undefined;
3963 var fields_len: c_uint = 2;
4037 if (layout.tag_size == 0) return o.builder.structConst(if (need_unnamed)
4038 try o.builder.structType(union_ty.structKind(&o.builder), &.{payload_ty})
4039 else
4040 union_ty, &.{payload});
4041 const tag = try o.lowerValue(un.tag);
4042 const tag_ty = tag.typeOf(&o.builder);
4043 var fields: [3]Builder.Type = undefined;
4044 var vals: [3]Builder.Constant = undefined;
4045 var len: usize = 2;
39644046 if (layout.tag_align >= layout.payload_align) {
3965 fields = .{ llvm_tag_value, payload, undefined };
4047 fields = .{ tag_ty, payload_ty, undefined };
4048 vals = .{ tag, payload, undefined };
39664049 } else {
3967 fields = .{ payload, llvm_tag_value, undefined };
4050 fields = .{ payload_ty, tag_ty, undefined };
4051 vals = .{ payload, tag, undefined };
39684052 }
39694053 if (layout.padding != 0) {
3970 fields[2] = (try o.builder.arrayType(layout.padding, .i8)).toLlvm(&o.builder).getUndef();
3971 fields_len = 3;
3972 }
3973 if (need_unnamed) {
3974 return o.context.constStruct(&fields, fields_len, .False);
3975 } else {
3976 return llvm_union_ty.constNamedStruct(&fields, fields_len);
4054 fields[2] = try o.builder.arrayType(layout.padding, .i8);
4055 vals[2] = try o.builder.undefConst(fields[2]);
4056 len = 3;
39774057 }
4058 return try o.builder.structConst(if (need_unnamed)
4059 try o.builder.structType(union_ty.structKind(&o.builder), fields[0..len])
4060 else
4061 union_ty, vals[0..len]);
39784062 },
39794063 .memoized_call => unreachable,
3980 }
4064 };
39814065 }
39824066
3983 fn lowerIntAsPtr(o: *Object, val: Value) Allocator.Error!*llvm.Value {
4067 fn lowerIntAsPtr(o: *Object, val: InternPool.Index) Allocator.Error!Builder.Constant {
39844068 const mod = o.module;
3985 switch (mod.intern_pool.indexToKey(val.toIntern())) {
3986 .undef => return o.context.pointerType(0).getUndef(),
4069 switch (mod.intern_pool.indexToKey(val)) {
4070 .undef => return o.builder.undefConst(.ptr),
39874071 .int => {
39884072 var bigint_space: Value.BigIntSpace = undefined;
3989 const bigint = val.toBigInt(&bigint_space, mod);
4073 const bigint = val.toValue().toBigInt(&bigint_space, mod);
39904074 const llvm_int = try lowerBigInt(o, Type.usize, bigint);
3991 return llvm_int.constIntToPtr(o.context.pointerType(0));
4075 return o.builder.castConst(.inttoptr, llvm_int, .ptr);
39924076 },
39934077 else => unreachable,
39944078 }
39954079 }
39964080
3997 fn lowerBigInt(o: *Object, ty: Type, bigint: std.math.big.int.Const) Allocator.Error!*llvm.Value {
3998 return (try o.builder.bigIntConst(try o.builder.intType(ty.intInfo(o.module).bits), bigint))
3999 .toLlvm(&o.builder);
4081 fn lowerBigInt(
4082 o: *Object,
4083 ty: Type,
4084 bigint: std.math.big.int.Const,
4085 ) Allocator.Error!Builder.Constant {
4086 const mod = o.module;
4087 return o.builder.bigIntConst(try o.builder.intType(ty.intInfo(mod).bits), bigint);
40004088 }
40014089
40024090 const ParentPtr = struct {
......@@ -4004,45 +4092,41 @@ pub const Object = struct {
40044092 llvm_ptr: *llvm.Value,
40054093 };
40064094
4007 fn lowerParentPtrDecl(
4008 o: *Object,
4009 ptr_val: Value,
4010 decl_index: Module.Decl.Index,
4011 ) Error!*llvm.Value {
4095 fn lowerParentPtrDecl(o: *Object, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {
40124096 const mod = o.module;
40134097 const decl = mod.declPtr(decl_index);
40144098 try mod.markDeclAlive(decl);
40154099 const ptr_ty = try mod.singleMutPtrType(decl.ty);
4016 return try o.lowerDeclRefValue(.{ .ty = ptr_ty, .val = ptr_val }, decl_index);
4100 return o.lowerDeclRefValue(ptr_ty, decl_index);
40174101 }
40184102
4019 fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Error!*llvm.Value {
4103 fn lowerParentPtr(o: *Object, ptr_val: Value, byte_aligned: bool) Allocator.Error!Builder.Constant {
40204104 const mod = o.module;
40214105 return switch (mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr.addr) {
4022 .decl => |decl| o.lowerParentPtrDecl(ptr_val, decl),
4023 .mut_decl => |mut_decl| o.lowerParentPtrDecl(ptr_val, mut_decl.decl),
4024 .int => |int| o.lowerIntAsPtr(int.toValue()),
4106 .decl => |decl| o.lowerParentPtrDecl(decl),
4107 .mut_decl => |mut_decl| o.lowerParentPtrDecl(mut_decl.decl),
4108 .int => |int| try o.lowerIntAsPtr(int),
40254109 .eu_payload => |eu_ptr| {
4026 const parent_llvm_ptr = try o.lowerParentPtr(eu_ptr.toValue(), true);
4110 const parent_ptr = try o.lowerParentPtr(eu_ptr.toValue(), true);
40274111
40284112 const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod);
40294113 const payload_ty = eu_ty.errorUnionPayload(mod);
40304114 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
40314115 // In this case, we represent pointer to error union the same as pointer
40324116 // to the payload.
4033 return parent_llvm_ptr;
4117 return parent_ptr;
40344118 }
40354119
4036 const payload_offset: u8 = if (payload_ty.abiAlignment(mod) > Type.anyerror.abiSize(mod)) 2 else 1;
4037 const indices: [2]*llvm.Value = .{
4038 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
4039 (try o.builder.intConst(.i32, payload_offset)).toLlvm(&o.builder),
4040 };
4041 const eu_llvm_ty = (try o.lowerType(eu_ty)).toLlvm(&o.builder);
4042 return eu_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
4120 return o.builder.gepConst(.inbounds, try o.lowerType(eu_ty), parent_ptr, &.{
4121 try o.builder.intConst(.i32, 0),
4122 try o.builder.intConst(.i32, @as(
4123 i32,
4124 if (payload_ty.abiAlignment(mod) > Type.err_int.abiSize(mod)) 2 else 1,
4125 )),
4126 });
40434127 },
40444128 .opt_payload => |opt_ptr| {
4045 const parent_llvm_ptr = try o.lowerParentPtr(opt_ptr.toValue(), true);
4129 const parent_ptr = try o.lowerParentPtr(opt_ptr.toValue(), true);
40464130
40474131 const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod);
40484132 const payload_ty = opt_ty.optionalChild(mod);
......@@ -4051,96 +4135,87 @@ pub const Object = struct {
40514135 {
40524136 // In this case, we represent pointer to optional the same as pointer
40534137 // to the payload.
4054 return parent_llvm_ptr;
4138 return parent_ptr;
40554139 }
40564140
4057 const indices: [2]*llvm.Value = .{
4058 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
4059 } ** 2;
4060 const opt_llvm_ty = (try o.lowerType(opt_ty)).toLlvm(&o.builder);
4061 return opt_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
4141 return o.builder.gepConst(.inbounds, try o.lowerType(opt_ty), parent_ptr, &(.{
4142 try o.builder.intConst(.i32, 0),
4143 } ** 2));
40624144 },
40634145 .comptime_field => unreachable,
40644146 .elem => |elem_ptr| {
4065 const parent_llvm_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true);
4066
4067 const indices: [1]*llvm.Value = .{
4068 (try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index)).toLlvm(&o.builder),
4069 };
4147 const parent_ptr = try o.lowerParentPtr(elem_ptr.base.toValue(), true);
40704148 const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod);
4071 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);
4072 return elem_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
4149
4150 return o.builder.gepConst(.inbounds, try o.lowerType(elem_ty), parent_ptr, &.{
4151 try o.builder.intConst(try o.lowerType(Type.usize), elem_ptr.index),
4152 });
40734153 },
40744154 .field => |field_ptr| {
4075 const parent_llvm_ptr = try o.lowerParentPtr(field_ptr.base.toValue(), byte_aligned);
4155 const parent_ptr = try o.lowerParentPtr(field_ptr.base.toValue(), byte_aligned);
40764156 const parent_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod);
40774157
4078 const field_index = @as(u32, @intCast(field_ptr.index));
4158 const field_index: u32 = @intCast(field_ptr.index);
40794159 switch (parent_ty.zigTypeTag(mod)) {
40804160 .Union => {
40814161 if (parent_ty.containerLayout(mod) == .Packed) {
4082 return parent_llvm_ptr;
4162 return parent_ptr;
40834163 }
40844164
40854165 const layout = parent_ty.unionGetLayout(mod);
40864166 if (layout.payload_size == 0) {
40874167 // In this case a pointer to the union and a pointer to any
40884168 // (void) payload is the same.
4089 return parent_llvm_ptr;
4169 return parent_ptr;
40904170 }
4091 const llvm_pl_index = if (layout.tag_size == 0)
4092 0
4093 else
4094 @intFromBool(layout.tag_align >= layout.payload_align);
4095 const indices: [2]*llvm.Value = .{
4096 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
4097 (try o.builder.intConst(.i32, llvm_pl_index)).toLlvm(&o.builder),
4098 };
4099 const parent_llvm_ty = (try o.lowerType(parent_ty)).toLlvm(&o.builder);
4100 return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
4171
4172 return o.builder.gepConst(.inbounds, try o.lowerType(parent_ty), parent_ptr, &.{
4173 try o.builder.intConst(.i32, 0),
4174 try o.builder.intConst(.i32, @intFromBool(
4175 layout.tag_size > 0 and layout.tag_align >= layout.payload_align,
4176 )),
4177 });
41014178 },
41024179 .Struct => {
41034180 if (parent_ty.containerLayout(mod) == .Packed) {
4104 if (!byte_aligned) return parent_llvm_ptr;
4181 if (!byte_aligned) return parent_ptr;
41054182 const llvm_usize = try o.lowerType(Type.usize);
4106 const base_addr = parent_llvm_ptr.constPtrToInt(llvm_usize.toLlvm(&o.builder));
4183 const base_addr =
4184 try o.builder.castConst(.ptrtoint, parent_ptr, llvm_usize);
41074185 // count bits of fields before this one
41084186 const prev_bits = b: {
41094187 var b: usize = 0;
41104188 for (parent_ty.structFields(mod).values()[0..field_index]) |field| {
41114189 if (field.is_comptime or !field.ty.hasRuntimeBitsIgnoreComptime(mod)) continue;
4112 b += @as(usize, @intCast(field.ty.bitSize(mod)));
4190 b += @intCast(field.ty.bitSize(mod));
41134191 }
41144192 break :b b;
41154193 };
4116 const byte_offset = (try o.builder.intConst(llvm_usize, prev_bits / 8)).toLlvm(&o.builder);
4117 const field_addr = base_addr.constAdd(byte_offset);
4118 const final_llvm_ty = o.context.pointerType(0);
4119 return field_addr.constIntToPtr(final_llvm_ty);
4194 const byte_offset = try o.builder.intConst(llvm_usize, prev_bits / 8);
4195 const field_addr = try o.builder.binConst(.add, base_addr, byte_offset);
4196 return o.builder.castConst(.inttoptr, field_addr, .ptr);
41204197 }
41214198
4122 const parent_llvm_ty = (try o.lowerType(parent_ty)).toLlvm(&o.builder);
4123 if (llvmField(parent_ty, field_index, mod)) |llvm_field| {
4124 const indices: [2]*llvm.Value = .{
4125 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
4126 (try o.builder.intConst(.i32, llvm_field.index)).toLlvm(&o.builder),
4127 };
4128 return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
4129 } else {
4130 const indices: [1]*llvm.Value = .{
4131 (try o.builder.intConst(.i32, @intFromBool(parent_ty.hasRuntimeBitsIgnoreComptime(mod)))).toLlvm(&o.builder),
4132 };
4133 return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
4134 }
4199 return o.builder.gepConst(
4200 .inbounds,
4201 try o.lowerType(parent_ty),
4202 parent_ptr,
4203 if (llvmField(parent_ty, field_index, mod)) |llvm_field| &.{
4204 try o.builder.intConst(.i32, 0),
4205 try o.builder.intConst(.i32, llvm_field.index),
4206 } else &.{
4207 try o.builder.intConst(.i32, @intFromBool(
4208 parent_ty.hasRuntimeBitsIgnoreComptime(mod),
4209 )),
4210 },
4211 );
41354212 },
41364213 .Pointer => {
41374214 assert(parent_ty.isSlice(mod));
4138 const indices: [2]*llvm.Value = .{
4139 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
4140 (try o.builder.intConst(.i32, field_index)).toLlvm(&o.builder),
4141 };
4142 const parent_llvm_ty = (try o.lowerType(parent_ty)).toLlvm(&o.builder);
4143 return parent_llvm_ty.constInBoundsGEP(parent_llvm_ptr, &indices, indices.len);
4215 return o.builder.gepConst(.inbounds, try o.lowerType(parent_ty), parent_ptr, &.{
4216 try o.builder.intConst(.i32, 0),
4217 try o.builder.intConst(.i32, field_index),
4218 });
41444219 },
41454220 else => unreachable,
41464221 }
......@@ -4148,11 +4223,7 @@ pub const Object = struct {
41484223 };
41494224 }
41504225
4151 fn lowerDeclRefValue(
4152 o: *Object,
4153 tv: TypedValue,
4154 decl_index: Module.Decl.Index,
4155 ) Error!*llvm.Value {
4226 fn lowerDeclRefValue(o: *Object, ty: Type, decl_index: Module.Decl.Index) Allocator.Error!Builder.Constant {
41564227 const mod = o.module;
41574228
41584229 // In the case of something like:
......@@ -4163,69 +4234,63 @@ pub const Object = struct {
41634234 const decl = mod.declPtr(decl_index);
41644235 if (decl.val.getFunction(mod)) |func| {
41654236 if (func.owner_decl != decl_index) {
4166 return o.lowerDeclRefValue(tv, func.owner_decl);
4237 return o.lowerDeclRefValue(ty, func.owner_decl);
41674238 }
41684239 } else if (decl.val.getExternFunc(mod)) |func| {
41694240 if (func.decl != decl_index) {
4170 return o.lowerDeclRefValue(tv, func.decl);
4241 return o.lowerDeclRefValue(ty, func.decl);
41714242 }
41724243 }
41734244
41744245 const is_fn_body = decl.ty.zigTypeTag(mod) == .Fn;
41754246 if ((!is_fn_body and !decl.ty.hasRuntimeBits(mod)) or
41764247 (is_fn_body and mod.typeToFunc(decl.ty).?.is_generic))
4177 {
4178 return o.lowerPtrToVoid(tv.ty);
4179 }
4248 return o.lowerPtrToVoid(ty);
41804249
41814250 try mod.markDeclAlive(decl);
41824251
4183 const llvm_decl_val = if (is_fn_body)
4184 (try o.resolveLlvmFunction(decl_index)).toLlvm(&o.builder)
4252 const llvm_global = if (is_fn_body)
4253 (try o.resolveLlvmFunction(decl_index)).ptrConst(&o.builder).global
41854254 else
4186 (try o.resolveGlobalDecl(decl_index)).toLlvm(&o.builder);
4255 (try o.resolveGlobalDecl(decl_index)).ptrConst(&o.builder).global;
41874256
41884257 const target = mod.getTarget();
41894258 const llvm_wanted_addrspace = toLlvmAddressSpace(decl.@"addrspace", target);
41904259 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
4191 const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) blk: {
4192 const llvm_decl_wanted_ptr_ty = o.context.pointerType(@intFromEnum(llvm_wanted_addrspace));
4193 break :blk llvm_decl_val.constAddrSpaceCast(llvm_decl_wanted_ptr_ty);
4194 } else llvm_decl_val;
4195
4196 const llvm_type = (try o.lowerType(tv.ty)).toLlvm(&o.builder);
4197 if (tv.ty.zigTypeTag(mod) == .Int) {
4198 return llvm_val.constPtrToInt(llvm_type);
4199 } else {
4200 return llvm_val.constBitCast(llvm_type);
4201 }
4260 const llvm_val = if (llvm_wanted_addrspace != llvm_actual_addrspace) try o.builder.castConst(
4261 .addrspacecast,
4262 llvm_global.toConst(),
4263 try o.builder.ptrType(llvm_wanted_addrspace),
4264 ) else llvm_global.toConst();
4265
4266 return o.builder.convConst(if (ty.isAbiInt(mod)) switch (ty.intInfo(mod).signedness) {
4267 .signed => .signed,
4268 .unsigned => .unsigned,
4269 } else .unneeded, llvm_val, try o.lowerType(ty));
42024270 }
42034271
4204 fn lowerPtrToVoid(o: *Object, ptr_ty: Type) !*llvm.Value {
4272 fn lowerPtrToVoid(o: *Object, ptr_ty: Type) Allocator.Error!Builder.Constant {
42054273 const mod = o.module;
42064274 // Even though we are pointing at something which has zero bits (e.g. `void`),
42074275 // Pointers are defined to have bits. So we must return something here.
42084276 // The value cannot be undefined, because we use the `nonnull` annotation
42094277 // for non-optional pointers. We also need to respect the alignment, even though
42104278 // the address will never be dereferenced.
4211 const llvm_usize = try o.lowerType(Type.usize);
4212 const llvm_ptr_ty = (try o.lowerType(ptr_ty)).toLlvm(&o.builder);
4213 if (ptr_ty.ptrInfo(mod).flags.alignment.toByteUnitsOptional()) |alignment| {
4214 return (try o.builder.intConst(llvm_usize, alignment)).toLlvm(&o.builder).constIntToPtr(llvm_ptr_ty);
4215 }
4216 // Note that these 0xaa values are appropriate even in release-optimized builds
4217 // because we need a well-defined value that is not null, and LLVM does not
4218 // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR
4219 // instruction is followed by a `wrap_optional`, it will return this value
4220 // verbatim, and the result should test as non-null.
4221 const target = mod.getTarget();
4222 const int = try o.builder.intConst(llvm_usize, @as(u64, switch (target.ptrBitWidth()) {
4279 const int: u64 = ptr_ty.ptrInfo(mod).flags.alignment.toByteUnitsOptional() orelse
4280 // Note that these 0xaa values are appropriate even in release-optimized builds
4281 // because we need a well-defined value that is not null, and LLVM does not
4282 // have an "undef_but_not_null" attribute. As an example, if this `alloc` AIR
4283 // instruction is followed by a `wrap_optional`, it will return this value
4284 // verbatim, and the result should test as non-null.
4285 switch (mod.getTarget().ptrBitWidth()) {
42234286 16 => 0xaaaa,
42244287 32 => 0xaaaaaaaa,
42254288 64 => 0xaaaaaaaa_aaaaaaaa,
42264289 else => unreachable,
4227 }));
4228 return int.toLlvm(&o.builder).constIntToPtr(llvm_ptr_ty);
4290 };
4291 const llvm_usize = try o.lowerType(Type.usize);
4292 const llvm_ptr_ty = try o.lowerType(ptr_ty);
4293 return o.builder.castConst(.inttoptr, try o.builder.intConst(llvm_usize, int), llvm_ptr_ty);
42294294 }
42304295
42314296 fn addAttr(o: *Object, val: *llvm.Value, index: llvm.AttributeIndex, name: []const u8) void {
......@@ -4436,26 +4501,29 @@ pub const DeclGen = struct {
44364501 _ = try o.resolveLlvmFunction(extern_func.decl);
44374502 } else {
44384503 const target = mod.getTarget();
4439 const object_index = try o.resolveGlobalDecl(decl_index);
4440 const object = object_index.ptr(&o.builder);
4441 const global = object.global.ptr(&o.builder);
4442 var llvm_global = object.global.toLlvm(&o.builder);
4443 global.alignment = Builder.Alignment.fromByteUnits(decl.getAlignment(mod));
4504 const object = try o.resolveGlobalDecl(decl_index);
4505 const global = object.ptrConst(&o.builder).global;
4506 var llvm_global = global.toLlvm(&o.builder);
4507 global.ptr(&o.builder).alignment = Builder.Alignment.fromByteUnits(decl.getAlignment(mod));
44444508 llvm_global.setAlignment(decl.getAlignment(mod));
4445 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s| llvm_global.setSection(s);
4509 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section| {
4510 global.ptr(&o.builder).section = try o.builder.string(section);
4511 llvm_global.setSection(section);
4512 }
44464513 assert(decl.has_tv);
4447 const init_val = if (decl.val.getVariable(mod)) |variable| init_val: {
4448 object.mutability = .global;
4449 break :init_val variable.init;
4514 const init_val = if (decl.val.getVariable(mod)) |decl_var| init_val: {
4515 object.ptr(&o.builder).mutability = .global;
4516 break :init_val decl_var.init;
44504517 } else init_val: {
4451 object.mutability = .constant;
4518 object.ptr(&o.builder).mutability = .constant;
44524519 llvm_global.setGlobalConstant(.True);
44534520 break :init_val decl.val.toIntern();
44544521 };
44554522 if (init_val != .none) {
4456 const llvm_init = try o.lowerValue(.{ .ty = decl.ty, .val = init_val.toValue() });
4457 if (llvm_global.globalGetValueType() == llvm_init.typeOf()) {
4458 llvm_global.setInitializer(llvm_init);
4523 const llvm_init = try o.lowerValue(init_val);
4524 if (llvm_global.globalGetValueType() == llvm_init.typeOf(&o.builder).toLlvm(&o.builder)) {
4525 object.ptr(&o.builder).init = llvm_init;
4526 llvm_global.setInitializer(llvm_init.toLlvm(&o.builder));
44594527 } else {
44604528 // LLVM does not allow us to change the type of globals. So we must
44614529 // create a new global with the correct type, copy all its attributes,
......@@ -4472,20 +4540,21 @@ pub const DeclGen = struct {
44724540 // Related: https://github.com/ziglang/zig/issues/13265
44734541 const llvm_global_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
44744542 const new_global = o.llvm_module.addGlobalInAddressSpace(
4475 llvm_init.typeOf(),
4543 llvm_init.typeOf(&o.builder).toLlvm(&o.builder),
44764544 "",
44774545 @intFromEnum(llvm_global_addrspace),
44784546 );
44794547 new_global.setLinkage(llvm_global.getLinkage());
44804548 new_global.setUnnamedAddr(llvm_global.getUnnamedAddress());
44814549 new_global.setAlignment(llvm_global.getAlignment());
4482 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |s|
4483 new_global.setSection(s);
4484 new_global.setInitializer(llvm_init);
4550 if (mod.intern_pool.stringToSliceUnwrap(decl.@"linksection")) |section|
4551 new_global.setSection(section);
4552 new_global.setInitializer(llvm_init.toLlvm(&o.builder));
44854553 // TODO: How should this work then the address space of a global changed?
44864554 llvm_global.replaceAllUsesWith(new_global);
44874555 new_global.takeName(llvm_global);
4488 o.builder.llvm_globals.items[@intFromEnum(object.global)] = new_global;
4556 o.builder.llvm_globals.items[@intFromEnum(object.ptrConst(&o.builder).global)] =
4557 new_global;
44894558 llvm_global.deleteGlobal();
44904559 llvm_global = new_global;
44914560 }
......@@ -4601,24 +4670,45 @@ pub const FuncGen = struct {
46014670 fn resolveValue(self: *FuncGen, tv: TypedValue) !*llvm.Value {
46024671 const o = self.dg.object;
46034672 const mod = o.module;
4604 const llvm_val = try o.lowerValue(tv);
4605 if (!isByRef(tv.ty, mod)) return llvm_val;
4673 const llvm_val = try o.lowerValue(tv.val.toIntern());
4674 if (!isByRef(tv.ty, mod)) return llvm_val.toLlvm(&o.builder);
46064675
46074676 // We have an LLVM value but we need to create a global constant and
46084677 // set the value as its initializer, and then return a pointer to the global.
46094678 const target = mod.getTarget();
46104679 const llvm_wanted_addrspace = toLlvmAddressSpace(.generic, target);
46114680 const llvm_actual_addrspace = toLlvmGlobalAddressSpace(.generic, target);
4612 const global = o.llvm_module.addGlobalInAddressSpace(llvm_val.typeOf(), "", @intFromEnum(llvm_actual_addrspace));
4613 global.setInitializer(llvm_val);
4614 global.setLinkage(.Private);
4615 global.setGlobalConstant(.True);
4616 global.setUnnamedAddr(.True);
4617 global.setAlignment(tv.ty.abiAlignment(mod));
4681 const llvm_ty = llvm_val.typeOf(&o.builder);
4682 const llvm_alignment = tv.ty.abiAlignment(mod);
4683 const llvm_global = o.llvm_module.addGlobalInAddressSpace(llvm_ty.toLlvm(&o.builder), "", @intFromEnum(llvm_actual_addrspace));
4684 llvm_global.setInitializer(llvm_val.toLlvm(&o.builder));
4685 llvm_global.setLinkage(.Private);
4686 llvm_global.setGlobalConstant(.True);
4687 llvm_global.setUnnamedAddr(.True);
4688 llvm_global.setAlignment(llvm_alignment);
4689
4690 var global = Builder.Global{
4691 .linkage = .private,
4692 .unnamed_addr = .unnamed_addr,
4693 .type = llvm_ty,
4694 .alignment = Builder.Alignment.fromByteUnits(llvm_alignment),
4695 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
4696 };
4697 var variable = Builder.Variable{
4698 .global = @enumFromInt(o.builder.globals.count()),
4699 .mutability = .constant,
4700 .init = llvm_val,
4701 };
4702 try o.builder.llvm_globals.append(o.gpa, llvm_global);
4703 _ = try o.builder.addGlobal(.none, global);
4704 try o.builder.variables.append(o.gpa, variable);
4705
46184706 const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace)
4619 global.constAddrSpaceCast(self.context.pointerType(@intFromEnum(llvm_wanted_addrspace)))
4707 llvm_global.constAddrSpaceCast(
4708 (try o.builder.ptrType(llvm_wanted_addrspace)).toLlvm(&o.builder),
4709 )
46204710 else
4621 global;
4711 llvm_global;
46224712 return addrspace_casted_ptr;
46234713 }
46244714
......@@ -5197,10 +5287,7 @@ pub const FuncGen = struct {
51975287 const msg_decl_index = mod.panic_messages[@intFromEnum(panic_id)].unwrap().?;
51985288 const msg_decl = mod.declPtr(msg_decl_index);
51995289 const msg_len = msg_decl.ty.childType(mod).arrayLen(mod);
5200 const msg_ptr = try o.lowerValue(.{
5201 .ty = msg_decl.ty,
5202 .val = msg_decl.val,
5203 });
5290 const msg_ptr = try o.lowerValue(try msg_decl.internValue(mod));
52045291 const null_opt_addr_global = try o.getNullOptAddr();
52055292 const target = mod.getTarget();
52065293 const llvm_usize = try o.lowerType(Type.usize);
......@@ -5212,9 +5299,9 @@ pub const FuncGen = struct {
52125299 // ptr @2, ; addr (null ?usize)
52135300 // )
52145301 const args = [4]*llvm.Value{
5215 msg_ptr,
5302 msg_ptr.toLlvm(&o.builder),
52165303 (try o.builder.intConst(llvm_usize, msg_len)).toLlvm(&o.builder),
5217 fg.context.pointerType(0).constNull(),
5304 (try o.builder.nullConst(.ptr)).toLlvm(&o.builder),
52185305 null_opt_addr_global,
52195306 };
52205307 const panic_func = mod.funcInfo(mod.panic_func_index);
......@@ -5672,8 +5759,8 @@ pub const FuncGen = struct {
56725759
56735760 if (!err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
56745761 const is_err = err: {
5675 const err_set_ty = (try o.lowerType(Type.anyerror)).toLlvm(&o.builder);
5676 const zero = err_set_ty.constNull();
5762 const err_set_ty = Builder.Type.err_int.toLlvm(&o.builder);
5763 const zero = (try o.builder.intConst(Builder.Type.err_int, 0)).toLlvm(&o.builder);
56775764 if (!payload_has_bits) {
56785765 // TODO add alignment to this load
56795766 const loaded = if (operand_is_ptr)
......@@ -6034,7 +6121,10 @@ pub const FuncGen = struct {
60346121 const array_llvm_ty = (try o.lowerType(array_ty)).toLlvm(&o.builder);
60356122 const elem_ty = array_ty.childType(mod);
60366123 if (isByRef(array_ty, mod)) {
6037 const indices: [2]*llvm.Value = .{ Builder.Type.i32.toLlvm(&o.builder).constNull(), rhs };
6124 const indices: [2]*llvm.Value = .{
6125 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
6126 rhs,
6127 };
60386128 if (isByRef(elem_ty, mod)) {
60396129 const elem_ptr = self.builder.buildInBoundsGEP(array_llvm_ty, array_llvm_val, &indices, indices.len, "");
60406130 if (canElideLoad(self, body_tail))
......@@ -6082,7 +6172,10 @@ pub const FuncGen = struct {
60826172 // TODO: when we go fully opaque pointers in LLVM 16 we can remove this branch
60836173 const ptr = if (ptr_ty.isSinglePointer(mod)) ptr: {
60846174 // If this is a single-item pointer to an array, we need another index in the GEP.
6085 const indices: [2]*llvm.Value = .{ Builder.Type.i32.toLlvm(&o.builder).constNull(), rhs };
6175 const indices: [2]*llvm.Value = .{
6176 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
6177 rhs,
6178 };
60866179 break :ptr self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
60876180 } else ptr: {
60886181 const indices: [1]*llvm.Value = .{rhs};
......@@ -6105,7 +6198,8 @@ pub const FuncGen = struct {
61056198 const bin_op = self.air.extraData(Air.Bin, ty_pl.payload).data;
61066199 const ptr_ty = self.typeOf(bin_op.lhs);
61076200 const elem_ty = ptr_ty.childType(mod);
6108 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod)) return o.lowerPtrToVoid(ptr_ty);
6201 if (!elem_ty.hasRuntimeBitsIgnoreComptime(mod))
6202 return (try o.lowerPtrToVoid(ptr_ty)).toLlvm(&o.builder);
61096203
61106204 const base_ptr = try self.resolveInst(bin_op.lhs);
61116205 const rhs = try self.resolveInst(bin_op.rhs);
......@@ -6116,7 +6210,10 @@ pub const FuncGen = struct {
61166210 const llvm_elem_ty = (try o.lowerPtrElemTy(elem_ty)).toLlvm(&o.builder);
61176211 if (ptr_ty.isSinglePointer(mod)) {
61186212 // If this is a single-item pointer to an array, we need another index in the GEP.
6119 const indices: [2]*llvm.Value = .{ Builder.Type.i32.toLlvm(&o.builder).constNull(), rhs };
6213 const indices: [2]*llvm.Value = .{
6214 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
6215 rhs,
6216 };
61206217 return self.builder.buildInBoundsGEP(llvm_elem_ty, base_ptr, &indices, indices.len, "");
61216218 } else {
61226219 const indices: [1]*llvm.Value = .{rhs};
......@@ -6829,8 +6926,11 @@ pub const FuncGen = struct {
68296926 operand;
68306927 if (payload_ty.isSlice(mod)) {
68316928 const slice_ptr = self.builder.buildExtractValue(loaded, 0, "");
6832 const ptr_ty = (try o.lowerType(payload_ty.slicePtrFieldType(mod))).toLlvm(&o.builder);
6833 return self.builder.buildICmp(pred, slice_ptr, ptr_ty.constNull(), "");
6929 const ptr_ty = try o.builder.ptrType(toLlvmAddressSpace(
6930 payload_ty.ptrAddressSpace(mod),
6931 mod.getTarget(),
6932 ));
6933 return self.builder.buildICmp(pred, slice_ptr, (try o.builder.nullConst(ptr_ty)).toLlvm(&o.builder), "");
68346934 }
68356935 return self.builder.buildICmp(pred, loaded, optional_llvm_ty.constNull(), "");
68366936 }
......@@ -6867,8 +6967,7 @@ pub const FuncGen = struct {
68676967 const operand_ty = self.typeOf(un_op);
68686968 const err_union_ty = if (operand_is_ptr) operand_ty.childType(mod) else operand_ty;
68696969 const payload_ty = err_union_ty.errorUnionPayload(mod);
6870 const err_set_ty = (try o.lowerType(Type.anyerror)).toLlvm(&o.builder);
6871 const zero = err_set_ty.constNull();
6970 const zero = (try o.builder.intConst(Builder.Type.err_int, 0)).toLlvm(&o.builder);
68726971
68736972 if (err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod)) {
68746973 const val: Builder.Constant = switch (op) {
......@@ -6892,7 +6991,7 @@ pub const FuncGen = struct {
68926991 if (operand_is_ptr or isByRef(err_union_ty, mod)) {
68936992 const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder);
68946993 const err_field_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, err_field_index, "");
6895 const loaded = self.builder.buildLoad(err_set_ty, err_field_ptr, "");
6994 const loaded = self.builder.buildLoad(Builder.Type.err_int.toLlvm(&o.builder), err_field_ptr, "");
68966995 return self.builder.buildICmp(op, loaded, zero, "");
68976996 }
68986997
......@@ -7057,9 +7156,9 @@ pub const FuncGen = struct {
70577156 const err_union_ty = self.typeOf(ty_op.operand).childType(mod);
70587157
70597158 const payload_ty = err_union_ty.errorUnionPayload(mod);
7060 const non_error_val = try o.lowerValue(.{ .ty = Type.anyerror, .val = try mod.intValue(Type.err_int, 0) });
7159 const non_error_val = try o.lowerValue((try mod.intValue(Type.err_int, 0)).toIntern());
70617160 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
7062 _ = self.builder.buildStore(non_error_val, operand);
7161 _ = self.builder.buildStore(non_error_val.toLlvm(&o.builder), operand);
70637162 return operand;
70647163 }
70657164 const err_union_llvm_ty = (try o.lowerType(err_union_ty)).toLlvm(&o.builder);
......@@ -7067,7 +7166,7 @@ pub const FuncGen = struct {
70677166 const error_offset = errUnionErrorOffset(payload_ty, mod);
70687167 // First set the non-error value.
70697168 const non_null_ptr = self.builder.buildStructGEP(err_union_llvm_ty, operand, error_offset, "");
7070 const store_inst = self.builder.buildStore(non_error_val, non_null_ptr);
7169 const store_inst = self.builder.buildStore(non_error_val.toLlvm(&o.builder), non_null_ptr);
70717170 store_inst.setAlignment(Type.anyerror.abiAlignment(mod));
70727171 }
70737172 // Then return the payload pointer (only if it is used).
......@@ -7146,7 +7245,7 @@ pub const FuncGen = struct {
71467245 if (!payload_ty.hasRuntimeBitsIgnoreComptime(mod)) {
71477246 return operand;
71487247 }
7149 const ok_err_code = (try o.lowerType(Type.anyerror)).toLlvm(&o.builder).constNull();
7248 const ok_err_code = (try o.builder.intConst(Builder.Type.err_int, 0)).toLlvm(&o.builder);
71507249 const err_un_llvm_ty = (try o.lowerType(err_un_ty)).toLlvm(&o.builder);
71517250
71527251 const payload_offset = errUnionPayloadOffset(payload_ty, mod);
......@@ -7606,7 +7705,10 @@ pub const FuncGen = struct {
76067705 switch (ptr_ty.ptrSize(mod)) {
76077706 .One => {
76087707 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
7609 const indices: [2]*llvm.Value = .{ Builder.Type.i32.toLlvm(&o.builder).constNull(), offset };
7708 const indices: [2]*llvm.Value = .{
7709 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
7710 offset,
7711 };
76107712 return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
76117713 },
76127714 .C, .Many => {
......@@ -7635,7 +7737,8 @@ pub const FuncGen = struct {
76357737 .One => {
76367738 // It's a pointer to an array, so according to LLVM we need an extra GEP index.
76377739 const indices: [2]*llvm.Value = .{
7638 Builder.Type.i32.toLlvm(&o.builder).constNull(), negative_offset,
7740 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
7741 negative_offset,
76397742 };
76407743 return self.builder.buildInBoundsGEP(llvm_elem_ty, ptr, &indices, indices.len, "");
76417744 },
......@@ -8448,7 +8551,7 @@ pub const FuncGen = struct {
84488551 const ptr_ty = self.typeOfIndex(inst);
84498552 const pointee_type = ptr_ty.childType(mod);
84508553 if (!pointee_type.isFnOrHasRuntimeBitsIgnoreComptime(mod))
8451 return o.lowerPtrToVoid(ptr_ty);
8554 return (try o.lowerPtrToVoid(ptr_ty)).toLlvm(&o.builder);
84528555
84538556 const pointee_llvm_ty = (try o.lowerType(pointee_type)).toLlvm(&o.builder);
84548557 const alignment = ptr_ty.ptrAlignment(mod);
......@@ -8460,7 +8563,8 @@ pub const FuncGen = struct {
84608563 const mod = o.module;
84618564 const ptr_ty = self.typeOfIndex(inst);
84628565 const ret_ty = ptr_ty.childType(mod);
8463 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod)) return o.lowerPtrToVoid(ptr_ty);
8566 if (!ret_ty.isFnOrHasRuntimeBitsIgnoreComptime(mod))
8567 return (try o.lowerPtrToVoid(ptr_ty)).toLlvm(&o.builder);
84648568 if (self.ret_ptr) |ret_ptr| return ret_ptr;
84658569 const ret_llvm_ty = (try o.lowerType(ret_ty)).toLlvm(&o.builder);
84668570 return self.buildAlloca(ret_llvm_ty, ptr_ty.ptrAlignment(mod));
......@@ -8566,18 +8670,19 @@ pub const FuncGen = struct {
85668670 _ = inst;
85678671 const o = self.dg.object;
85688672 const mod = o.module;
8569 const llvm_usize = (try o.lowerType(Type.usize)).toLlvm(&o.builder);
8673 const llvm_usize = try o.lowerType(Type.usize);
85708674 const target = mod.getTarget();
85718675 if (!target_util.supportsReturnAddress(target)) {
85728676 // https://github.com/ziglang/zig/issues/11946
8573 return llvm_usize.constNull();
8677 return (try o.builder.intConst(llvm_usize, 0)).toLlvm(&o.builder);
85748678 }
85758679
8576 const llvm_i32 = Builder.Type.i32.toLlvm(&o.builder);
85778680 const llvm_fn = try self.getIntrinsic("llvm.returnaddress", &.{});
8578 const params = [_]*llvm.Value{llvm_i32.constNull()};
8681 const params = [_]*llvm.Value{
8682 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
8683 };
85798684 const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
8580 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
8685 return self.builder.buildPtrToInt(ptr_val, llvm_usize.toLlvm(&o.builder), "");
85818686 }
85828687
85838688 fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
......@@ -8589,7 +8694,9 @@ pub const FuncGen = struct {
85898694 break :blk o.llvm_module.addFunction(llvm_fn_name, fn_type.toLlvm(&o.builder));
85908695 };
85918696
8592 const params = [_]*llvm.Value{Builder.Type.i32.toLlvm(&o.builder).constNull()};
8697 const params = [_]*llvm.Value{
8698 (try o.builder.intConst(.i32, 0)).toLlvm(&o.builder),
8699 };
85938700 const ptr_val = self.builder.buildCall(llvm_fn.globalGetValueType(), llvm_fn, &params, params.len, .Fast, .Auto, "");
85948701 const llvm_usize = (try o.lowerType(Type.usize)).toLlvm(&o.builder);
85958702 return self.builder.buildPtrToInt(ptr_val, llvm_usize, "");
......@@ -9060,10 +9167,9 @@ pub const FuncGen = struct {
90609167 const operand_ty = self.typeOf(ty_op.operand);
90619168 const operand = try self.resolveInst(ty_op.operand);
90629169
9063 const llvm_i1 = Builder.Type.i1.toLlvm(&o.builder);
90649170 const fn_val = try self.getIntrinsic(llvm_fn_name, &.{try o.lowerType(operand_ty)});
90659171
9066 const params = [_]*llvm.Value{ operand, llvm_i1.constNull() };
9172 const params = [_]*llvm.Value{ operand, Builder.Constant.false.toLlvm(&o.builder) };
90679173 const wrong_size_result = self.builder.buildCall(fn_val.globalGetValueType(), fn_val, &params, params.len, .C, .Auto, "");
90689174 const result_ty = self.typeOfIndex(inst);
90699175 const result_llvm_ty = (try o.lowerType(result_ty)).toLlvm(&o.builder);
......@@ -9170,11 +9276,9 @@ pub const FuncGen = struct {
91709276
91719277 for (names) |name| {
91729278 const err_int = @as(Module.ErrorInt, @intCast(mod.global_error_set.getIndex(name).?));
9173 const this_tag_int_value = try o.lowerValue(.{
9174 .ty = Type.err_int,
9175 .val = try mod.intValue(Type.err_int, err_int),
9176 });
9177 switch_instr.addCase(this_tag_int_value, valid_block);
9279 const this_tag_int_value =
9280 try o.lowerValue((try mod.intValue(Type.err_int, err_int)).toIntern());
9281 switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), valid_block);
91789282 }
91799283 self.builder.positionBuilderAtEnd(valid_block);
91809284 _ = self.builder.buildBr(end_block);
......@@ -9258,13 +9362,9 @@ pub const FuncGen = struct {
92589362
92599363 for (enum_type.names, 0..) |_, field_index_usize| {
92609364 const field_index = @as(u32, @intCast(field_index_usize));
9261 const this_tag_int_value = int: {
9262 break :int try o.lowerValue(.{
9263 .ty = enum_ty,
9264 .val = try mod.enumValueFieldIndex(enum_ty, field_index),
9265 });
9266 };
9267 switch_instr.addCase(this_tag_int_value, named_block);
9365 const this_tag_int_value =
9366 try o.lowerValue((try mod.enumValueFieldIndex(enum_ty, field_index)).toIntern());
9367 switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), named_block);
92689368 }
92699369 self.builder.positionBuilderAtEnd(named_block);
92709370 _ = self.builder.buildRet(Builder.Constant.true.toLlvm(&o.builder));
......@@ -9371,11 +9471,9 @@ pub const FuncGen = struct {
93719471 slice_global.setAlignment(slice_alignment);
93729472
93739473 const return_block = self.context.appendBasicBlock(fn_val, "Name");
9374 const this_tag_int_value = try o.lowerValue(.{
9375 .ty = enum_ty,
9376 .val = try mod.enumValueFieldIndex(enum_ty, field_index),
9377 });
9378 switch_instr.addCase(this_tag_int_value, return_block);
9474 const this_tag_int_value =
9475 try o.lowerValue((try mod.enumValueFieldIndex(enum_ty, field_index)).toIntern());
9476 switch_instr.addCase(this_tag_int_value.toLlvm(&o.builder), return_block);
93799477
93809478 self.builder.positionBuilderAtEnd(return_block);
93819479 const loaded = self.builder.buildLoad(llvm_ret_ty, slice_global, "");
......@@ -9404,7 +9502,12 @@ pub const FuncGen = struct {
94049502 const fn_type = try o.builder.fnType(.i1, &.{Builder.Type.err_int}, .normal);
94059503 const llvm_fn = o.llvm_module.addFunction(lt_errors_fn_name, fn_type.toLlvm(&o.builder));
94069504
9505 llvm_fn.setLinkage(.Internal);
9506 llvm_fn.setFunctionCallConv(.Fast);
9507 o.addCommonFnAttributes(llvm_fn);
9508
94079509 var global = Builder.Global{
9510 .linkage = .internal,
94089511 .type = fn_type,
94099512 .kind = .{ .function = @enumFromInt(o.builder.functions.items.len) },
94109513 };
......@@ -9412,10 +9515,6 @@ pub const FuncGen = struct {
94129515 .global = @enumFromInt(o.builder.globals.count()),
94139516 };
94149517
9415 llvm_fn.setLinkage(.Internal);
9416 llvm_fn.setFunctionCallConv(.Fast);
9417 o.addCommonFnAttributes(llvm_fn);
9418
94199518 try o.builder.llvm_globals.append(self.gpa, llvm_fn);
94209519 _ = try o.builder.addGlobal(try o.builder.string(lt_errors_fn_name), global);
94219520 try o.builder.functions.append(self.gpa, function);
......@@ -9431,7 +9530,7 @@ pub const FuncGen = struct {
94319530
94329531 const error_name_table_ptr = try self.getErrorNameTable();
94339532 const ptr_slice_llvm_ty = self.context.pointerType(0);
9434 const error_name_table = self.builder.buildLoad(ptr_slice_llvm_ty, error_name_table_ptr, "");
9533 const error_name_table = self.builder.buildLoad(ptr_slice_llvm_ty, error_name_table_ptr.toLlvm(&o.builder), "");
94359534 const indices = [_]*llvm.Value{operand};
94369535 const error_name_ptr = self.builder.buildInBoundsGEP(slice_llvm_ty, error_name_table, &indices, indices.len, "");
94379536 return self.builder.buildLoad(slice_llvm_ty, error_name_ptr, "");
......@@ -9588,18 +9687,18 @@ pub const FuncGen = struct {
95889687 .Add => switch (scalar_ty.zigTypeTag(mod)) {
95899688 .Int => return self.builder.buildAddReduce(operand),
95909689 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9591 const scalar_llvm_ty = (try o.lowerType(scalar_ty)).toLlvm(&o.builder);
9592 const neutral_value = scalar_llvm_ty.constReal(-0.0);
9593 return self.builder.buildFPAddReduce(neutral_value, operand);
9690 const scalar_llvm_ty = try o.lowerType(scalar_ty);
9691 const neutral_value = try o.builder.fpConst(scalar_llvm_ty, -0.0);
9692 return self.builder.buildFPAddReduce(neutral_value.toLlvm(&o.builder), operand);
95949693 },
95959694 else => unreachable,
95969695 },
95979696 .Mul => switch (scalar_ty.zigTypeTag(mod)) {
95989697 .Int => return self.builder.buildMulReduce(operand),
95999698 .Float => if (intrinsicsAllowed(scalar_ty, target)) {
9600 const scalar_llvm_ty = (try o.lowerType(scalar_ty)).toLlvm(&o.builder);
9601 const neutral_value = scalar_llvm_ty.constReal(1.0);
9602 return self.builder.buildFPMulReduce(neutral_value, operand);
9699 const scalar_llvm_ty = try o.lowerType(scalar_ty);
9700 const neutral_value = try o.builder.fpConst(scalar_llvm_ty, 1.0);
9701 return self.builder.buildFPMulReduce(neutral_value.toLlvm(&o.builder), operand);
96039702 },
96049703 else => unreachable,
96059704 },
......@@ -9626,17 +9725,14 @@ pub const FuncGen = struct {
96269725
96279726 const param_llvm_ty = try o.lowerType(scalar_ty);
96289727 const libc_fn = try self.getLibcFunction(fn_name, &(.{param_llvm_ty} ** 2), param_llvm_ty);
9629 const init_value = try o.lowerValue(.{
9630 .ty = scalar_ty,
9631 .val = try mod.floatValue(scalar_ty, switch (reduce.operation) {
9632 .Min => std.math.nan(f32),
9633 .Max => std.math.nan(f32),
9634 .Add => -0.0,
9635 .Mul => 1.0,
9636 else => unreachable,
9637 }),
9638 });
9639 return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_value);
9728 const init_value = try o.lowerValue((try mod.floatValue(scalar_ty, switch (reduce.operation) {
9729 .Min => std.math.nan(f32),
9730 .Max => std.math.nan(f32),
9731 .Add => -0.0,
9732 .Mul => 1.0,
9733 else => unreachable,
9734 })).toIntern());
9735 return self.buildReducedCall(libc_fn, operand, operand_ty.vectorLen(mod), init_value.toLlvm(&o.builder));
96409736 }
96419737
96429738 fn airAggregateInit(self: *FuncGen, inst: Air.Inst.Index) !?*llvm.Value {
......@@ -10030,26 +10126,42 @@ pub const FuncGen = struct {
1003010126 return self.amdgcnWorkIntrinsic(dimension, 0, "llvm.amdgcn.workgroup.id");
1003110127 }
1003210128
10033 fn getErrorNameTable(self: *FuncGen) !*llvm.Value {
10129 fn getErrorNameTable(self: *FuncGen) Allocator.Error!Builder.Variable.Index {
1003410130 const o = self.dg.object;
10035 if (o.error_name_table) |table| {
10036 return table;
10037 }
10131 const table = o.error_name_table;
10132 if (table != .none) return table;
1003810133
1003910134 const mod = o.module;
1004010135 const slice_ty = Type.slice_const_u8_sentinel_0;
1004110136 const slice_alignment = slice_ty.abiAlignment(mod);
10042 const llvm_slice_ptr_ty = self.context.pointerType(0); // TODO: Address space
10137 const undef_init = try o.builder.undefConst(.ptr); // TODO: Address space
1004310138
10044 const error_name_table_global = o.llvm_module.addGlobal(llvm_slice_ptr_ty, "__zig_err_name_table");
10045 error_name_table_global.setInitializer(llvm_slice_ptr_ty.getUndef());
10139 const name = try o.builder.string("__zig_err_name_table");
10140 const error_name_table_global = o.llvm_module.addGlobal(Builder.Type.ptr.toLlvm(&o.builder), name.toSlice(&o.builder).?);
10141 error_name_table_global.setInitializer(undef_init.toLlvm(&o.builder));
1004610142 error_name_table_global.setLinkage(.Private);
1004710143 error_name_table_global.setGlobalConstant(.True);
1004810144 error_name_table_global.setUnnamedAddr(.True);
1004910145 error_name_table_global.setAlignment(slice_alignment);
1005010146
10051 o.error_name_table = error_name_table_global;
10052 return error_name_table_global;
10147 var global = Builder.Global{
10148 .linkage = .private,
10149 .unnamed_addr = .unnamed_addr,
10150 .type = .ptr,
10151 .alignment = Builder.Alignment.fromByteUnits(slice_alignment),
10152 .kind = .{ .variable = @enumFromInt(o.builder.variables.items.len) },
10153 };
10154 var variable = Builder.Variable{
10155 .global = @enumFromInt(o.builder.globals.count()),
10156 .mutability = .constant,
10157 .init = undef_init,
10158 };
10159 try o.builder.llvm_globals.append(o.gpa, error_name_table_global);
10160 _ = try o.builder.addGlobal(name, global);
10161 try o.builder.variables.append(o.gpa, variable);
10162
10163 o.error_name_table = global.kind.variable;
10164 return global.kind.variable;
1005310165 }
1005410166
1005510167 /// Assumes the optional is not pointer-like and payload has bits.
......@@ -10273,14 +10385,14 @@ pub const FuncGen = struct {
1027310385 return llvm_inst;
1027410386 }
1027510387
10276 const int_elem_ty = (try o.builder.intType(@intCast(info.packed_offset.host_size * 8))).toLlvm(&o.builder);
10277 const containing_int = self.builder.buildLoad(int_elem_ty, ptr, "");
10388 const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8));
10389 const containing_int = self.builder.buildLoad(containing_int_ty.toLlvm(&o.builder), ptr, "");
1027810390 containing_int.setAlignment(ptr_alignment);
1027910391 containing_int.setVolatile(ptr_volatile);
1028010392
1028110393 const elem_bits = @as(c_uint, @intCast(ptr_ty.childType(mod).bitSize(mod)));
10282 const shift_amt = containing_int.typeOf().constInt(info.packed_offset.bit_offset, .False);
10283 const shifted_value = self.builder.buildLShr(containing_int, shift_amt, "");
10394 const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset);
10395 const shifted_value = self.builder.buildLShr(containing_int, shift_amt.toLlvm(&o.builder), "");
1028410396 const elem_llvm_ty = (try o.lowerType(elem_ty)).toLlvm(&o.builder);
1028510397
1028610398 if (isByRef(elem_ty, mod)) {
......@@ -10346,30 +10458,29 @@ pub const FuncGen = struct {
1034610458 }
1034710459
1034810460 if (info.packed_offset.host_size != 0) {
10349 const int_elem_ty = (try o.builder.intType(@intCast(info.packed_offset.host_size * 8))).toLlvm(&o.builder);
10350 const containing_int = self.builder.buildLoad(int_elem_ty, ptr, "");
10461 const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8));
10462 const containing_int = self.builder.buildLoad(containing_int_ty.toLlvm(&o.builder), ptr, "");
1035110463 assert(ordering == .NotAtomic);
1035210464 containing_int.setAlignment(ptr_alignment);
1035310465 containing_int.setVolatile(ptr_volatile);
1035410466 const elem_bits = @as(c_uint, @intCast(ptr_ty.childType(mod).bitSize(mod)));
10355 const containing_int_ty = containing_int.typeOf();
10356 const shift_amt = containing_int_ty.constInt(info.packed_offset.bit_offset, .False);
10467 const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset);
1035710468 // Convert to equally-sized integer type in order to perform the bit
1035810469 // operations on the value to store
10359 const value_bits_type = (try o.builder.intType(@intCast(elem_bits))).toLlvm(&o.builder);
10470 const value_bits_type = try o.builder.intType(@intCast(elem_bits));
1036010471 const value_bits = if (elem_ty.isPtrAtRuntime(mod))
10361 self.builder.buildPtrToInt(elem, value_bits_type, "")
10472 self.builder.buildPtrToInt(elem, value_bits_type.toLlvm(&o.builder), "")
1036210473 else
10363 self.builder.buildBitCast(elem, value_bits_type, "");
10474 self.builder.buildBitCast(elem, value_bits_type.toLlvm(&o.builder), "");
1036410475
10365 var mask_val = value_bits_type.constAllOnes();
10366 mask_val = mask_val.constZExt(containing_int_ty);
10367 mask_val = mask_val.constShl(shift_amt);
10476 var mask_val = (try o.builder.intConst(value_bits_type, -1)).toLlvm(&o.builder);
10477 mask_val = mask_val.constZExt(containing_int_ty.toLlvm(&o.builder));
10478 mask_val = mask_val.constShl(shift_amt.toLlvm(&o.builder));
1036810479 mask_val = mask_val.constNot();
1036910480
1037010481 const anded_containing_int = self.builder.buildAnd(containing_int, mask_val, "");
10371 const extended_value = self.builder.buildZExt(value_bits, containing_int_ty, "");
10372 const shifted_value = self.builder.buildShl(extended_value, shift_amt, "");
10482 const extended_value = self.builder.buildZExt(value_bits, containing_int_ty.toLlvm(&o.builder), "");
10483 const shifted_value = self.builder.buildShl(extended_value, shift_amt.toLlvm(&o.builder), "");
1037310484 const ored_value = self.builder.buildOr(shifted_value, anded_containing_int, "");
1037410485
1037510486 const store_inst = self.builder.buildStore(ored_value, ptr);
src/codegen/llvm/Builder.zig+1865-176
......@@ -27,7 +27,7 @@ globals: std.AutoArrayHashMapUnmanaged(String, Global) = .{},
2727next_unnamed_global: String = @enumFromInt(0),
2828next_unique_global_id: std.AutoHashMapUnmanaged(String, u32) = .{},
2929aliases: std.ArrayListUnmanaged(Alias) = .{},
30objects: std.ArrayListUnmanaged(Object) = .{},
30variables: std.ArrayListUnmanaged(Variable) = .{},
3131functions: std.ArrayListUnmanaged(Function) = .{},
3232
3333constant_map: std.AutoArrayHashMapUnmanaged(void, void) = .{},
......@@ -35,10 +35,12 @@ constant_items: std.MultiArrayList(Constant.Item) = .{},
3535constant_extra: std.ArrayListUnmanaged(u32) = .{},
3636constant_limbs: std.ArrayListUnmanaged(std.math.big.Limb) = .{},
3737
38pub const expected_fields_len = 32;
39pub const expected_gep_indices_len = 8;
40
3841pub const String = enum(u32) {
3942 none = std.math.maxInt(u31),
4043 empty,
41 debugme,
4244 _,
4345
4446 pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 {
......@@ -58,22 +60,23 @@ pub const String = enum(u32) {
5860 _: std.fmt.FormatOptions,
5961 writer: anytype,
6062 ) @TypeOf(writer).Error!void {
63 if (comptime std.mem.indexOfNone(u8, fmt_str, "@\"")) |_|
64 @compileError("invalid format string: '" ++ fmt_str ++ "'");
6165 assert(data.string != .none);
6266 const slice = data.string.toSlice(data.builder) orelse
6367 return writer.print("{d}", .{@intFromEnum(data.string)});
64 const need_quotes = if (comptime std.mem.eql(u8, fmt_str, ""))
65 !isValidIdentifier(slice)
66 else if (comptime std.mem.eql(u8, fmt_str, "\""))
67 true
68 else
69 @compileError("invalid format string: '" ++ fmt_str ++ "'");
70 if (need_quotes) try writer.writeByte('\"');
71 for (slice) |character| switch (character) {
68 const full_slice = slice[0 .. slice.len + comptime @intFromBool(
69 std.mem.indexOfScalar(u8, fmt_str, '@') != null,
70 )];
71 const need_quotes = (comptime std.mem.indexOfScalar(u8, fmt_str, '"') != null) or
72 !isValidIdentifier(full_slice);
73 if (need_quotes) try writer.writeByte('"');
74 for (full_slice) |character| switch (character) {
7275 '\\' => try writer.writeAll("\\\\"),
7376 ' '...'"' - 1, '"' + 1...'\\' - 1, '\\' + 1...'~' => try writer.writeByte(character),
7477 else => try writer.print("\\{X:0>2}", .{character}),
7578 };
76 if (need_quotes) try writer.writeByte('\"');
79 if (need_quotes) try writer.writeByte('"');
7780 }
7881 pub fn fmt(self: String, builder: *const Builder) std.fmt.Formatter(format) {
7982 return .{ .data = .{ .string = self, .builder = builder } };
......@@ -92,8 +95,8 @@ pub const String = enum(u32) {
9295 pub fn hash(_: Adapter, key: []const u8) u32 {
9396 return @truncate(std.hash.Wyhash.hash(0, key));
9497 }
95 pub fn eql(ctx: Adapter, lhs: []const u8, _: void, rhs_index: usize) bool {
96 return std.mem.eql(u8, lhs, String.fromIndex(rhs_index).toSlice(ctx.builder).?);
98 pub fn eql(ctx: Adapter, lhs_key: []const u8, _: void, rhs_index: usize) bool {
99 return std.mem.eql(u8, lhs_key, String.fromIndex(rhs_index).toSlice(ctx.builder).?);
97100 }
98101 };
99102};
......@@ -204,9 +207,167 @@ pub const Type = enum(u32) {
204207 pub const Item = packed struct(u32) {
205208 tag: Tag,
206209 data: ExtraIndex,
210
211 pub const ExtraIndex = u28;
207212 };
208213
209 pub const ExtraIndex = u28;
214 pub fn tag(self: Type, builder: *const Builder) Tag {
215 return builder.type_items.items[@intFromEnum(self)].tag;
216 }
217
218 pub fn unnamedTag(self: Type, builder: *const Builder) Tag {
219 const item = builder.type_items.items[@intFromEnum(self)];
220 return switch (item.tag) {
221 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
222 .unnamedTag(builder),
223 else => item.tag,
224 };
225 }
226
227 pub fn scalarTag(self: Type, builder: *const Builder) Tag {
228 const item = builder.type_items.items[@intFromEnum(self)];
229 return switch (item.tag) {
230 .vector, .scalable_vector => builder.typeExtraData(Type.Vector, item.data)
231 .child.tag(builder),
232 else => item.tag,
233 };
234 }
235
236 pub fn isFn(self: Type, builder: *const Builder) bool {
237 return switch (self.tag(builder)) {
238 .function, .vararg_function => true,
239 else => false,
240 };
241 }
242
243 pub fn fnKind(self: Type, builder: *const Builder) Type.Function.Kind {
244 return switch (self.tag(builder)) {
245 .function => .normal,
246 .vararg_function => .vararg,
247 else => unreachable,
248 };
249 }
250
251 pub fn isVector(self: Type, builder: *const Builder) bool {
252 return switch (self.tag(builder)) {
253 .vector, .scalable_vector => true,
254 else => false,
255 };
256 }
257
258 pub fn vectorKind(self: Type, builder: *const Builder) Type.Vector.Kind {
259 return switch (self.tag(builder)) {
260 .vector => .normal,
261 .scalable_vector => .scalable,
262 else => unreachable,
263 };
264 }
265
266 pub fn isStruct(self: Type, builder: *const Builder) bool {
267 return switch (self.tag(builder)) {
268 .structure, .packed_structure, .named_structure => true,
269 else => false,
270 };
271 }
272
273 pub fn structKind(self: Type, builder: *const Builder) Type.Structure.Kind {
274 return switch (self.unnamedTag(builder)) {
275 .structure => .normal,
276 .packed_structure => .@"packed",
277 else => unreachable,
278 };
279 }
280
281 pub fn scalarBits(self: Type, builder: *const Builder) u24 {
282 return switch (self) {
283 .void, .label, .token, .metadata, .none, .x86_amx => unreachable,
284 .i1 => 1,
285 .i8 => 8,
286 .half, .bfloat, .i16 => 16,
287 .i29 => 29,
288 .float, .i32 => 32,
289 .double, .i64, .x86_mmx => 64,
290 .x86_fp80, .i80 => 80,
291 .fp128, .ppc_fp128, .i128 => 128,
292 .ptr => @panic("TODO: query data layout"),
293 _ => {
294 const item = builder.type_items.items[@intFromEnum(self)];
295 return switch (item.tag) {
296 .simple,
297 .function,
298 .vararg_function,
299 => unreachable,
300 .integer => @intCast(item.data),
301 .pointer => @panic("TODO: query data layout"),
302 .target => unreachable,
303 .vector,
304 .scalable_vector,
305 => builder.typeExtraData(Type.Vector, item.data).child.scalarBits(builder),
306 .small_array,
307 .array,
308 .structure,
309 .packed_structure,
310 .named_structure,
311 => unreachable,
312 };
313 },
314 };
315 }
316
317 pub fn childType(self: Type, builder: *const Builder) Type {
318 const item = builder.type_items.items[@intFromEnum(self)];
319 return switch (item.tag) {
320 .vector,
321 .scalable_vector,
322 .small_array,
323 => builder.typeExtraData(Type.Vector, item.data).child,
324 .array => builder.typeExtraData(Type.Array, item.data).child,
325 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body,
326 else => unreachable,
327 };
328 }
329
330 pub fn vectorLen(self: Type, builder: *const Builder) u32 {
331 const item = builder.type_items.items[@intFromEnum(self)];
332 return switch (item.tag) {
333 .vector,
334 .scalable_vector,
335 => builder.typeExtraData(Type.Vector, item.data).len,
336 else => unreachable,
337 };
338 }
339
340 pub fn aggregateLen(self: Type, builder: *const Builder) u64 {
341 const item = builder.type_items.items[@intFromEnum(self)];
342 return switch (item.tag) {
343 .vector,
344 .scalable_vector,
345 .small_array,
346 => builder.typeExtraData(Type.Vector, item.data).len,
347 .array => builder.typeExtraData(Type.Array, item.data).len(),
348 .structure,
349 .packed_structure,
350 => builder.typeExtraData(Type.Structure, item.data).fields_len,
351 .named_structure => builder.typeExtraData(Type.NamedStructure, item.data).body
352 .aggregateLen(builder),
353 else => unreachable,
354 };
355 }
356
357 pub fn structFields(self: Type, builder: *const Builder) []const Type {
358 const item = builder.type_items.items[@intFromEnum(self)];
359 switch (item.tag) {
360 .structure,
361 .packed_structure,
362 => {
363 const extra = builder.typeExtraDataTrail(Type.Structure, item.data);
364 return @ptrCast(builder.type_extra.items[extra.end..][0..extra.data.fields_len]);
365 },
366 .named_structure => return builder.typeExtraData(Type.NamedStructure, item.data).body
367 .structFields(builder),
368 else => unreachable,
369 }
370 }
210371
211372 pub const FormatData = struct {
212373 type: Type,
......@@ -220,11 +381,11 @@ pub const Type = enum(u32) {
220381 ) @TypeOf(writer).Error!void {
221382 assert(data.type != .none);
222383 if (std.enums.tagName(Type, data.type)) |name| return writer.writeAll(name);
223 const type_item = data.builder.type_items.items[@intFromEnum(data.type)];
224 switch (type_item.tag) {
384 const item = data.builder.type_items.items[@intFromEnum(data.type)];
385 switch (item.tag) {
225386 .simple => unreachable,
226387 .function, .vararg_function => {
227 const extra = data.builder.typeExtraDataTrail(Type.Function, type_item.data);
388 const extra = data.builder.typeExtraDataTrail(Type.Function, item.data);
228389 const params: []const Type =
229390 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.params_len]);
230391 if (!comptime std.mem.eql(u8, fmt_str, ">"))
......@@ -235,7 +396,7 @@ pub const Type = enum(u32) {
235396 if (index > 0) try writer.writeAll(", ");
236397 try writer.print("{%}", .{param.fmt(data.builder)});
237398 }
238 switch (type_item.tag) {
399 switch (item.tag) {
239400 .function => {},
240401 .vararg_function => {
241402 if (params.len > 0) try writer.writeAll(", ");
......@@ -246,10 +407,10 @@ pub const Type = enum(u32) {
246407 try writer.writeByte(')');
247408 }
248409 },
249 .integer => try writer.print("i{d}", .{type_item.data}),
250 .pointer => try writer.print("ptr{}", .{@as(AddrSpace, @enumFromInt(type_item.data))}),
410 .integer => try writer.print("i{d}", .{item.data}),
411 .pointer => try writer.print("ptr{}", .{@as(AddrSpace, @enumFromInt(item.data))}),
251412 .target => {
252 const extra = data.builder.typeExtraDataTrail(Type.Target, type_item.data);
413 const extra = data.builder.typeExtraDataTrail(Type.Target, item.data);
253414 const types: []const Type =
254415 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.types_len]);
255416 const ints: []const u32 = @ptrCast(data.builder.type_extra.items[extra.end +
......@@ -262,26 +423,28 @@ pub const Type = enum(u32) {
262423 try writer.writeByte(')');
263424 },
264425 .vector => {
265 const extra = data.builder.typeExtraData(Type.Vector, type_item.data);
426 const extra = data.builder.typeExtraData(Type.Vector, item.data);
266427 try writer.print("<{d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) });
267428 },
268429 .scalable_vector => {
269 const extra = data.builder.typeExtraData(Type.Vector, type_item.data);
430 const extra = data.builder.typeExtraData(Type.Vector, item.data);
270431 try writer.print("<vscale x {d} x {%}>", .{ extra.len, extra.child.fmt(data.builder) });
271432 },
272433 .small_array => {
273 const extra = data.builder.typeExtraData(Type.Vector, type_item.data);
434 const extra = data.builder.typeExtraData(Type.Vector, item.data);
274435 try writer.print("[{d} x {%}]", .{ extra.len, extra.child.fmt(data.builder) });
275436 },
276437 .array => {
277 const extra = data.builder.typeExtraData(Type.Array, type_item.data);
438 const extra = data.builder.typeExtraData(Type.Array, item.data);
278439 try writer.print("[{d} x {%}]", .{ extra.len(), extra.child.fmt(data.builder) });
279440 },
280 .structure, .packed_structure => {
281 const extra = data.builder.typeExtraDataTrail(Type.Structure, type_item.data);
441 .structure,
442 .packed_structure,
443 => {
444 const extra = data.builder.typeExtraDataTrail(Type.Structure, item.data);
282445 const fields: []const Type =
283446 @ptrCast(data.builder.type_extra.items[extra.end..][0..extra.data.fields_len]);
284 switch (type_item.tag) {
447 switch (item.tag) {
285448 .structure => {},
286449 .packed_structure => try writer.writeByte('<'),
287450 else => unreachable,
......@@ -292,14 +455,14 @@ pub const Type = enum(u32) {
292455 try writer.print("{%}", .{field.fmt(data.builder)});
293456 }
294457 try writer.writeAll(" }");
295 switch (type_item.tag) {
458 switch (item.tag) {
296459 .structure => {},
297460 .packed_structure => try writer.writeByte('>'),
298461 else => unreachable,
299462 }
300463 },
301464 .named_structure => {
302 const extra = data.builder.typeExtraData(Type.NamedStructure, type_item.data);
465 const extra = data.builder.typeExtraData(Type.NamedStructure, item.data);
303466 if (comptime std.mem.eql(u8, fmt_str, "%")) try writer.print("%{}", .{
304467 extra.id.fmt(data.builder),
305468 }) else switch (extra.body) {
......@@ -323,7 +486,7 @@ pub const Type = enum(u32) {
323486};
324487
325488pub const Linkage = enum {
326 default,
489 external,
327490 private,
328491 internal,
329492 available_externally,
......@@ -334,7 +497,6 @@ pub const Linkage = enum {
334497 extern_weak,
335498 linkonce_odr,
336499 weak_odr,
337 external,
338500
339501 pub fn format(
340502 self: Linkage,
......@@ -342,14 +504,14 @@ pub const Linkage = enum {
342504 _: std.fmt.FormatOptions,
343505 writer: anytype,
344506 ) @TypeOf(writer).Error!void {
345 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
507 if (self != .external) try writer.print(" {s}", .{@tagName(self)});
346508 }
347509};
348510
349511pub const Preemption = enum {
350 default,
351512 dso_preemptable,
352513 dso_local,
514 implicit_dso_local,
353515
354516 pub fn format(
355517 self: Preemption,
......@@ -357,7 +519,7 @@ pub const Preemption = enum {
357519 _: std.fmt.FormatOptions,
358520 writer: anytype,
359521 ) @TypeOf(writer).Error!void {
360 if (self != .default) try writer.print(" {s}", .{@tagName(self)});
522 if (self == .dso_local) try writer.print(" {s}", .{@tagName(self)});
361523 }
362524};
363525
......@@ -554,22 +716,25 @@ pub const Alignment = enum(u6) {
554716};
555717
556718pub const Global = struct {
557 linkage: Linkage = .default,
558 preemption: Preemption = .default,
719 linkage: Linkage = .external,
720 preemption: Preemption = .dso_preemptable,
559721 visibility: Visibility = .default,
560722 dll_storage_class: DllStorageClass = .default,
561723 unnamed_addr: UnnamedAddr = .default,
562724 addr_space: AddrSpace = .default,
563725 externally_initialized: ExternallyInitialized = .default,
564726 type: Type,
727 section: String = .none,
728 partition: String = .none,
565729 alignment: Alignment = .default,
566730 kind: union(enum) {
567731 alias: Alias.Index,
568 object: Object.Index,
732 variable: Variable.Index,
569733 function: Function.Index,
570734 },
571735
572736 pub const Index = enum(u32) {
737 none = std.math.maxInt(u32),
573738 _,
574739
575740 pub fn ptr(self: Index, builder: *Builder) *Global {
......@@ -580,11 +745,33 @@ pub const Global = struct {
580745 return &builder.globals.values()[@intFromEnum(self)];
581746 }
582747
748 pub fn toConst(self: Index) Constant {
749 return @enumFromInt(@intFromEnum(Constant.first_global) + @intFromEnum(self));
750 }
751
583752 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
584753 assert(builder.useLibLlvm());
585754 return builder.llvm_globals.items[@intFromEnum(self)];
586755 }
587756
757 const FormatData = struct {
758 global: Index,
759 builder: *const Builder,
760 };
761 fn format(
762 data: FormatData,
763 comptime _: []const u8,
764 _: std.fmt.FormatOptions,
765 writer: anytype,
766 ) @TypeOf(writer).Error!void {
767 try writer.print("@{}", .{
768 data.builder.globals.keys()[@intFromEnum(data.global)].fmt(data.builder),
769 });
770 }
771 pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
772 return .{ .data = .{ .global = self, .builder = builder } };
773 }
774
588775 pub fn rename(self: Index, builder: *Builder, name: String) Allocator.Error!void {
589776 try builder.ensureUnusedCapacityGlobal(name);
590777 self.renameAssumeCapacity(builder, name);
......@@ -618,12 +805,32 @@ pub const Global = struct {
618805 builder.llvm_globals.items[index].setValueName2(slice.ptr, slice.len);
619806 }
620807 };
808
809 pub fn updateAttributes(self: *Global) void {
810 switch (self.linkage) {
811 .private, .internal => {
812 self.visibility = .default;
813 self.dll_storage_class = .default;
814 self.preemption = .implicit_dso_local;
815 },
816 .extern_weak => if (self.preemption == .implicit_dso_local) {
817 self.preemption = .dso_local;
818 },
819 else => switch (self.visibility) {
820 .default => if (self.preemption == .implicit_dso_local) {
821 self.preemption = .dso_local;
822 },
823 else => self.preemption = .implicit_dso_local,
824 },
825 }
826 }
621827};
622828
623829pub const Alias = struct {
624830 global: Global.Index,
625831
626832 pub const Index = enum(u32) {
833 none = std.math.maxInt(u32),
627834 _,
628835
629836 pub fn ptr(self: Index, builder: *Builder) *Alias {
......@@ -640,21 +847,22 @@ pub const Alias = struct {
640847 };
641848};
642849
643pub const Object = struct {
850pub const Variable = struct {
644851 global: Global.Index,
645852 thread_local: ThreadLocal = .default,
646853 mutability: enum { global, constant } = .global,
647854 init: Constant = .no_init,
648855
649856 pub const Index = enum(u32) {
857 none = std.math.maxInt(u32),
650858 _,
651859
652 pub fn ptr(self: Index, builder: *Builder) *Object {
653 return &builder.objects.items[@intFromEnum(self)];
860 pub fn ptr(self: Index, builder: *Builder) *Variable {
861 return &builder.variables.items[@intFromEnum(self)];
654862 }
655863
656 pub fn ptrConst(self: Index, builder: *const Builder) *const Object {
657 return &builder.objects.items[@intFromEnum(self)];
864 pub fn ptrConst(self: Index, builder: *const Builder) *const Variable {
865 return &builder.variables.items[@intFromEnum(self)];
658866 }
659867
660868 pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
......@@ -670,6 +878,7 @@ pub const Function = struct {
670878 blocks: std.ArrayListUnmanaged(Block) = .{},
671879
672880 pub const Index = enum(u32) {
881 none = std.math.maxInt(u32),
673882 _,
674883
675884 pub fn ptr(self: Index, builder: *Builder) *Function {
......@@ -693,13 +902,13 @@ pub const Function = struct {
693902 block,
694903 };
695904
696 pub const Index = enum(u31) { _ };
905 pub const Index = enum(u32) { _ };
697906 };
698907
699908 pub const Block = struct {
700909 body: std.ArrayListUnmanaged(Instruction.Index) = .{},
701910
702 pub const Index = enum(u31) { _ };
911 pub const Index = enum(u32) { _ };
703912 };
704913
705914 pub fn deinit(self: *Function, gpa: Allocator) void {
......@@ -709,6 +918,36 @@ pub const Function = struct {
709918 }
710919};
711920
921pub const FloatCondition = enum(u4) {
922 oeq = 1,
923 ogt = 2,
924 oge = 3,
925 olt = 4,
926 ole = 5,
927 one = 6,
928 ord = 7,
929 uno = 8,
930 ueq = 9,
931 ugt = 10,
932 uge = 11,
933 ult = 12,
934 ule = 13,
935 une = 14,
936};
937
938pub const IntegerCondition = enum(u6) {
939 eq = 32,
940 ne = 33,
941 ugt = 34,
942 uge = 35,
943 ult = 36,
944 ule = 37,
945 sgt = 38,
946 sge = 39,
947 slt = 40,
948 sle = 41,
949};
950
712951pub const Constant = enum(u32) {
713952 false,
714953 true,
......@@ -719,15 +958,24 @@ pub const Constant = enum(u32) {
719958 const first_global: Constant = @enumFromInt(1 << 30);
720959
721960 pub const Tag = enum(u6) {
722 integer_positive,
723 integer_negative,
961 positive_integer,
962 negative_integer,
963 half,
964 bfloat,
965 float,
966 double,
967 fp128,
968 x86_fp80,
969 ppc_fp128,
724970 null,
725971 none,
726972 structure,
973 packed_structure,
727974 array,
975 string,
976 string_null,
728977 vector,
729978 zeroinitializer,
730 global,
731979 undef,
732980 poison,
733981 blockaddress,
......@@ -747,6 +995,7 @@ pub const Constant = enum(u32) {
747995 bitcast,
748996 addrspacecast,
749997 getelementptr,
998 @"getelementptr inbounds",
750999 icmp,
7511000 fcmp,
7521001 extractelement,
......@@ -765,7 +1014,9 @@ pub const Constant = enum(u32) {
7651014
7661015 pub const Item = struct {
7671016 tag: Tag,
768 data: u32,
1017 data: ExtraIndex,
1018
1019 const ExtraIndex = u32;
7691020 };
7701021
7711022 pub const Integer = packed struct(u64) {
......@@ -775,6 +1026,80 @@ pub const Constant = enum(u32) {
7751026 pub const limbs = @divExact(@bitSizeOf(Integer), @bitSizeOf(std.math.big.Limb));
7761027 };
7771028
1029 pub const Double = struct {
1030 lo: u32,
1031 hi: u32,
1032 };
1033
1034 pub const Fp80 = struct {
1035 lo_lo: u32,
1036 lo_hi: u32,
1037 hi: u32,
1038 };
1039
1040 pub const Fp128 = struct {
1041 lo_lo: u32,
1042 lo_hi: u32,
1043 hi_lo: u32,
1044 hi_hi: u32,
1045 };
1046
1047 pub const Aggregate = struct {
1048 type: Type,
1049 };
1050
1051 pub const BlockAddress = extern struct {
1052 function: Function.Index,
1053 block: Function.Block.Index,
1054 };
1055
1056 pub const FunctionReference = struct {
1057 function: Function.Index,
1058 };
1059
1060 pub const Cast = extern struct {
1061 arg: Constant,
1062 type: Type,
1063
1064 pub const Signedness = enum { unsigned, signed, unneeded };
1065 };
1066
1067 pub const GetElementPtr = struct {
1068 type: Type,
1069 base: Constant,
1070 indices_len: u32,
1071
1072 pub const Kind = enum { normal, inbounds };
1073 };
1074
1075 pub const Compare = struct {
1076 cond: u32,
1077 lhs: Constant,
1078 rhs: Constant,
1079 };
1080
1081 pub const ExtractElement = struct {
1082 arg: Constant,
1083 index: Constant,
1084 };
1085
1086 pub const InsertElement = struct {
1087 arg: Constant,
1088 elem: Constant,
1089 index: Constant,
1090 };
1091
1092 pub const ShuffleVector = struct {
1093 lhs: Constant,
1094 rhs: Constant,
1095 mask: Constant,
1096 };
1097
1098 pub const Binary = extern struct {
1099 lhs: Constant,
1100 rhs: Constant,
1101 };
1102
7781103 pub fn unwrap(self: Constant) union(enum) {
7791104 constant: u30,
7801105 global: Global.Index,
......@@ -785,6 +1110,307 @@ pub const Constant = enum(u32) {
7851110 .{ .global = @enumFromInt(@intFromEnum(self) - @intFromEnum(first_global)) };
7861111 }
7871112
1113 pub fn typeOf(self: Constant, builder: *Builder) Type {
1114 switch (self.unwrap()) {
1115 .constant => |constant| {
1116 const item = builder.constant_items.get(constant);
1117 return switch (item.tag) {
1118 .positive_integer,
1119 .negative_integer,
1120 => @as(
1121 *align(@alignOf(std.math.big.Limb)) Integer,
1122 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]),
1123 ).type,
1124 .half => .half,
1125 .bfloat => .bfloat,
1126 .float => .float,
1127 .double => .double,
1128 .fp128 => .fp128,
1129 .x86_fp80 => .x86_fp80,
1130 .ppc_fp128 => .ppc_fp128,
1131 .null,
1132 .none,
1133 .zeroinitializer,
1134 .undef,
1135 .poison,
1136 => @enumFromInt(item.data),
1137 .structure,
1138 .packed_structure,
1139 .array,
1140 .vector,
1141 => builder.constantExtraData(Aggregate, item.data).type,
1142 .string,
1143 .string_null,
1144 => builder.arrayTypeAssumeCapacity(
1145 @as(String, @enumFromInt(item.data)).toSlice(builder).?.len +
1146 @intFromBool(item.tag == .string_null),
1147 .i8,
1148 ),
1149 .blockaddress => builder.ptrTypeAssumeCapacity(
1150 builder.constantExtraData(BlockAddress, item.data)
1151 .function.ptrConst(builder).global.ptrConst(builder).addr_space,
1152 ),
1153 .dso_local_equivalent,
1154 .no_cfi,
1155 => builder.ptrTypeAssumeCapacity(
1156 builder.constantExtraData(FunctionReference, item.data)
1157 .function.ptrConst(builder).global.ptrConst(builder).addr_space,
1158 ),
1159 .trunc,
1160 .zext,
1161 .sext,
1162 .fptrunc,
1163 .fpext,
1164 .fptoui,
1165 .fptosi,
1166 .uitofp,
1167 .sitofp,
1168 .ptrtoint,
1169 .inttoptr,
1170 .bitcast,
1171 .addrspacecast,
1172 => builder.constantExtraData(Cast, item.data).type,
1173 .getelementptr,
1174 .@"getelementptr inbounds",
1175 => {
1176 const extra = builder.constantExtraDataTrail(GetElementPtr, item.data);
1177 const indices: []const Constant = @ptrCast(builder.constant_extra
1178 .items[extra.end..][0..extra.data.indices_len]);
1179 const base_ty = extra.data.base.typeOf(builder);
1180 if (!base_ty.isVector(builder)) for (indices) |index| {
1181 const index_ty = index.typeOf(builder);
1182 if (!index_ty.isVector(builder)) continue;
1183 switch (index_ty.vectorKind(builder)) {
1184 inline else => |kind| return builder.vectorTypeAssumeCapacity(
1185 kind,
1186 index_ty.vectorLen(builder),
1187 base_ty,
1188 ),
1189 }
1190 };
1191 return base_ty;
1192 },
1193 .icmp, .fcmp => {
1194 const ty = builder.constantExtraData(Compare, item.data).lhs.typeOf(builder);
1195 return switch (ty) {
1196 .half,
1197 .bfloat,
1198 .float,
1199 .double,
1200 .fp128,
1201 .x86_fp80,
1202 .ppc_fp128,
1203 .i1,
1204 .i8,
1205 .i16,
1206 .i29,
1207 .i32,
1208 .i64,
1209 .i80,
1210 .i128,
1211 => ty,
1212 else => if (ty.isVector(builder)) switch (ty.vectorKind(builder)) {
1213 inline else => |kind| builder
1214 .vectorTypeAssumeCapacity(kind, ty.vectorLen(builder), .i1),
1215 } else ty,
1216 };
1217 },
1218 .extractelement => builder.constantExtraData(ExtractElement, item.data)
1219 .arg.typeOf(builder).childType(builder),
1220 .insertelement => builder.constantExtraData(InsertElement, item.data)
1221 .arg.typeOf(builder),
1222 .shufflevector => {
1223 const extra = builder.constantExtraData(ShuffleVector, item.data);
1224 const ty = extra.lhs.typeOf(builder);
1225 return switch (ty.vectorKind(builder)) {
1226 inline else => |kind| builder.vectorTypeAssumeCapacity(
1227 kind,
1228 extra.mask.typeOf(builder).vectorLen(builder),
1229 ty.childType(builder),
1230 ),
1231 };
1232 },
1233 .add,
1234 .sub,
1235 .mul,
1236 .shl,
1237 .lshr,
1238 .ashr,
1239 .@"and",
1240 .@"or",
1241 .xor,
1242 => builder.constantExtraData(Binary, item.data).lhs.typeOf(builder),
1243 };
1244 },
1245 .global => |global| return builder.ptrTypeAssumeCapacity(
1246 global.ptrConst(builder).addr_space,
1247 ),
1248 }
1249 }
1250
1251 pub fn isZeroInit(self: Constant, builder: *const Builder) bool {
1252 switch (self.unwrap()) {
1253 .constant => |constant| {
1254 const item = builder.constant_items.get(constant);
1255 return switch (item.tag) {
1256 .positive_integer => {
1257 const extra: *align(@alignOf(std.math.big.Limb)) Integer =
1258 @ptrCast(builder.constant_limbs.items[item.data..][0..Integer.limbs]);
1259 const limbs = builder.constant_limbs
1260 .items[item.data + Integer.limbs ..][0..extra.limbs_len];
1261 return std.mem.eql(std.math.big.Limb, limbs, &.{0});
1262 },
1263 .half, .bfloat, .float => item.data == 0,
1264 .double => {
1265 const extra = builder.constantExtraData(Constant.Double, item.data);
1266 return extra.lo == 0 and extra.hi == 0;
1267 },
1268 .fp128, .ppc_fp128 => {
1269 const extra = builder.constantExtraData(Constant.Fp128, item.data);
1270 return extra.lo_lo == 0 and extra.lo_hi == 0 and
1271 extra.hi_lo == 0 and extra.hi_hi == 0;
1272 },
1273 .x86_fp80 => {
1274 const extra = builder.constantExtraData(Constant.Fp80, item.data);
1275 return extra.lo_lo == 0 and extra.lo_hi == 0 and extra.hi == 0;
1276 },
1277 .vector => {
1278 const extra = builder.constantExtraDataTrail(Aggregate, item.data);
1279 const len = extra.data.type.aggregateLen(builder);
1280 const vals: []const Constant =
1281 @ptrCast(builder.constant_extra.items[extra.end..][0..len]);
1282 for (vals) |val| if (!val.isZeroInit(builder)) return false;
1283 return true;
1284 },
1285 .null, .zeroinitializer => true,
1286 else => false,
1287 };
1288 },
1289 .global => return false,
1290 }
1291 }
1292
1293 pub const FormatData = struct {
1294 constant: Constant,
1295 builder: *Builder,
1296 };
1297 fn format(
1298 data: FormatData,
1299 comptime fmt_str: []const u8,
1300 _: std.fmt.FormatOptions,
1301 writer: anytype,
1302 ) @TypeOf(writer).Error!void {
1303 if (comptime std.mem.eql(u8, fmt_str, "%")) {
1304 try writer.print("{%} ", .{data.constant.typeOf(data.builder).fmt(data.builder)});
1305 } else if (comptime std.mem.eql(u8, fmt_str, " ")) {
1306 if (data.constant == .no_init) return;
1307 try writer.writeByte(' ');
1308 }
1309 assert(data.constant != .no_init);
1310 if (std.enums.tagName(Constant, data.constant)) |name| return writer.writeAll(name);
1311 switch (data.constant.unwrap()) {
1312 .constant => |constant| {
1313 const item = data.builder.constant_items.get(constant);
1314 switch (item.tag) {
1315 .positive_integer,
1316 .negative_integer,
1317 => {
1318 const extra: *align(@alignOf(std.math.big.Limb)) Integer =
1319 @ptrCast(data.builder.constant_limbs.items[item.data..][0..Integer.limbs]);
1320 const limbs = data.builder.constant_limbs
1321 .items[item.data + Integer.limbs ..][0..extra.limbs_len];
1322 const bigint = std.math.big.int.Const{
1323 .limbs = limbs,
1324 .positive = item.tag == .positive_integer,
1325 };
1326 const ExpectedContents = extern struct {
1327 string: [(64 * 8 / std.math.log2(10)) + 2]u8,
1328 limbs: [
1329 std.math.big.int.calcToStringLimbsBufferLen(
1330 64 / @sizeOf(std.math.big.Limb),
1331 10,
1332 )
1333 ]std.math.big.Limb,
1334 };
1335 var stack align(@alignOf(ExpectedContents)) =
1336 std.heap.stackFallback(@sizeOf(ExpectedContents), data.builder.gpa);
1337 const allocator = stack.get();
1338 const str = bigint.toStringAlloc(allocator, 10, undefined) catch
1339 return writer.writeAll("...");
1340 defer allocator.free(str);
1341 try writer.writeAll(str);
1342 },
1343 .null,
1344 .none,
1345 .zeroinitializer,
1346 .undef,
1347 .poison,
1348 => try writer.writeAll(@tagName(item.tag)),
1349 .structure,
1350 .packed_structure,
1351 .array,
1352 .vector,
1353 => {
1354 const extra = data.builder.constantExtraDataTrail(Aggregate, item.data);
1355 const len = extra.data.type.aggregateLen(data.builder);
1356 const vals: []const Constant =
1357 @ptrCast(data.builder.constant_extra.items[extra.end..][0..len]);
1358
1359 try writer.writeAll(switch (item.tag) {
1360 .structure => "{ ",
1361 .packed_structure => "<{ ",
1362 .array => "[",
1363 .vector => "<",
1364 else => unreachable,
1365 });
1366 for (vals, 0..) |val, index| {
1367 if (index > 0) try writer.writeAll(", ");
1368 try writer.print("{%}", .{val.fmt(data.builder)});
1369 }
1370 try writer.writeAll(switch (item.tag) {
1371 .structure => " }",
1372 .packed_structure => " }>",
1373 .array => "]",
1374 .vector => ">",
1375 else => unreachable,
1376 });
1377 },
1378 .string => try writer.print(
1379 \\c{"}
1380 , .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}),
1381 .string_null => try writer.print(
1382 \\c{"@}
1383 , .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}),
1384 .blockaddress => {
1385 const extra = data.builder.constantExtraData(BlockAddress, item.data);
1386 const function = extra.function.ptrConst(data.builder);
1387 try writer.print("{s}({}, %{d})", .{
1388 @tagName(item.tag),
1389 function.global.fmt(data.builder),
1390 @intFromEnum(extra.block), // TODO
1391 });
1392 },
1393 .dso_local_equivalent,
1394 .no_cfi,
1395 => {
1396 const extra = data.builder.constantExtraData(FunctionReference, item.data);
1397 try writer.print("{s} {}", .{
1398 @tagName(item.tag),
1399 extra.function.ptrConst(data.builder).global.fmt(data.builder),
1400 });
1401 },
1402 else => try writer.print("<{s}:0x{X}>", .{
1403 @tagName(item.tag), @intFromEnum(data.constant),
1404 }),
1405 }
1406 },
1407 .global => |global| try writer.print("{}", .{global.fmt(data.builder)}),
1408 }
1409 }
1410 pub fn fmt(self: Constant, builder: *Builder) std.fmt.Formatter(format) {
1411 return .{ .data = .{ .constant = self, .builder = builder } };
1412 }
1413
7881414 pub fn toLlvm(self: Constant, builder: *const Builder) *llvm.Value {
7891415 assert(builder.useLibLlvm());
7901416 return switch (self.unwrap()) {
......@@ -813,7 +1439,6 @@ pub const Value = enum(u32) {
8131439pub fn init(self: *Builder) Allocator.Error!void {
8141440 try self.string_indices.append(self.gpa, 0);
8151441 assert(try self.string("") == .empty);
816 assert(try self.string("debugme") == .debugme);
8171442
8181443 {
8191444 const static_len = @typeInfo(Type).Enum.fields.len - 1;
......@@ -821,10 +1446,9 @@ pub fn init(self: *Builder) Allocator.Error!void {
8211446 try self.type_items.ensureTotalCapacity(self.gpa, static_len);
8221447 if (self.useLibLlvm()) try self.llvm_types.ensureTotalCapacity(self.gpa, static_len);
8231448 inline for (@typeInfo(Type.Simple).Enum.fields) |simple_field| {
824 const result = self.typeNoExtraAssumeCapacity(.{
825 .tag = .simple,
826 .data = simple_field.value,
827 });
1449 const result = self.getOrPutTypeNoExtraAssumeCapacity(
1450 .{ .tag = .simple, .data = simple_field.value },
1451 );
8281452 assert(result.new and result.type == @field(Type, simple_field.name));
8291453 if (self.useLibLlvm()) self.llvm_types.appendAssumeCapacity(
8301454 @field(llvm.Context, simple_field.name ++ "Type")(self.llvm_context),
......@@ -838,6 +1462,7 @@ pub fn init(self: *Builder) Allocator.Error!void {
8381462
8391463 assert(try self.intConst(.i1, 0) == .false);
8401464 assert(try self.intConst(.i1, 1) == .true);
1465 assert(try self.noneConst(.token) == .none);
8411466}
8421467
8431468pub fn deinit(self: *Builder) void {
......@@ -858,7 +1483,7 @@ pub fn deinit(self: *Builder) void {
8581483 self.globals.deinit(self.gpa);
8591484 self.next_unique_global_id.deinit(self.gpa);
8601485 self.aliases.deinit(self.gpa);
861 self.objects.deinit(self.gpa);
1486 self.variables.deinit(self.gpa);
8621487 for (self.functions.items) |*function| function.deinit(self.gpa);
8631488 self.functions.deinit(self.gpa);
8641489
......@@ -1110,19 +1735,19 @@ pub fn fnType(
11101735 params: []const Type,
11111736 kind: Type.Function.Kind,
11121737) Allocator.Error!Type {
1113 try self.ensureUnusedCapacityTypes(1, Type.Function, params.len);
1738 try self.ensureUnusedTypeCapacity(1, Type.Function, params.len);
11141739 return switch (kind) {
11151740 inline else => |comptime_kind| self.fnTypeAssumeCapacity(ret, params, comptime_kind),
11161741 };
11171742}
11181743
11191744pub fn intType(self: *Builder, bits: u24) Allocator.Error!Type {
1120 try self.ensureUnusedCapacityTypes(1, null, 0);
1745 try self.ensureUnusedTypeCapacity(1, null, 0);
11211746 return self.intTypeAssumeCapacity(bits);
11221747}
11231748
11241749pub fn ptrType(self: *Builder, addr_space: AddrSpace) Allocator.Error!Type {
1125 try self.ensureUnusedCapacityTypes(1, null, 0);
1750 try self.ensureUnusedTypeCapacity(1, null, 0);
11261751 return self.ptrTypeAssumeCapacity(addr_space);
11271752}
11281753
......@@ -1132,7 +1757,7 @@ pub fn vectorType(
11321757 len: u32,
11331758 child: Type,
11341759) Allocator.Error!Type {
1135 try self.ensureUnusedCapacityTypes(1, Type.Vector, 0);
1760 try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);
11361761 return switch (kind) {
11371762 inline else => |comptime_kind| self.vectorTypeAssumeCapacity(comptime_kind, len, child),
11381763 };
......@@ -1140,7 +1765,7 @@ pub fn vectorType(
11401765
11411766pub fn arrayType(self: *Builder, len: u64, child: Type) Allocator.Error!Type {
11421767 comptime assert(@sizeOf(Type.Array) >= @sizeOf(Type.Vector));
1143 try self.ensureUnusedCapacityTypes(1, Type.Array, 0);
1768 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
11441769 return self.arrayTypeAssumeCapacity(len, child);
11451770}
11461771
......@@ -1149,7 +1774,7 @@ pub fn structType(
11491774 kind: Type.Structure.Kind,
11501775 fields: []const Type,
11511776) Allocator.Error!Type {
1152 try self.ensureUnusedCapacityTypes(1, Type.Structure, fields.len);
1777 try self.ensureUnusedTypeCapacity(1, Type.Structure, fields.len);
11531778 return switch (kind) {
11541779 inline else => |comptime_kind| self.structTypeAssumeCapacity(comptime_kind, fields),
11551780 };
......@@ -1162,7 +1787,7 @@ pub fn opaqueType(self: *Builder, name: String) Allocator.Error!Type {
11621787 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
11631788 try self.types.ensureUnusedCapacity(self.gpa, 1);
11641789 try self.next_unique_type_id.ensureUnusedCapacity(self.gpa, 1);
1165 try self.ensureUnusedCapacityTypes(1, Type.NamedStructure, 0);
1790 try self.ensureUnusedTypeCapacity(1, Type.NamedStructure, 0);
11661791 return self.opaqueTypeAssumeCapacity(name);
11671792}
11681793
......@@ -1181,8 +1806,7 @@ pub fn namedTypeSetBody(
11811806 @ptrCast(self.type_extra.items[body_extra.end..][0..body_extra.data.fields_len]);
11821807 const llvm_fields = try self.gpa.alloc(*llvm.Type, body_fields.len);
11831808 defer self.gpa.free(llvm_fields);
1184 for (llvm_fields, body_fields) |*llvm_field, body_field|
1185 llvm_field.* = self.llvm_types.items[@intFromEnum(body_field)];
1809 for (llvm_fields, body_fields) |*llvm_field, body_field| llvm_field.* = body_field.toLlvm(self);
11861810 self.llvm_types.items[@intFromEnum(named_type)].structSetBody(
11871811 llvm_fields.ptr,
11881812 @intCast(llvm_fields.len),
......@@ -1196,11 +1820,13 @@ pub fn namedTypeSetBody(
11961820}
11971821
11981822pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {
1823 try self.ensureUnusedTypeCapacity(1, null, 0);
11991824 try self.ensureUnusedCapacityGlobal(name);
12001825 return self.addGlobalAssumeCapacity(name, global);
12011826}
12021827
12031828pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Global.Index {
1829 _ = self.ptrTypeAssumeCapacity(global.addr_space);
12041830 var id = name;
12051831 if (id == .none) {
12061832 id = self.next_unnamed_global;
......@@ -1210,6 +1836,7 @@ pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Glo
12101836 const global_gop = self.globals.getOrPutAssumeCapacity(id);
12111837 if (!global_gop.found_existing) {
12121838 global_gop.value_ptr.* = global;
1839 global_gop.value_ptr.updateAttributes();
12131840 const index: Global.Index = @enumFromInt(global_gop.index);
12141841 index.updateName(self);
12151842 return index;
......@@ -1246,6 +1873,207 @@ pub fn bigIntConst(self: *Builder, ty: Type, value: std.math.big.int.Const) Allo
12461873 return self.bigIntConstAssumeCapacity(ty, value);
12471874}
12481875
1876pub fn fpConst(self: *Builder, ty: Type, comptime val: comptime_float) Allocator.Error!Constant {
1877 return switch (ty) {
1878 .half => try self.halfConst(val),
1879 .bfloat => try self.bfloatConst(val),
1880 .float => try self.floatConst(val),
1881 .double => try self.doubleConst(val),
1882 .fp128 => try self.fp128Const(val),
1883 .x86_fp80 => try self.x86_fp80Const(val),
1884 .ppc_fp128 => try self.ppc_fp128Const(.{ val, 0 }),
1885 else => unreachable,
1886 };
1887}
1888
1889pub fn halfConst(self: *Builder, val: f16) Allocator.Error!Constant {
1890 try self.ensureUnusedConstantCapacity(1, null, 0);
1891 return self.halfConstAssumeCapacity(val);
1892}
1893
1894pub fn bfloatConst(self: *Builder, val: f32) Allocator.Error!Constant {
1895 try self.ensureUnusedConstantCapacity(1, null, 0);
1896 return self.bfloatConstAssumeCapacity(val);
1897}
1898
1899pub fn floatConst(self: *Builder, val: f32) Allocator.Error!Constant {
1900 try self.ensureUnusedConstantCapacity(1, null, 0);
1901 return self.floatConstAssumeCapacity(val);
1902}
1903
1904pub fn doubleConst(self: *Builder, val: f64) Allocator.Error!Constant {
1905 try self.ensureUnusedConstantCapacity(1, Constant.Double, 0);
1906 return self.doubleConstAssumeCapacity(val);
1907}
1908
1909pub fn fp128Const(self: *Builder, val: f128) Allocator.Error!Constant {
1910 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
1911 return self.fp128ConstAssumeCapacity(val);
1912}
1913
1914pub fn x86_fp80Const(self: *Builder, val: f80) Allocator.Error!Constant {
1915 try self.ensureUnusedConstantCapacity(1, Constant.Fp80, 0);
1916 return self.x86_fp80ConstAssumeCapacity(val);
1917}
1918
1919pub fn ppc_fp128Const(self: *Builder, val: [2]f64) Allocator.Error!Constant {
1920 try self.ensureUnusedConstantCapacity(1, Constant.Fp128, 0);
1921 return self.ppc_fp128ConstAssumeCapacity(val);
1922}
1923
1924pub fn nullConst(self: *Builder, ty: Type) Allocator.Error!Constant {
1925 try self.ensureUnusedConstantCapacity(1, null, 0);
1926 return self.nullConstAssumeCapacity(ty);
1927}
1928
1929pub fn noneConst(self: *Builder, ty: Type) Allocator.Error!Constant {
1930 try self.ensureUnusedConstantCapacity(1, null, 0);
1931 return self.noneConstAssumeCapacity(ty);
1932}
1933
1934pub fn structConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
1935 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
1936 return self.structConstAssumeCapacity(ty, vals);
1937}
1938
1939pub fn arrayConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
1940 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
1941 return self.arrayConstAssumeCapacity(ty, vals);
1942}
1943
1944pub fn stringConst(self: *Builder, val: String) Allocator.Error!Constant {
1945 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
1946 try self.ensureUnusedConstantCapacity(1, null, 0);
1947 return self.stringConstAssumeCapacity(val);
1948}
1949
1950pub fn stringNullConst(self: *Builder, val: String) Allocator.Error!Constant {
1951 try self.ensureUnusedTypeCapacity(1, Type.Array, 0);
1952 try self.ensureUnusedConstantCapacity(1, null, 0);
1953 return self.stringNullConstAssumeCapacity(val);
1954}
1955
1956pub fn vectorConst(self: *Builder, ty: Type, vals: []const Constant) Allocator.Error!Constant {
1957 try self.ensureUnusedConstantCapacity(1, Constant.Aggregate, vals.len);
1958 return self.vectorConstAssumeCapacity(ty, vals);
1959}
1960
1961pub fn zeroInitConst(self: *Builder, ty: Type) Allocator.Error!Constant {
1962 try self.ensureUnusedConstantCapacity(1, null, 0);
1963 return self.zeroInitConstAssumeCapacity(ty);
1964}
1965
1966pub fn undefConst(self: *Builder, ty: Type) Allocator.Error!Constant {
1967 try self.ensureUnusedConstantCapacity(1, null, 0);
1968 return self.undefConstAssumeCapacity(ty);
1969}
1970
1971pub fn poisonConst(self: *Builder, ty: Type) Allocator.Error!Constant {
1972 try self.ensureUnusedConstantCapacity(1, null, 0);
1973 return self.poisonConstAssumeCapacity(ty);
1974}
1975
1976pub fn blockAddrConst(
1977 self: *Builder,
1978 function: Function.Index,
1979 block: Function.Block.Index,
1980) Allocator.Error!Constant {
1981 try self.ensureUnusedConstantCapacity(1, Constant.BlockAddress, 0);
1982 return self.blockAddrConstAssumeCapacity(function, block);
1983}
1984
1985pub fn dsoLocalEquivalentConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {
1986 try self.ensureUnusedConstantCapacity(1, Constant.FunctionReference, 0);
1987 return self.dsoLocalEquivalentConstAssumeCapacity(function);
1988}
1989
1990pub fn noCfiConst(self: *Builder, function: Function.Index) Allocator.Error!Constant {
1991 try self.ensureUnusedConstantCapacity(1, Constant.FunctionReference, 0);
1992 return self.noCfiConstAssumeCapacity(function);
1993}
1994
1995pub fn convConst(
1996 self: *Builder,
1997 signedness: Constant.Cast.Signedness,
1998 arg: Constant,
1999 ty: Type,
2000) Allocator.Error!Constant {
2001 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);
2002 return self.convConstAssumeCapacity(signedness, arg, ty);
2003}
2004
2005pub fn castConst(self: *Builder, tag: Constant.Tag, arg: Constant, ty: Type) Allocator.Error!Constant {
2006 try self.ensureUnusedConstantCapacity(1, Constant.Cast, 0);
2007 return self.castConstAssumeCapacity(tag, arg, ty);
2008}
2009
2010pub fn gepConst(
2011 self: *Builder,
2012 comptime kind: Constant.GetElementPtr.Kind,
2013 ty: Type,
2014 base: Constant,
2015 indices: []const Constant,
2016) Allocator.Error!Constant {
2017 try self.ensureUnusedTypeCapacity(1, Type.Vector, 0);
2018 try self.ensureUnusedConstantCapacity(1, Constant.GetElementPtr, indices.len);
2019 return self.gepConstAssumeCapacity(kind, ty, base, indices);
2020}
2021
2022pub fn icmpConst(
2023 self: *Builder,
2024 cond: IntegerCondition,
2025 lhs: Constant,
2026 rhs: Constant,
2027) Allocator.Error!Constant {
2028 try self.ensureUnusedConstantCapacity(1, Constant.Compare, 0);
2029 return self.icmpConstAssumeCapacity(cond, lhs, rhs);
2030}
2031
2032pub fn fcmpConst(
2033 self: *Builder,
2034 cond: FloatCondition,
2035 lhs: Constant,
2036 rhs: Constant,
2037) Allocator.Error!Constant {
2038 try self.ensureUnusedConstantCapacity(1, Constant.Compare, 0);
2039 return self.icmpConstAssumeCapacity(cond, lhs, rhs);
2040}
2041
2042pub fn extractElementConst(self: *Builder, arg: Constant, index: Constant) Allocator.Error!Constant {
2043 try self.ensureUnusedConstantCapacity(1, Constant.ExtractElement, 0);
2044 return self.extractElementConstAssumeCapacity(arg, index);
2045}
2046
2047pub fn insertElementConst(
2048 self: *Builder,
2049 arg: Constant,
2050 elem: Constant,
2051 index: Constant,
2052) Allocator.Error!Constant {
2053 try self.ensureUnusedConstantCapacity(1, Constant.InsertElement, 0);
2054 return self.insertElementConstAssumeCapacity(arg, elem, index);
2055}
2056
2057pub fn shuffleVectorConst(
2058 self: *Builder,
2059 lhs: Constant,
2060 rhs: Constant,
2061 mask: Constant,
2062) Allocator.Error!Constant {
2063 try self.ensureUnusedConstantCapacity(1, Constant.ShuffleVector, 0);
2064 return self.shuffleVectorConstAssumeCapacity(lhs, rhs, mask);
2065}
2066
2067pub fn binConst(
2068 self: *Builder,
2069 tag: Constant.Tag,
2070 lhs: Constant,
2071 rhs: Constant,
2072) Allocator.Error!Constant {
2073 try self.ensureUnusedConstantCapacity(1, Constant.Binary, 0);
2074 return self.binConstAssumeCapacity(tag, lhs, rhs);
2075}
2076
12492077pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
12502078 if (self.source_filename != .none) try writer.print(
12512079 \\; ModuleID = '{s}'
......@@ -1266,43 +2094,44 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
12662094 \\
12672095 , .{ id.fmt(self), ty.fmt(self) });
12682096 try writer.writeByte('\n');
1269 for (self.objects.items) |object| {
1270 const global = self.globals.entries.get(@intFromEnum(object.global));
2097 for (self.variables.items) |variable| {
2098 const global = self.globals.values()[@intFromEnum(variable.global)];
12712099 try writer.print(
1272 \\@{} ={}{}{}{}{}{}{}{} {s} {%}{,}
2100 \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,}
12732101 \\
12742102 , .{
1275 global.key.fmt(self),
1276 global.value.linkage,
1277 global.value.preemption,
1278 global.value.visibility,
1279 global.value.dll_storage_class,
1280 object.thread_local,
1281 global.value.unnamed_addr,
1282 global.value.addr_space,
1283 global.value.externally_initialized,
1284 @tagName(object.mutability),
1285 global.value.type.fmt(self),
1286 global.value.alignment,
2103 variable.global.fmt(self),
2104 global.linkage,
2105 global.preemption,
2106 global.visibility,
2107 global.dll_storage_class,
2108 variable.thread_local,
2109 global.unnamed_addr,
2110 global.addr_space,
2111 global.externally_initialized,
2112 @tagName(variable.mutability),
2113 global.type.fmt(self),
2114 variable.init.fmt(self),
2115 global.alignment,
12872116 });
12882117 }
12892118 try writer.writeByte('\n');
12902119 for (self.functions.items) |function| {
1291 const global = self.globals.entries.get(@intFromEnum(function.global));
1292 const item = self.type_items.items[@intFromEnum(global.value.type)];
2120 const global = self.globals.values()[@intFromEnum(function.global)];
2121 const item = self.type_items.items[@intFromEnum(global.type)];
12932122 const extra = self.typeExtraDataTrail(Type.Function, item.data);
12942123 const params: []const Type =
12952124 @ptrCast(self.type_extra.items[extra.end..][0..extra.data.params_len]);
12962125 try writer.print(
1297 \\{s} {}{}{}{}{} @{}(
2126 \\{s}{}{}{}{} {} {}(
12982127 , .{
12992128 if (function.body) |_| "define" else "declare",
1300 global.value.linkage,
1301 global.value.preemption,
1302 global.value.visibility,
1303 global.value.dll_storage_class,
2129 global.linkage,
2130 global.preemption,
2131 global.visibility,
2132 global.dll_storage_class,
13042133 extra.data.ret.fmt(self),
1305 global.key.fmt(self),
2134 function.global.fmt(self),
13062135 });
13072136 for (params, 0..) |param, index| {
13082137 if (index > 0) try writer.writeAll(", ");
......@@ -1316,65 +2145,36 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
13162145 },
13172146 else => unreachable,
13182147 }
1319 try writer.print(") {}{}", .{
1320 global.value.unnamed_addr,
1321 global.value.alignment,
1322 });
2148 try writer.print(") {}{}", .{ global.unnamed_addr, global.alignment });
13232149 if (function.body) |_| try writer.print(
13242150 \\{{
13252151 \\ ret {%}
13262152 \\}}
13272153 \\
1328 , .{
1329 extra.data.ret.fmt(self),
1330 });
2154 , .{extra.data.ret.fmt(self)});
13312155 try writer.writeByte('\n');
13322156 }
13332157}
13342158
2159fn isValidIdentifier(id: []const u8) bool {
2160 for (id, 0..) |character, index| switch (character) {
2161 '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},
2162 '0'...'9' => if (index == 0) return false,
2163 else => return false,
2164 };
2165 return true;
2166}
2167
13352168fn ensureUnusedCapacityGlobal(self: *Builder, name: String) Allocator.Error!void {
13362169 if (self.useLibLlvm()) try self.llvm_globals.ensureUnusedCapacity(self.gpa, 1);
13372170 try self.string_map.ensureUnusedCapacity(self.gpa, 1);
1338 try self.string_bytes.ensureUnusedCapacity(self.gpa, name.toSlice(self).?.len +
2171 if (name.toSlice(self)) |id| try self.string_bytes.ensureUnusedCapacity(self.gpa, id.len +
13392172 comptime std.fmt.count("{d}" ++ .{0}, .{std.math.maxInt(u32)}));
13402173 try self.string_indices.ensureUnusedCapacity(self.gpa, 1);
13412174 try self.globals.ensureUnusedCapacity(self.gpa, 1);
13422175 try self.next_unique_global_id.ensureUnusedCapacity(self.gpa, 1);
13432176}
13442177
1345fn addTypeExtraAssumeCapacity(self: *Builder, extra: anytype) Type.ExtraIndex {
1346 const result: Type.ExtraIndex = @intCast(self.type_extra.items.len);
1347 inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
1348 const value = @field(extra, field.name);
1349 self.type_extra.appendAssumeCapacity(switch (field.type) {
1350 u32 => value,
1351 String, Type => @intFromEnum(value),
1352 else => @compileError("bad field type: " ++ @typeName(field.type)),
1353 });
1354 }
1355 return result;
1356}
1357
1358fn typeExtraDataTrail(
1359 self: *const Builder,
1360 comptime T: type,
1361 index: Type.ExtraIndex,
1362) struct { data: T, end: Type.ExtraIndex } {
1363 var result: T = undefined;
1364 const fields = @typeInfo(T).Struct.fields;
1365 inline for (fields, self.type_extra.items[index..][0..fields.len]) |field, data|
1366 @field(result, field.name) = switch (field.type) {
1367 u32 => data,
1368 String, Type => @enumFromInt(data),
1369 else => @compileError("bad field type: " ++ @typeName(field.type)),
1370 };
1371 return .{ .data = result, .end = index + @as(Type.ExtraIndex, @intCast(fields.len)) };
1372}
1373
1374fn typeExtraData(self: *const Builder, comptime T: type, index: Type.ExtraIndex) T {
1375 return self.typeExtraDataTrail(T, index).data;
1376}
1377
13782178fn fnTypeAssumeCapacity(
13792179 self: *Builder,
13802180 ret: Type,
......@@ -1394,17 +2194,19 @@ fn fnTypeAssumeCapacity(
13942194 hasher.update(std.mem.sliceAsBytes(key.params));
13952195 return @truncate(hasher.final());
13962196 }
1397 pub fn eql(ctx: @This(), lhs: Key, _: void, rhs_index: usize) bool {
2197 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
13982198 const rhs_data = ctx.builder.type_items.items[rhs_index];
13992199 const rhs_extra = ctx.builder.typeExtraDataTrail(Type.Function, rhs_data.data);
14002200 const rhs_params: []const Type =
14012201 @ptrCast(ctx.builder.type_extra.items[rhs_extra.end..][0..rhs_extra.data.params_len]);
1402 return rhs_data.tag == tag and lhs.ret == rhs_extra.data.ret and
1403 std.mem.eql(Type, lhs.params, rhs_params);
2202 return rhs_data.tag == tag and lhs_key.ret == rhs_extra.data.ret and
2203 std.mem.eql(Type, lhs_key.params, rhs_params);
14042204 }
14052205 };
1406 const data = Key{ .ret = ret, .params = params };
1407 const gop = self.type_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
2206 const gop = self.type_map.getOrPutAssumeCapacityAdapted(
2207 Key{ .ret = ret, .params = params },
2208 Adapter{ .builder = self },
2209 );
14082210 if (!gop.found_existing) {
14092211 gop.key_ptr.* = {};
14102212 gop.value_ptr.* = {};
......@@ -1436,17 +2238,16 @@ fn fnTypeAssumeCapacity(
14362238
14372239fn intTypeAssumeCapacity(self: *Builder, bits: u24) Type {
14382240 assert(bits > 0);
1439 const result = self.typeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits });
2241 const result = self.getOrPutTypeNoExtraAssumeCapacity(.{ .tag = .integer, .data = bits });
14402242 if (self.useLibLlvm() and result.new)
14412243 self.llvm_types.appendAssumeCapacity(self.llvm_context.intType(bits));
14422244 return result.type;
14432245}
14442246
14452247fn ptrTypeAssumeCapacity(self: *Builder, addr_space: AddrSpace) Type {
1446 const result = self.typeNoExtraAssumeCapacity(.{
1447 .tag = .pointer,
1448 .data = @intFromEnum(addr_space),
1449 });
2248 const result = self.getOrPutTypeNoExtraAssumeCapacity(
2249 .{ .tag = .pointer, .data = @intFromEnum(addr_space) },
2250 );
14502251 if (self.useLibLlvm() and result.new)
14512252 self.llvm_types.appendAssumeCapacity(self.llvm_context.pointerType(@intFromEnum(addr_space)));
14522253 return result.type;
......@@ -1470,10 +2271,10 @@ fn vectorTypeAssumeCapacity(
14702271 std.mem.asBytes(&key),
14712272 ));
14722273 }
1473 pub fn eql(ctx: @This(), lhs: Type.Vector, _: void, rhs_index: usize) bool {
2274 pub fn eql(ctx: @This(), lhs_key: Type.Vector, _: void, rhs_index: usize) bool {
14742275 const rhs_data = ctx.builder.type_items.items[rhs_index];
14752276 return rhs_data.tag == tag and
1476 std.meta.eql(lhs, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
2277 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
14772278 }
14782279 };
14792280 const data = Type.Vector{ .len = len, .child = child };
......@@ -1503,10 +2304,10 @@ fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type {
15032304 std.mem.asBytes(&key),
15042305 ));
15052306 }
1506 pub fn eql(ctx: @This(), lhs: Type.Vector, _: void, rhs_index: usize) bool {
2307 pub fn eql(ctx: @This(), lhs_key: Type.Vector, _: void, rhs_index: usize) bool {
15072308 const rhs_data = ctx.builder.type_items.items[rhs_index];
15082309 return rhs_data.tag == .small_array and
1509 std.meta.eql(lhs, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
2310 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Vector, rhs_data.data));
15102311 }
15112312 };
15122313 const data = Type.Vector{ .len = small_len, .child = child };
......@@ -1532,10 +2333,10 @@ fn arrayTypeAssumeCapacity(self: *Builder, len: u64, child: Type) Type {
15322333 std.mem.asBytes(&key),
15332334 ));
15342335 }
1535 pub fn eql(ctx: @This(), lhs: Type.Array, _: void, rhs_index: usize) bool {
2336 pub fn eql(ctx: @This(), lhs_key: Type.Array, _: void, rhs_index: usize) bool {
15362337 const rhs_data = ctx.builder.type_items.items[rhs_index];
15372338 return rhs_data.tag == .array and
1538 std.meta.eql(lhs, ctx.builder.typeExtraData(Type.Array, rhs_data.data));
2339 std.meta.eql(lhs_key, ctx.builder.typeExtraData(Type.Array, rhs_data.data));
15392340 }
15402341 };
15412342 const data = Type.Array{
......@@ -1576,12 +2377,12 @@ fn structTypeAssumeCapacity(
15762377 std.mem.sliceAsBytes(key),
15772378 ));
15782379 }
1579 pub fn eql(ctx: @This(), lhs: []const Type, _: void, rhs_index: usize) bool {
2380 pub fn eql(ctx: @This(), lhs_key: []const Type, _: void, rhs_index: usize) bool {
15802381 const rhs_data = ctx.builder.type_items.items[rhs_index];
15812382 const rhs_extra = ctx.builder.typeExtraDataTrail(Type.Structure, rhs_data.data);
15822383 const rhs_fields: []const Type =
15832384 @ptrCast(ctx.builder.type_extra.items[rhs_extra.end..][0..rhs_extra.data.fields_len]);
1584 return rhs_data.tag == tag and std.mem.eql(Type, lhs, rhs_fields);
2385 return rhs_data.tag == tag and std.mem.eql(Type, lhs_key, rhs_fields);
15852386 }
15862387 };
15872388 const gop = self.type_map.getOrPutAssumeCapacityAdapted(fields, Adapter{ .builder = self });
......@@ -1596,15 +2397,14 @@ fn structTypeAssumeCapacity(
15962397 });
15972398 self.type_extra.appendSliceAssumeCapacity(@ptrCast(fields));
15982399 if (self.useLibLlvm()) {
1599 const ExpectedContents = [32]*llvm.Type;
2400 const ExpectedContents = [expected_fields_len]*llvm.Type;
16002401 var stack align(@alignOf(ExpectedContents)) =
16012402 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
16022403 const allocator = stack.get();
16032404
16042405 const llvm_fields = try allocator.alloc(*llvm.Type, fields.len);
16052406 defer allocator.free(llvm_fields);
1606 for (llvm_fields, fields) |*llvm_field, field|
1607 llvm_field.* = self.llvm_types.items[@intFromEnum(field)];
2407 for (llvm_fields, fields) |*llvm_field, field| llvm_field.* = field.toLlvm(self);
16082408
16092409 self.llvm_types.appendAssumeCapacity(self.llvm_context.structType(
16102410 llvm_fields.ptr,
......@@ -1628,10 +2428,10 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
16282428 std.mem.asBytes(&key),
16292429 ));
16302430 }
1631 pub fn eql(ctx: @This(), lhs: String, _: void, rhs_index: usize) bool {
2431 pub fn eql(ctx: @This(), lhs_key: String, _: void, rhs_index: usize) bool {
16322432 const rhs_data = ctx.builder.type_items.items[rhs_index];
16332433 return rhs_data.tag == .named_structure and
1634 lhs == ctx.builder.typeExtraData(Type.NamedStructure, rhs_data.data).id;
2434 lhs_key == ctx.builder.typeExtraData(Type.NamedStructure, rhs_data.data).id;
16352435 }
16362436 };
16372437 var id = name;
......@@ -1669,7 +2469,7 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
16692469 }
16702470}
16712471
1672fn ensureUnusedCapacityTypes(
2472fn ensureUnusedTypeCapacity(
16732473 self: *Builder,
16742474 count: usize,
16752475 comptime Extra: ?type,
......@@ -1680,11 +2480,11 @@ fn ensureUnusedCapacityTypes(
16802480 if (Extra) |E| try self.type_extra.ensureUnusedCapacity(
16812481 self.gpa,
16822482 count * (@typeInfo(E).Struct.fields.len + trail_len),
1683 );
2483 ) else assert(trail_len == 0);
16842484 if (self.useLibLlvm()) try self.llvm_types.ensureUnusedCapacity(self.gpa, count);
16852485}
16862486
1687fn typeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool, type: Type } {
2487fn getOrPutTypeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool, type: Type } {
16882488 const Adapter = struct {
16892489 builder: *const Builder,
16902490 pub fn hash(_: @This(), key: Type.Item) u32 {
......@@ -1693,8 +2493,8 @@ fn typeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool
16932493 std.mem.asBytes(&key),
16942494 ));
16952495 }
1696 pub fn eql(ctx: @This(), lhs: Type.Item, _: void, rhs_index: usize) bool {
1697 const lhs_bits: u32 = @bitCast(lhs);
2496 pub fn eql(ctx: @This(), lhs_key: Type.Item, _: void, rhs_index: usize) bool {
2497 const lhs_bits: u32 = @bitCast(lhs_key);
16982498 const rhs_bits: u32 = @bitCast(ctx.builder.type_items.items[rhs_index]);
16992499 return lhs_bits == rhs_bits;
17002500 }
......@@ -1708,13 +2508,37 @@ fn typeNoExtraAssumeCapacity(self: *Builder, item: Type.Item) struct { new: bool
17082508 return .{ .new = !gop.found_existing, .type = @enumFromInt(gop.index) };
17092509}
17102510
1711fn isValidIdentifier(id: []const u8) bool {
1712 for (id, 0..) |character, index| switch (character) {
1713 '$', '-', '.', 'A'...'Z', '_', 'a'...'z' => {},
1714 '0'...'9' => if (index == 0) return false,
1715 else => return false,
1716 };
1717 return true;
2511fn addTypeExtraAssumeCapacity(self: *Builder, extra: anytype) Type.Item.ExtraIndex {
2512 const result: Type.Item.ExtraIndex = @intCast(self.type_extra.items.len);
2513 inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
2514 const value = @field(extra, field.name);
2515 self.type_extra.appendAssumeCapacity(switch (field.type) {
2516 u32 => value,
2517 String, Type => @intFromEnum(value),
2518 else => @compileError("bad field type: " ++ @typeName(field.type)),
2519 });
2520 }
2521 return result;
2522}
2523
2524fn typeExtraDataTrail(
2525 self: *const Builder,
2526 comptime T: type,
2527 index: Type.Item.ExtraIndex,
2528) struct { data: T, end: Type.Item.ExtraIndex } {
2529 var result: T = undefined;
2530 const fields = @typeInfo(T).Struct.fields;
2531 inline for (fields, self.type_extra.items[index..][0..fields.len]) |field, data|
2532 @field(result, field.name) = switch (field.type) {
2533 u32 => data,
2534 String, Type => @enumFromInt(data),
2535 else => @compileError("bad field type: " ++ @typeName(field.type)),
2536 };
2537 return .{ .data = result, .end = index + @as(Type.Item.ExtraIndex, @intCast(fields.len)) };
2538}
2539
2540fn typeExtraData(self: *const Builder, comptime T: type, index: Type.Item.ExtraIndex) T {
2541 return self.typeExtraDataTrail(T, index).data;
17182542}
17192543
17202544fn bigIntConstAssumeCapacity(
......@@ -1748,8 +2572,8 @@ fn bigIntConstAssumeCapacity(
17482572 const ExtraPtr = *align(@alignOf(std.math.big.Limb)) Constant.Integer;
17492573 const Key = struct { tag: Constant.Tag, type: Type, limbs: []const std.math.big.Limb };
17502574 const tag: Constant.Tag = switch (canonical_value.positive) {
1751 true => .integer_positive,
1752 false => .integer_negative,
2575 true => .positive_integer,
2576 false => .negative_integer,
17532577 };
17542578 const Adapter = struct {
17552579 builder: *const Builder,
......@@ -1759,20 +2583,22 @@ fn bigIntConstAssumeCapacity(
17592583 hasher.update(std.mem.sliceAsBytes(key.limbs));
17602584 return @truncate(hasher.final());
17612585 }
1762 pub fn eql(ctx: @This(), lhs: Key, _: void, rhs_index: usize) bool {
1763 if (lhs.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
2586 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
2587 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
17642588 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
1765 const rhs_extra: ExtraPtr = @ptrCast(
1766 ctx.builder.constant_limbs.items[rhs_data..][0..Constant.Integer.limbs],
1767 );
2589 const rhs_extra: ExtraPtr =
2590 @ptrCast(ctx.builder.constant_limbs.items[rhs_data..][0..Constant.Integer.limbs]);
17682591 const rhs_limbs = ctx.builder.constant_limbs
17692592 .items[rhs_data + Constant.Integer.limbs ..][0..rhs_extra.limbs_len];
1770 return lhs.type == rhs_extra.type and std.mem.eql(std.math.big.Limb, lhs.limbs, rhs_limbs);
2593 return lhs_key.type == rhs_extra.type and
2594 std.mem.eql(std.math.big.Limb, lhs_key.limbs, rhs_limbs);
17712595 }
17722596 };
17732597
1774 const data = Key{ .tag = tag, .type = ty, .limbs = canonical_value.limbs };
1775 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
2598 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(
2599 Key{ .tag = tag, .type = ty, .limbs = canonical_value.limbs },
2600 Adapter{ .builder = self },
2601 );
17762602 if (!gop.found_existing) {
17772603 gop.key_ptr.* = {};
17782604 gop.value_ptr.* = {};
......@@ -1780,9 +2606,8 @@ fn bigIntConstAssumeCapacity(
17802606 .tag = tag,
17812607 .data = @intCast(self.constant_limbs.items.len),
17822608 });
1783 const extra: ExtraPtr = @ptrCast(
1784 self.constant_limbs.addManyAsArrayAssumeCapacity(Constant.Integer.limbs),
1785 );
2609 const extra: ExtraPtr =
2610 @ptrCast(self.constant_limbs.addManyAsArrayAssumeCapacity(Constant.Integer.limbs));
17862611 extra.* = .{ .type = ty, .limbs_len = @intCast(canonical_value.limbs.len) };
17872612 self.constant_limbs.appendSliceAssumeCapacity(canonical_value.limbs);
17882613 if (self.useLibLlvm()) {
......@@ -1827,6 +2652,870 @@ fn bigIntConstAssumeCapacity(
18272652 return @enumFromInt(gop.index);
18282653}
18292654
2655fn halfConstAssumeCapacity(self: *Builder, val: f16) Constant {
2656 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2657 .{ .tag = .half, .data = @as(u16, @bitCast(val)) },
2658 );
2659 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(
2660 if (std.math.isSignalNan(val))
2661 Type.i16.toLlvm(self).constInt(@as(u16, @bitCast(val)), .False)
2662 .constBitCast(Type.half.toLlvm(self))
2663 else
2664 Type.half.toLlvm(self).constReal(val),
2665 );
2666 return result.constant;
2667}
2668
2669fn bfloatConstAssumeCapacity(self: *Builder, val: f32) Constant {
2670 assert(@as(u16, @truncate(@as(u32, @bitCast(val)))) == 0);
2671 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2672 .{ .tag = .bfloat, .data = @bitCast(val) },
2673 );
2674 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(
2675 if (std.math.isSignalNan(val))
2676 Type.i16.toLlvm(self).constInt(@as(u32, @bitCast(val)) >> 16, .False)
2677 .constBitCast(Type.bfloat.toLlvm(self))
2678 else
2679 Type.bfloat.toLlvm(self).constReal(val),
2680 );
2681
2682 if (self.useLibLlvm() and result.new)
2683 self.llvm_constants.appendAssumeCapacity(Type.bfloat.toLlvm(self).constReal(val));
2684 return result.constant;
2685}
2686
2687fn floatConstAssumeCapacity(self: *Builder, val: f32) Constant {
2688 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2689 .{ .tag = .float, .data = @bitCast(val) },
2690 );
2691 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(
2692 if (std.math.isSignalNan(val))
2693 Type.i32.toLlvm(self).constInt(@as(u32, @bitCast(val)), .False)
2694 .constBitCast(Type.float.toLlvm(self))
2695 else
2696 Type.float.toLlvm(self).constReal(val),
2697 );
2698 return result.constant;
2699}
2700
2701fn doubleConstAssumeCapacity(self: *Builder, val: f64) Constant {
2702 const Adapter = struct {
2703 builder: *const Builder,
2704 pub fn hash(_: @This(), key: f64) u32 {
2705 return @truncate(std.hash.Wyhash.hash(
2706 comptime std.hash.uint32(@intFromEnum(Constant.Tag.double)),
2707 std.mem.asBytes(&key),
2708 ));
2709 }
2710 pub fn eql(ctx: @This(), lhs_key: f64, _: void, rhs_index: usize) bool {
2711 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .double) return false;
2712 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
2713 const rhs_extra = ctx.builder.constantExtraData(Constant.Double, rhs_data);
2714 return @as(u64, @bitCast(lhs_key)) == @as(u64, rhs_extra.hi) << 32 | rhs_extra.lo;
2715 }
2716 };
2717 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
2718 if (!gop.found_existing) {
2719 gop.key_ptr.* = {};
2720 gop.value_ptr.* = {};
2721 self.constant_items.appendAssumeCapacity(.{
2722 .tag = .double,
2723 .data = self.addConstantExtraAssumeCapacity(Constant.Double{
2724 .lo = @intCast(@as(u64, @bitCast(val)) >> 32),
2725 .hi = @truncate(@as(u64, @bitCast(val))),
2726 }),
2727 });
2728 if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity(
2729 if (std.math.isSignalNan(val))
2730 Type.i64.toLlvm(self).constInt(@as(u64, @bitCast(val)), .False)
2731 .constBitCast(Type.double.toLlvm(self))
2732 else
2733 Type.double.toLlvm(self).constReal(val),
2734 );
2735 }
2736 return @enumFromInt(gop.index);
2737}
2738
2739fn fp128ConstAssumeCapacity(self: *Builder, val: f128) Constant {
2740 const Adapter = struct {
2741 builder: *const Builder,
2742 pub fn hash(_: @This(), key: f128) u32 {
2743 return @truncate(std.hash.Wyhash.hash(
2744 comptime std.hash.uint32(@intFromEnum(Constant.Tag.fp128)),
2745 std.mem.asBytes(&key),
2746 ));
2747 }
2748 pub fn eql(ctx: @This(), lhs_key: f128, _: void, rhs_index: usize) bool {
2749 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .fp128) return false;
2750 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
2751 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp128, rhs_data);
2752 return @as(u128, @bitCast(lhs_key)) == @as(u128, rhs_extra.hi_hi) << 96 |
2753 @as(u128, rhs_extra.hi_lo) << 64 | @as(u128, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo;
2754 }
2755 };
2756 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
2757 if (!gop.found_existing) {
2758 gop.key_ptr.* = {};
2759 gop.value_ptr.* = {};
2760 self.constant_items.appendAssumeCapacity(.{
2761 .tag = .fp128,
2762 .data = self.addConstantExtraAssumeCapacity(Constant.Fp128{
2763 .lo_lo = @truncate(@as(u128, @bitCast(val))),
2764 .lo_hi = @truncate(@as(u128, @bitCast(val)) >> 32),
2765 .hi_lo = @truncate(@as(u128, @bitCast(val)) >> 64),
2766 .hi_hi = @intCast(@as(u128, @bitCast(val)) >> 96),
2767 }),
2768 });
2769 if (self.useLibLlvm()) {
2770 const llvm_limbs = [_]u64{
2771 @truncate(@as(u128, @bitCast(val))),
2772 @intCast(@as(u128, @bitCast(val)) >> 64),
2773 };
2774 self.llvm_constants.appendAssumeCapacity(
2775 Type.i128.toLlvm(self)
2776 .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), &llvm_limbs)
2777 .constBitCast(Type.fp128.toLlvm(self)),
2778 );
2779 }
2780 }
2781 return @enumFromInt(gop.index);
2782}
2783
2784fn x86_fp80ConstAssumeCapacity(self: *Builder, val: f80) Constant {
2785 const Adapter = struct {
2786 builder: *const Builder,
2787 pub fn hash(_: @This(), key: f80) u32 {
2788 return @truncate(std.hash.Wyhash.hash(
2789 comptime std.hash.uint32(@intFromEnum(Constant.Tag.x86_fp80)),
2790 std.mem.asBytes(&key)[0..10],
2791 ));
2792 }
2793 pub fn eql(ctx: @This(), lhs_key: f80, _: void, rhs_index: usize) bool {
2794 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .x86_fp80) return false;
2795 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
2796 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp80, rhs_data);
2797 return @as(u80, @bitCast(lhs_key)) == @as(u80, rhs_extra.hi) << 64 |
2798 @as(u80, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo;
2799 }
2800 };
2801 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
2802 if (!gop.found_existing) {
2803 gop.key_ptr.* = {};
2804 gop.value_ptr.* = {};
2805 self.constant_items.appendAssumeCapacity(.{
2806 .tag = .x86_fp80,
2807 .data = self.addConstantExtraAssumeCapacity(Constant.Fp80{
2808 .lo_lo = @truncate(@as(u80, @bitCast(val))),
2809 .lo_hi = @truncate(@as(u80, @bitCast(val)) >> 32),
2810 .hi = @intCast(@as(u80, @bitCast(val)) >> 64),
2811 }),
2812 });
2813 if (self.useLibLlvm()) {
2814 const llvm_limbs = [_]u64{
2815 @truncate(@as(u80, @bitCast(val))),
2816 @intCast(@as(u80, @bitCast(val)) >> 64),
2817 };
2818 self.llvm_constants.appendAssumeCapacity(
2819 Type.i80.toLlvm(self)
2820 .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), &llvm_limbs)
2821 .constBitCast(Type.x86_fp80.toLlvm(self)),
2822 );
2823 }
2824 }
2825 return @enumFromInt(gop.index);
2826}
2827
2828fn ppc_fp128ConstAssumeCapacity(self: *Builder, val: [2]f64) Constant {
2829 const Adapter = struct {
2830 builder: *const Builder,
2831 pub fn hash(_: @This(), key: [2]f64) u32 {
2832 return @truncate(std.hash.Wyhash.hash(
2833 comptime std.hash.uint32(@intFromEnum(Constant.Tag.ppc_fp128)),
2834 std.mem.asBytes(&key),
2835 ));
2836 }
2837 pub fn eql(ctx: @This(), lhs_key: [2]f64, _: void, rhs_index: usize) bool {
2838 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .ppc_fp128) return false;
2839 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
2840 const rhs_extra = ctx.builder.constantExtraData(Constant.Fp128, rhs_data);
2841 return @as(u64, @bitCast(lhs_key[0])) == @as(u64, rhs_extra.lo_hi) << 32 | rhs_extra.lo_lo and
2842 @as(u64, @bitCast(lhs_key[1])) == @as(u64, rhs_extra.hi_hi) << 32 | rhs_extra.hi_lo;
2843 }
2844 };
2845 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(val, Adapter{ .builder = self });
2846 if (!gop.found_existing) {
2847 gop.key_ptr.* = {};
2848 gop.value_ptr.* = {};
2849 self.constant_items.appendAssumeCapacity(.{
2850 .tag = .ppc_fp128,
2851 .data = self.addConstantExtraAssumeCapacity(Constant.Fp128{
2852 .lo_lo = @truncate(@as(u64, @bitCast(val[0]))),
2853 .lo_hi = @intCast(@as(u64, @bitCast(val[0])) >> 32),
2854 .hi_lo = @truncate(@as(u64, @bitCast(val[1]))),
2855 .hi_hi = @intCast(@as(u64, @bitCast(val[1])) >> 32),
2856 }),
2857 });
2858 if (self.useLibLlvm()) {
2859 const llvm_limbs: *const [2]u64 = @ptrCast(&val);
2860 self.llvm_constants.appendAssumeCapacity(
2861 Type.i128.toLlvm(self)
2862 .constIntOfArbitraryPrecision(@intCast(llvm_limbs.len), llvm_limbs)
2863 .constBitCast(Type.ppc_fp128.toLlvm(self)),
2864 );
2865 }
2866 }
2867 return @enumFromInt(gop.index);
2868}
2869
2870fn nullConstAssumeCapacity(self: *Builder, ty: Type) Constant {
2871 assert(self.type_items.items[@intFromEnum(ty)].tag == .pointer);
2872 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2873 .{ .tag = .null, .data = @intFromEnum(ty) },
2874 );
2875 if (self.useLibLlvm() and result.new)
2876 self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).constNull());
2877 return result.constant;
2878}
2879
2880fn noneConstAssumeCapacity(self: *Builder, ty: Type) Constant {
2881 assert(ty == .token);
2882 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2883 .{ .tag = .none, .data = @intFromEnum(ty) },
2884 );
2885 if (self.useLibLlvm() and result.new)
2886 self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).constNull());
2887 return result.constant;
2888}
2889
2890fn structConstAssumeCapacity(
2891 self: *Builder,
2892 ty: Type,
2893 vals: []const Constant,
2894) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
2895 const type_item = self.type_items.items[@intFromEnum(ty)];
2896 const extra = self.typeExtraDataTrail(Type.Structure, switch (type_item.tag) {
2897 .structure, .packed_structure => type_item.data,
2898 .named_structure => data: {
2899 const body_ty = self.typeExtraData(Type.NamedStructure, type_item.data).body;
2900 const body_item = self.type_items.items[@intFromEnum(body_ty)];
2901 switch (body_item.tag) {
2902 .structure, .packed_structure => break :data body_item.data,
2903 else => unreachable,
2904 }
2905 },
2906 else => unreachable,
2907 });
2908 const fields: []const Type =
2909 @ptrCast(self.type_extra.items[extra.end..][0..extra.data.fields_len]);
2910 for (fields, vals) |field, val| assert(field == val.typeOf(self));
2911
2912 for (vals) |val| {
2913 if (!val.isZeroInit(self)) break;
2914 } else return self.zeroInitConstAssumeCapacity(ty);
2915
2916 const tag: Constant.Tag = switch (ty.unnamedTag(self)) {
2917 .structure => .structure,
2918 .packed_structure => .packed_structure,
2919 else => unreachable,
2920 };
2921 const result = self.getOrPutConstantAggregateAssumeCapacity(tag, ty, vals);
2922 if (self.useLibLlvm() and result.new) {
2923 const ExpectedContents = [expected_fields_len]*llvm.Value;
2924 var stack align(@alignOf(ExpectedContents)) =
2925 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
2926 const allocator = stack.get();
2927
2928 const llvm_vals = try allocator.alloc(*llvm.Value, vals.len);
2929 defer allocator.free(llvm_vals);
2930 for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self);
2931
2932 self.llvm_constants.appendAssumeCapacity(
2933 ty.toLlvm(self).constNamedStruct(llvm_vals.ptr, @intCast(llvm_vals.len)),
2934 );
2935 }
2936 return result.constant;
2937}
2938
2939fn arrayConstAssumeCapacity(
2940 self: *Builder,
2941 ty: Type,
2942 vals: []const Constant,
2943) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
2944 const type_item = self.type_items.items[@intFromEnum(ty)];
2945 const type_extra: struct { len: u64, child: Type } = switch (type_item.tag) {
2946 .small_array => extra: {
2947 const extra = self.typeExtraData(Type.Vector, type_item.data);
2948 break :extra .{ .len = extra.len, .child = extra.child };
2949 },
2950 .array => extra: {
2951 const extra = self.typeExtraData(Type.Array, type_item.data);
2952 break :extra .{ .len = extra.len(), .child = extra.child };
2953 },
2954 else => unreachable,
2955 };
2956 assert(type_extra.len == vals.len);
2957 for (vals) |val| assert(type_extra.child == val.typeOf(self));
2958
2959 for (vals) |val| {
2960 if (!val.isZeroInit(self)) break;
2961 } else return self.zeroInitConstAssumeCapacity(ty);
2962
2963 const result = self.getOrPutConstantAggregateAssumeCapacity(.array, ty, vals);
2964 if (self.useLibLlvm() and result.new) {
2965 const ExpectedContents = [expected_fields_len]*llvm.Value;
2966 var stack align(@alignOf(ExpectedContents)) =
2967 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
2968 const allocator = stack.get();
2969
2970 const llvm_vals = try allocator.alloc(*llvm.Value, vals.len);
2971 defer allocator.free(llvm_vals);
2972 for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self);
2973
2974 self.llvm_constants.appendAssumeCapacity(
2975 type_extra.child.toLlvm(self).constArray(llvm_vals.ptr, @intCast(llvm_vals.len)),
2976 );
2977 }
2978 return result.constant;
2979}
2980
2981fn stringConstAssumeCapacity(self: *Builder, val: String) Constant {
2982 const slice = val.toSlice(self).?;
2983 const ty = self.arrayTypeAssumeCapacity(slice.len, .i8);
2984 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
2985 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2986 .{ .tag = .string, .data = @intFromEnum(val) },
2987 );
2988 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(
2989 self.llvm_context.constString(slice.ptr, @intCast(slice.len), .True),
2990 );
2991 return result.constant;
2992}
2993
2994fn stringNullConstAssumeCapacity(self: *Builder, val: String) Constant {
2995 const slice = val.toSlice(self).?;
2996 const ty = self.arrayTypeAssumeCapacity(slice.len + 1, .i8);
2997 if (std.mem.allEqual(u8, slice, 0)) return self.zeroInitConstAssumeCapacity(ty);
2998 const result = self.getOrPutConstantNoExtraAssumeCapacity(
2999 .{ .tag = .string_null, .data = @intFromEnum(val) },
3000 );
3001 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(
3002 self.llvm_context.constString(slice.ptr, @intCast(slice.len + 1), .True),
3003 );
3004 return result.constant;
3005}
3006
3007fn vectorConstAssumeCapacity(
3008 self: *Builder,
3009 ty: Type,
3010 vals: []const Constant,
3011) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
3012 if (std.debug.runtime_safety) {
3013 const type_item = self.type_items.items[@intFromEnum(ty)];
3014 assert(type_item.tag == .vector);
3015 const extra = self.typeExtraData(Type.Vector, type_item.data);
3016 assert(extra.len == vals.len);
3017 for (vals) |val| assert(extra.child == val.typeOf(self));
3018 }
3019
3020 for (vals) |val| {
3021 if (!val.isZeroInit(self)) break;
3022 } else return self.zeroInitConstAssumeCapacity(ty);
3023
3024 const result = self.getOrPutConstantAggregateAssumeCapacity(.vector, ty, vals);
3025 if (self.useLibLlvm() and result.new) {
3026 const ExpectedContents = [expected_fields_len]*llvm.Value;
3027 var stack align(@alignOf(ExpectedContents)) =
3028 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
3029 const allocator = stack.get();
3030
3031 const llvm_vals = try allocator.alloc(*llvm.Value, vals.len);
3032 defer allocator.free(llvm_vals);
3033 for (llvm_vals, vals) |*llvm_val, val| llvm_val.* = val.toLlvm(self);
3034
3035 self.llvm_constants.appendAssumeCapacity(
3036 llvm.constVector(llvm_vals.ptr, @intCast(llvm_vals.len)),
3037 );
3038 }
3039 return result.constant;
3040}
3041
3042fn zeroInitConstAssumeCapacity(self: *Builder, ty: Type) Constant {
3043 switch (self.type_items.items[@intFromEnum(ty)].tag) {
3044 .simple,
3045 .function,
3046 .vararg_function,
3047 .integer,
3048 .pointer,
3049 => unreachable,
3050 .target,
3051 .vector,
3052 .scalable_vector,
3053 .small_array,
3054 .array,
3055 .structure,
3056 .packed_structure,
3057 .named_structure,
3058 => {},
3059 }
3060 const result = self.getOrPutConstantNoExtraAssumeCapacity(
3061 .{ .tag = .zeroinitializer, .data = @intFromEnum(ty) },
3062 );
3063 if (self.useLibLlvm() and result.new)
3064 self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).constNull());
3065 return result.constant;
3066}
3067
3068fn undefConstAssumeCapacity(self: *Builder, ty: Type) Constant {
3069 switch (self.type_items.items[@intFromEnum(ty)].tag) {
3070 .simple => switch (ty) {
3071 .void, .label => unreachable,
3072 else => {},
3073 },
3074 .function, .vararg_function => unreachable,
3075 else => {},
3076 }
3077 const result = self.getOrPutConstantNoExtraAssumeCapacity(
3078 .{ .tag = .undef, .data = @intFromEnum(ty) },
3079 );
3080 if (self.useLibLlvm() and result.new)
3081 self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).getUndef());
3082 return result.constant;
3083}
3084
3085fn poisonConstAssumeCapacity(self: *Builder, ty: Type) Constant {
3086 switch (self.type_items.items[@intFromEnum(ty)].tag) {
3087 .simple => switch (ty) {
3088 .void, .label => unreachable,
3089 else => {},
3090 },
3091 .function, .vararg_function => unreachable,
3092 else => {},
3093 }
3094 const result = self.getOrPutConstantNoExtraAssumeCapacity(
3095 .{ .tag = .poison, .data = @intFromEnum(ty) },
3096 );
3097 if (self.useLibLlvm() and result.new)
3098 self.llvm_constants.appendAssumeCapacity(ty.toLlvm(self).getUndef());
3099 return result.constant;
3100}
3101
3102fn blockAddrConstAssumeCapacity(
3103 self: *Builder,
3104 function: Function.Index,
3105 block: Function.Block.Index,
3106) Constant {
3107 const Adapter = struct {
3108 builder: *const Builder,
3109 pub fn hash(_: @This(), key: Constant.BlockAddress) u32 {
3110 return @truncate(std.hash.Wyhash.hash(
3111 comptime std.hash.uint32(@intFromEnum(Constant.Tag.blockaddress)),
3112 std.mem.asBytes(&key),
3113 ));
3114 }
3115 pub fn eql(ctx: @This(), lhs_key: Constant.BlockAddress, _: void, rhs_index: usize) bool {
3116 if (ctx.builder.constant_items.items(.tag)[rhs_index] != .blockaddress) return false;
3117 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
3118 const rhs_extra = ctx.builder.constantExtraData(Constant.BlockAddress, rhs_data);
3119 return std.meta.eql(lhs_key, rhs_extra);
3120 }
3121 };
3122 const data = Constant.BlockAddress{ .function = function, .block = block };
3123 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
3124 if (!gop.found_existing) {
3125 gop.key_ptr.* = {};
3126 gop.value_ptr.* = {};
3127 self.constant_items.appendAssumeCapacity(.{
3128 .tag = .blockaddress,
3129 .data = self.addConstantExtraAssumeCapacity(data),
3130 });
3131 if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity(
3132 function.toLlvm(self).blockAddress(block.toValue(self, function).toLlvm(self, function)),
3133 );
3134 }
3135 return @enumFromInt(gop.index);
3136}
3137
3138fn dsoLocalEquivalentConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {
3139 const result = self.getOrPutConstantNoExtraAssumeCapacity(
3140 .{ .tag = .dso_local_equivalent, .data = @intFromEnum(function) },
3141 );
3142 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(undefined);
3143 return result.constant;
3144}
3145
3146fn noCfiConstAssumeCapacity(self: *Builder, function: Function.Index) Constant {
3147 const result = self.getOrPutConstantNoExtraAssumeCapacity(
3148 .{ .tag = .no_cfi, .data = @intFromEnum(function) },
3149 );
3150 if (self.useLibLlvm() and result.new) self.llvm_constants.appendAssumeCapacity(undefined);
3151 return result.constant;
3152}
3153
3154fn convConstAssumeCapacity(
3155 self: *Builder,
3156 signedness: Constant.Cast.Signedness,
3157 arg: Constant,
3158 ty: Type,
3159) Constant {
3160 const arg_ty = arg.typeOf(self);
3161 if (arg_ty == ty) return arg;
3162 return self.castConstAssumeCapacity(switch (arg_ty.scalarTag(self)) {
3163 .simple => switch (ty.scalarTag(self)) {
3164 .simple => switch (std.math.order(arg_ty.scalarBits(self), ty.scalarBits(self))) {
3165 .lt => .fpext,
3166 .eq => unreachable,
3167 .gt => .fptrunc,
3168 },
3169 .integer => switch (signedness) {
3170 .unsigned => .fptoui,
3171 .signed => .fptosi,
3172 .unneeded => unreachable,
3173 },
3174 else => unreachable,
3175 },
3176 .integer => switch (ty.tag(self)) {
3177 .simple => switch (signedness) {
3178 .unsigned => .uitofp,
3179 .signed => .sitofp,
3180 .unneeded => unreachable,
3181 },
3182 .integer => switch (std.math.order(arg_ty.scalarBits(self), ty.scalarBits(self))) {
3183 .lt => switch (signedness) {
3184 .unsigned => .zext,
3185 .signed => .sext,
3186 .unneeded => unreachable,
3187 },
3188 .eq => unreachable,
3189 .gt => .trunc,
3190 },
3191 .pointer => .inttoptr,
3192 else => unreachable,
3193 },
3194 .pointer => switch (ty.tag(self)) {
3195 .integer => .ptrtoint,
3196 .pointer => .addrspacecast,
3197 else => unreachable,
3198 },
3199 else => unreachable,
3200 }, arg, ty);
3201}
3202
3203fn castConstAssumeCapacity(self: *Builder, tag: Constant.Tag, arg: Constant, ty: Type) Constant {
3204 const Key = struct { tag: Constant.Tag, cast: Constant.Cast };
3205 const Adapter = struct {
3206 builder: *const Builder,
3207 pub fn hash(_: @This(), key: Key) u32 {
3208 return @truncate(std.hash.Wyhash.hash(
3209 std.hash.uint32(@intFromEnum(key.tag)),
3210 std.mem.asBytes(&key.cast),
3211 ));
3212 }
3213 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
3214 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
3215 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
3216 const rhs_extra = ctx.builder.constantExtraData(Constant.Cast, rhs_data);
3217 return std.meta.eql(lhs_key.cast, rhs_extra);
3218 }
3219 };
3220 const data = Key{ .tag = tag, .cast = .{ .arg = arg, .type = ty } };
3221 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
3222 if (!gop.found_existing) {
3223 gop.key_ptr.* = {};
3224 gop.value_ptr.* = {};
3225 self.constant_items.appendAssumeCapacity(.{
3226 .tag = tag,
3227 .data = self.addConstantExtraAssumeCapacity(data.cast),
3228 });
3229 if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity(switch (tag) {
3230 .trunc => &llvm.Value.constTrunc,
3231 .zext => &llvm.Value.constZExt,
3232 .sext => &llvm.Value.constSExt,
3233 .fptrunc => &llvm.Value.constFPTrunc,
3234 .fpext => &llvm.Value.constFPExt,
3235 .fptoui => &llvm.Value.constFPToUI,
3236 .fptosi => &llvm.Value.constFPToSI,
3237 .uitofp => &llvm.Value.constUIToFP,
3238 .sitofp => &llvm.Value.constSIToFP,
3239 .ptrtoint => &llvm.Value.constPtrToInt,
3240 .inttoptr => &llvm.Value.constIntToPtr,
3241 .bitcast => &llvm.Value.constBitCast,
3242 else => unreachable,
3243 }(arg.toLlvm(self), ty.toLlvm(self)));
3244 }
3245 return @enumFromInt(gop.index);
3246}
3247
3248fn gepConstAssumeCapacity(
3249 self: *Builder,
3250 comptime kind: Constant.GetElementPtr.Kind,
3251 ty: Type,
3252 base: Constant,
3253 indices: []const Constant,
3254) if (build_options.have_llvm) Allocator.Error!Constant else Constant {
3255 const tag: Constant.Tag = switch (kind) {
3256 .normal => .getelementptr,
3257 .inbounds => .@"getelementptr inbounds",
3258 };
3259 const base_ty = base.typeOf(self);
3260 const base_is_vector = base_ty.isVector(self);
3261
3262 const VectorInfo = struct {
3263 kind: Type.Vector.Kind,
3264 len: u32,
3265
3266 fn init(vector_ty: Type, builder: *const Builder) @This() {
3267 return .{ .kind = vector_ty.vectorKind(builder), .len = vector_ty.vectorLen(builder) };
3268 }
3269 };
3270 var vector_info: ?VectorInfo = if (base_is_vector) VectorInfo.init(base_ty, self) else null;
3271 for (indices) |index| {
3272 const index_ty = index.typeOf(self);
3273 switch (index_ty.tag(self)) {
3274 .integer => {},
3275 .vector, .scalable_vector => {
3276 const index_info = VectorInfo.init(index_ty, self);
3277 if (vector_info) |info|
3278 assert(std.meta.eql(info, index_info))
3279 else
3280 vector_info = index_info;
3281 },
3282 else => unreachable,
3283 }
3284 }
3285 if (!base_is_vector) if (vector_info) |info| switch (info.kind) {
3286 inline else => |vector_kind| _ = self.vectorTypeAssumeCapacity(vector_kind, info.len, base_ty),
3287 };
3288
3289 const Key = struct { type: Type, base: Constant, indices: []const Constant };
3290 const Adapter = struct {
3291 builder: *const Builder,
3292 pub fn hash(_: @This(), key: Key) u32 {
3293 var hasher = std.hash.Wyhash.init(comptime std.hash.uint32(@intFromEnum(tag)));
3294 hasher.update(std.mem.asBytes(&key.type));
3295 hasher.update(std.mem.asBytes(&key.base));
3296 hasher.update(std.mem.sliceAsBytes(key.indices));
3297 return @truncate(hasher.final());
3298 }
3299 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
3300 if (ctx.builder.constant_items.items(.tag)[rhs_index] != tag) return false;
3301 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
3302 const rhs_extra = ctx.builder.constantExtraDataTrail(Constant.GetElementPtr, rhs_data);
3303 const rhs_indices: []const Constant = @ptrCast(ctx.builder.constant_extra
3304 .items[rhs_extra.end..][0..rhs_extra.data.indices_len]);
3305 return lhs_key.type == rhs_extra.data.type and lhs_key.base == rhs_extra.data.base and
3306 std.mem.eql(Constant, lhs_key.indices, rhs_indices);
3307 }
3308 };
3309 const data = Key{ .type = ty, .base = base, .indices = indices };
3310 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
3311 if (!gop.found_existing) {
3312 gop.key_ptr.* = {};
3313 gop.value_ptr.* = {};
3314 self.constant_items.appendAssumeCapacity(.{
3315 .tag = tag,
3316 .data = self.addConstantExtraAssumeCapacity(Constant.GetElementPtr{
3317 .type = ty,
3318 .base = base,
3319 .indices_len = @intCast(indices.len),
3320 }),
3321 });
3322 self.constant_extra.appendSliceAssumeCapacity(@ptrCast(indices));
3323 if (self.useLibLlvm()) {
3324 const ExpectedContents = [expected_gep_indices_len]*llvm.Value;
3325 var stack align(@alignOf(ExpectedContents)) =
3326 std.heap.stackFallback(@sizeOf(ExpectedContents), self.gpa);
3327 const allocator = stack.get();
3328
3329 const llvm_indices = try allocator.alloc(*llvm.Value, indices.len);
3330 defer allocator.free(llvm_indices);
3331 for (llvm_indices, indices) |*llvm_index, index| llvm_index.* = index.toLlvm(self);
3332
3333 self.llvm_constants.appendAssumeCapacity(switch (kind) {
3334 .normal => &llvm.Type.constGEP,
3335 .inbounds => &llvm.Type.constInBoundsGEP,
3336 }(ty.toLlvm(self), base.toLlvm(self), llvm_indices.ptr, @intCast(indices.len)));
3337 }
3338 }
3339 return @enumFromInt(gop.index);
3340}
3341
3342fn binConstAssumeCapacity(
3343 self: *Builder,
3344 tag: Constant.Tag,
3345 lhs: Constant,
3346 rhs: Constant,
3347) Constant {
3348 switch (tag) {
3349 .add, .sub, .mul, .shl, .lshr, .ashr, .@"and", .@"or", .xor => {},
3350 else => unreachable,
3351 }
3352 const Key = struct { tag: Constant.Tag, bin: Constant.Binary };
3353 const Adapter = struct {
3354 builder: *const Builder,
3355 pub fn hash(_: @This(), key: Key) u32 {
3356 return @truncate(std.hash.Wyhash.hash(
3357 std.hash.uint32(@intFromEnum(key.tag)),
3358 std.mem.asBytes(&key.bin),
3359 ));
3360 }
3361 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
3362 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
3363 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
3364 const rhs_extra = ctx.builder.constantExtraData(Constant.Binary, rhs_data);
3365 return std.meta.eql(lhs_key.bin, rhs_extra);
3366 }
3367 };
3368 const data = Key{ .tag = tag, .bin = .{ .lhs = lhs, .rhs = rhs } };
3369 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
3370 if (!gop.found_existing) {
3371 gop.key_ptr.* = {};
3372 gop.value_ptr.* = {};
3373 self.constant_items.appendAssumeCapacity(.{
3374 .tag = tag,
3375 .data = self.addConstantExtraAssumeCapacity(data.bin),
3376 });
3377 if (self.useLibLlvm()) self.llvm_constants.appendAssumeCapacity(switch (tag) {
3378 .add => &llvm.Value.constAdd,
3379 .sub => &llvm.Value.constSub,
3380 .mul => &llvm.Value.constMul,
3381 .shl => &llvm.Value.constShl,
3382 .lshr => &llvm.Value.constLShr,
3383 .ashr => &llvm.Value.constAShr,
3384 .@"and" => &llvm.Value.constAnd,
3385 .@"or" => &llvm.Value.constOr,
3386 .xor => &llvm.Value.constXor,
3387 else => unreachable,
3388 }(lhs.toLlvm(self), rhs.toLlvm(self)));
3389 }
3390 return @enumFromInt(gop.index);
3391}
3392
3393fn ensureUnusedConstantCapacity(
3394 self: *Builder,
3395 count: usize,
3396 comptime Extra: ?type,
3397 trail_len: usize,
3398) Allocator.Error!void {
3399 try self.constant_map.ensureUnusedCapacity(self.gpa, count);
3400 try self.constant_items.ensureUnusedCapacity(self.gpa, count);
3401 if (Extra) |E| try self.constant_extra.ensureUnusedCapacity(
3402 self.gpa,
3403 count * (@typeInfo(E).Struct.fields.len + trail_len),
3404 ) else assert(trail_len == 0);
3405 if (self.useLibLlvm()) try self.llvm_constants.ensureUnusedCapacity(self.gpa, count);
3406}
3407
3408fn getOrPutConstantNoExtraAssumeCapacity(
3409 self: *Builder,
3410 item: Constant.Item,
3411) struct { new: bool, constant: Constant } {
3412 const Adapter = struct {
3413 builder: *const Builder,
3414 pub fn hash(_: @This(), key: Constant.Item) u32 {
3415 return @truncate(std.hash.Wyhash.hash(
3416 std.hash.uint32(@intFromEnum(key.tag)),
3417 std.mem.asBytes(&key.data),
3418 ));
3419 }
3420 pub fn eql(ctx: @This(), lhs_key: Constant.Item, _: void, rhs_index: usize) bool {
3421 return std.meta.eql(lhs_key, ctx.builder.constant_items.get(rhs_index));
3422 }
3423 };
3424 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(item, Adapter{ .builder = self });
3425 if (!gop.found_existing) {
3426 gop.key_ptr.* = {};
3427 gop.value_ptr.* = {};
3428 self.constant_items.appendAssumeCapacity(item);
3429 }
3430 return .{ .new = !gop.found_existing, .constant = @enumFromInt(gop.index) };
3431}
3432
3433fn getOrPutConstantAggregateAssumeCapacity(
3434 self: *Builder,
3435 tag: Constant.Tag,
3436 ty: Type,
3437 vals: []const Constant,
3438) struct { new: bool, constant: Constant } {
3439 switch (tag) {
3440 .structure, .packed_structure, .array, .vector => {},
3441 else => unreachable,
3442 }
3443 const Key = struct { tag: Constant.Tag, type: Type, vals: []const Constant };
3444 const Adapter = struct {
3445 builder: *const Builder,
3446 pub fn hash(_: @This(), key: Key) u32 {
3447 var hasher = std.hash.Wyhash.init(std.hash.uint32(@intFromEnum(key.tag)));
3448 hasher.update(std.mem.asBytes(&key.type));
3449 hasher.update(std.mem.sliceAsBytes(key.vals));
3450 return @truncate(hasher.final());
3451 }
3452 pub fn eql(ctx: @This(), lhs_key: Key, _: void, rhs_index: usize) bool {
3453 if (lhs_key.tag != ctx.builder.constant_items.items(.tag)[rhs_index]) return false;
3454 const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
3455 const rhs_extra = ctx.builder.constantExtraDataTrail(Constant.Aggregate, rhs_data);
3456 if (lhs_key.type != rhs_extra.data.type) return false;
3457 const rhs_vals: []const Constant =
3458 @ptrCast(ctx.builder.constant_extra.items[rhs_extra.end..][0..lhs_key.vals.len]);
3459 return std.mem.eql(Constant, lhs_key.vals, rhs_vals);
3460 }
3461 };
3462 const gop = self.constant_map.getOrPutAssumeCapacityAdapted(
3463 Key{ .tag = tag, .type = ty, .vals = vals },
3464 Adapter{ .builder = self },
3465 );
3466 if (!gop.found_existing) {
3467 gop.key_ptr.* = {};
3468 gop.value_ptr.* = {};
3469 self.constant_items.appendAssumeCapacity(.{
3470 .tag = tag,
3471 .data = self.addConstantExtraAssumeCapacity(Constant.Aggregate{ .type = ty }),
3472 });
3473 self.constant_extra.appendSliceAssumeCapacity(@ptrCast(vals));
3474 }
3475 return .{ .new = !gop.found_existing, .constant = @enumFromInt(gop.index) };
3476}
3477
3478fn addConstantExtraAssumeCapacity(self: *Builder, extra: anytype) Constant.Item.ExtraIndex {
3479 const result: Constant.Item.ExtraIndex = @intCast(self.constant_extra.items.len);
3480 inline for (@typeInfo(@TypeOf(extra)).Struct.fields) |field| {
3481 const value = @field(extra, field.name);
3482 self.constant_extra.appendAssumeCapacity(switch (field.type) {
3483 u32 => value,
3484 Type,
3485 Constant,
3486 Function.Index,
3487 Function.Block.Index,
3488 => @intFromEnum(value),
3489 else => @compileError("bad field type: " ++ @typeName(field.type)),
3490 });
3491 }
3492 return result;
3493}
3494
3495fn constantExtraDataTrail(
3496 self: *const Builder,
3497 comptime T: type,
3498 index: Constant.Item.ExtraIndex,
3499) struct { data: T, end: Constant.Item.ExtraIndex } {
3500 var result: T = undefined;
3501 const fields = @typeInfo(T).Struct.fields;
3502 inline for (fields, self.constant_extra.items[index..][0..fields.len]) |field, data|
3503 @field(result, field.name) = switch (field.type) {
3504 u32 => data,
3505 Type,
3506 Constant,
3507 Function.Index,
3508 Function.Block.Index,
3509 => @enumFromInt(data),
3510 else => @compileError("bad field type: " ++ @typeName(field.type)),
3511 };
3512 return .{ .data = result, .end = index + @as(Constant.Item.ExtraIndex, @intCast(fields.len)) };
3513}
3514
3515fn constantExtraData(self: *const Builder, comptime T: type, index: Constant.Item.ExtraIndex) T {
3516 return self.constantExtraDataTrail(T, index).data;
3517}
3518
18303519inline fn useLibLlvm(self: *const Builder) bool {
18313520 return build_options.have_llvm and self.use_lib_llvm;
18323521}
src/codegen/llvm/bindings.zig+64-11
......@@ -168,23 +168,41 @@ pub const Value = opaque {
168168 pub const setAliasee = LLVMAliasSetAliasee;
169169 extern fn LLVMAliasSetAliasee(Alias: *Value, Aliasee: *Value) void;
170170
171 pub const constBitCast = LLVMConstBitCast;
172 extern fn LLVMConstBitCast(ConstantVal: *Value, ToType: *Type) *Value;
171 pub const constTrunc = LLVMConstTrunc;
172 extern fn LLVMConstTrunc(ConstantVal: *Value, ToType: *Type) *Value;
173173
174 pub const constIntToPtr = LLVMConstIntToPtr;
175 extern fn LLVMConstIntToPtr(ConstantVal: *Value, ToType: *Type) *Value;
174 pub const constSExt = LLVMConstSExt;
175 extern fn LLVMConstSExt(ConstantVal: *Value, ToType: *Type) *Value;
176
177 pub const constZExt = LLVMConstZExt;
178 extern fn LLVMConstZExt(ConstantVal: *Value, ToType: *Type) *Value;
179
180 pub const constFPTrunc = LLVMConstFPTrunc;
181 extern fn LLVMConstFPTrunc(ConstantVal: *Value, ToType: *Type) *Value;
182
183 pub const constFPExt = LLVMConstFPExt;
184 extern fn LLVMConstFPExt(ConstantVal: *Value, ToType: *Type) *Value;
185
186 pub const constUIToFP = LLVMConstUIToFP;
187 extern fn LLVMConstUIToFP(ConstantVal: *Value, ToType: *Type) *Value;
188
189 pub const constSIToFP = LLVMConstSIToFP;
190 extern fn LLVMConstSIToFP(ConstantVal: *Value, ToType: *Type) *Value;
191
192 pub const constFPToUI = LLVMConstFPToUI;
193 extern fn LLVMConstFPToUI(ConstantVal: *Value, ToType: *Type) *Value;
194
195 pub const constFPToSI = LLVMConstFPToSI;
196 extern fn LLVMConstFPToSI(ConstantVal: *Value, ToType: *Type) *Value;
176197
177198 pub const constPtrToInt = LLVMConstPtrToInt;
178199 extern fn LLVMConstPtrToInt(ConstantVal: *Value, ToType: *Type) *Value;
179200
180 pub const constShl = LLVMConstShl;
181 extern fn LLVMConstShl(LHSConstant: *Value, RHSConstant: *Value) *Value;
182
183 pub const constOr = LLVMConstOr;
184 extern fn LLVMConstOr(LHSConstant: *Value, RHSConstant: *Value) *Value;
201 pub const constIntToPtr = LLVMConstIntToPtr;
202 extern fn LLVMConstIntToPtr(ConstantVal: *Value, ToType: *Type) *Value;
185203
186 pub const constZExt = LLVMConstZExt;
187 extern fn LLVMConstZExt(ConstantVal: *Value, ToType: *Type) *Value;
204 pub const constBitCast = LLVMConstBitCast;
205 extern fn LLVMConstBitCast(ConstantVal: *Value, ToType: *Type) *Value;
188206
189207 pub const constZExtOrBitCast = LLVMConstZExtOrBitCast;
190208 extern fn LLVMConstZExtOrBitCast(ConstantVal: *Value, ToType: *Type) *Value;
......@@ -195,6 +213,30 @@ pub const Value = opaque {
195213 pub const constAdd = LLVMConstAdd;
196214 extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
197215
216 pub const constSub = LLVMConstSub;
217 extern fn LLVMConstSub(LHSConstant: *Value, RHSConstant: *Value) *Value;
218
219 pub const constMul = LLVMConstMul;
220 extern fn LLVMConstMul(LHSConstant: *Value, RHSConstant: *Value) *Value;
221
222 pub const constAnd = LLVMConstAnd;
223 extern fn LLVMConstAnd(LHSConstant: *Value, RHSConstant: *Value) *Value;
224
225 pub const constOr = LLVMConstOr;
226 extern fn LLVMConstOr(LHSConstant: *Value, RHSConstant: *Value) *Value;
227
228 pub const constXor = LLVMConstXor;
229 extern fn LLVMConstXor(LHSConstant: *Value, RHSConstant: *Value) *Value;
230
231 pub const constShl = LLVMConstShl;
232 extern fn LLVMConstShl(LHSConstant: *Value, RHSConstant: *Value) *Value;
233
234 pub const constLShr = LLVMConstLShr;
235 extern fn LLVMConstLShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
236
237 pub const constAShr = LLVMConstAShr;
238 extern fn LLVMConstAShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
239
198240 pub const constAddrSpaceCast = LLVMConstAddrSpaceCast;
199241 extern fn LLVMConstAddrSpaceCast(ConstantVal: *Value, ToType: *Type) *Value;
200242
......@@ -281,6 +323,9 @@ pub const Value = opaque {
281323 pub const attachMetaData = ZigLLVMAttachMetaData;
282324 extern fn ZigLLVMAttachMetaData(GlobalVar: *Value, DIG: *DIGlobalVariableExpression) void;
283325
326 pub const blockAddress = LLVMBlockAddress;
327 extern fn LLVMBlockAddress(F: *Value, BB: *BasicBlock) *Value;
328
284329 pub const dump = LLVMDumpValue;
285330 extern fn LLVMDumpValue(Val: *Value) void;
286331};
......@@ -349,6 +394,14 @@ pub const Type = opaque {
349394 pub const isSized = LLVMTypeIsSized;
350395 extern fn LLVMTypeIsSized(Ty: *Type) Bool;
351396
397 pub const constGEP = LLVMConstGEP2;
398 extern fn LLVMConstGEP2(
399 Ty: *Type,
400 ConstantVal: *Value,
401 ConstantIndices: [*]const *Value,
402 NumIndices: c_uint,
403 ) *Value;
404
352405 pub const constInBoundsGEP = LLVMConstInBoundsGEP2;
353406 extern fn LLVMConstInBoundsGEP2(
354407 Ty: *Type,