Commit 1f8407c356

Jacob Young <jacobly0@users.noreply.github.com>
2023-07-11 08:14:17
llvm: cleanup management and implement more const functions
1 parent 7ec7fe5
Changed files (3)
src/codegen/llvm/bindings.zig
@@ -168,6 +168,66 @@ pub const Value = opaque {
     pub const setAliasee = LLVMAliasSetAliasee;
     extern fn LLVMAliasSetAliasee(Alias: *Value, Aliasee: *Value) void;
 
+    pub const constZExtOrBitCast = LLVMConstZExtOrBitCast;
+    extern fn LLVMConstZExtOrBitCast(ConstantVal: *Value, ToType: *Type) *Value;
+
+    pub const constNeg = LLVMConstNeg;
+    extern fn LLVMConstNeg(ConstantVal: *Value) *Value;
+
+    pub const constNSWNeg = LLVMConstNSWNeg;
+    extern fn LLVMConstNSWNeg(ConstantVal: *Value) *Value;
+
+    pub const constNUWNeg = LLVMConstNUWNeg;
+    extern fn LLVMConstNUWNeg(ConstantVal: *Value) *Value;
+
+    pub const constNot = LLVMConstNot;
+    extern fn LLVMConstNot(ConstantVal: *Value) *Value;
+
+    pub const constAdd = LLVMConstAdd;
+    extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constNSWAdd = LLVMConstNSWAdd;
+    extern fn LLVMConstNSWAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constNUWAdd = LLVMConstNUWAdd;
+    extern fn LLVMConstNUWAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constSub = LLVMConstSub;
+    extern fn LLVMConstSub(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constNSWSub = LLVMConstNSWSub;
+    extern fn LLVMConstNSWSub(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constNUWSub = LLVMConstNUWSub;
+    extern fn LLVMConstNUWSub(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constMul = LLVMConstMul;
+    extern fn LLVMConstMul(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constNSWMul = LLVMConstNSWMul;
+    extern fn LLVMConstNSWMul(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constNUWMul = LLVMConstNUWMul;
+    extern fn LLVMConstNUWMul(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constAnd = LLVMConstAnd;
+    extern fn LLVMConstAnd(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constOr = LLVMConstOr;
+    extern fn LLVMConstOr(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constXor = LLVMConstXor;
+    extern fn LLVMConstXor(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constShl = LLVMConstShl;
+    extern fn LLVMConstShl(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constLShr = LLVMConstLShr;
+    extern fn LLVMConstLShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+    pub const constAShr = LLVMConstAShr;
+    extern fn LLVMConstAShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
+
     pub const constTrunc = LLVMConstTrunc;
     extern fn LLVMConstTrunc(ConstantVal: *Value, ToType: *Type) *Value;
 
@@ -204,41 +264,35 @@ pub const Value = opaque {
     pub const constBitCast = LLVMConstBitCast;
     extern fn LLVMConstBitCast(ConstantVal: *Value, ToType: *Type) *Value;
 
-    pub const constZExtOrBitCast = LLVMConstZExtOrBitCast;
-    extern fn LLVMConstZExtOrBitCast(ConstantVal: *Value, ToType: *Type) *Value;
-
-    pub const constNot = LLVMConstNot;
-    extern fn LLVMConstNot(ConstantVal: *Value) *Value;
-
-    pub const constAdd = LLVMConstAdd;
-    extern fn LLVMConstAdd(LHSConstant: *Value, RHSConstant: *Value) *Value;
-
-    pub const constSub = LLVMConstSub;
-    extern fn LLVMConstSub(LHSConstant: *Value, RHSConstant: *Value) *Value;
-
-    pub const constMul = LLVMConstMul;
-    extern fn LLVMConstMul(LHSConstant: *Value, RHSConstant: *Value) *Value;
-
-    pub const constAnd = LLVMConstAnd;
-    extern fn LLVMConstAnd(LHSConstant: *Value, RHSConstant: *Value) *Value;
-
-    pub const constOr = LLVMConstOr;
-    extern fn LLVMConstOr(LHSConstant: *Value, RHSConstant: *Value) *Value;
+    pub const constAddrSpaceCast = LLVMConstAddrSpaceCast;
+    extern fn LLVMConstAddrSpaceCast(ConstantVal: *Value, ToType: *Type) *Value;
 
-    pub const constXor = LLVMConstXor;
-    extern fn LLVMConstXor(LHSConstant: *Value, RHSConstant: *Value) *Value;
+    pub const constSelect = LLVMConstSelect;
+    extern fn LLVMConstSelect(
+        ConstantCondition: *Value,
+        ConstantIfTrue: *Value,
+        ConstantIfFalse: *Value,
+    ) *Value;
 
-    pub const constShl = LLVMConstShl;
-    extern fn LLVMConstShl(LHSConstant: *Value, RHSConstant: *Value) *Value;
+    pub const constExtractElement = LLVMConstExtractElement;
+    extern fn LLVMConstExtractElement(VectorConstant: *Value, IndexConstant: *Value) *Value;
 
-    pub const constLShr = LLVMConstLShr;
-    extern fn LLVMConstLShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
+    pub const constInsertElement = LLVMConstInsertElement;
+    extern fn LLVMConstInsertElement(
+        VectorConstant: *Value,
+        ElementValueConstant: *Value,
+        IndexConstant: *Value,
+    ) *Value;
 
-    pub const constAShr = LLVMConstAShr;
-    extern fn LLVMConstAShr(LHSConstant: *Value, RHSConstant: *Value) *Value;
+    pub const constShuffleVector = LLVMConstShuffleVector;
+    extern fn LLVMConstShuffleVector(
+        VectorAConstant: *Value,
+        VectorBConstant: *Value,
+        MaskConstant: *Value,
+    ) *Value;
 
-    pub const constAddrSpaceCast = LLVMConstAddrSpaceCast;
-    extern fn LLVMConstAddrSpaceCast(ConstantVal: *Value, ToType: *Type) *Value;
+    pub const blockAddress = LLVMBlockAddress;
+    extern fn LLVMBlockAddress(F: *Value, BB: *BasicBlock) *Value;
 
     pub const setWeak = LLVMSetWeak;
     extern fn LLVMSetWeak(CmpXchgInst: *Value, IsWeak: Bool) void;
@@ -323,9 +377,6 @@ pub const Value = opaque {
     pub const attachMetaData = ZigLLVMAttachMetaData;
     extern fn ZigLLVMAttachMetaData(GlobalVar: *Value, DIG: *DIGlobalVariableExpression) void;
 
-    pub const blockAddress = LLVMBlockAddress;
-    extern fn LLVMBlockAddress(F: *Value, BB: *BasicBlock) *Value;
-
     pub const dump = LLVMDumpValue;
     extern fn LLVMDumpValue(Val: *Value) void;
 };
@@ -522,15 +573,18 @@ pub const VerifierFailureAction = enum(c_int) {
     ReturnStatus,
 };
 
-pub const constNeg = LLVMConstNeg;
-extern fn LLVMConstNeg(ConstantVal: *Value) *Value;
-
 pub const constVector = LLVMConstVector;
 extern fn LLVMConstVector(
     ScalarConstantVals: [*]*Value,
     Size: c_uint,
 ) *Value;
 
+pub const constICmp = LLVMConstICmp;
+extern fn LLVMConstICmp(Predicate: IntPredicate, LHSConstant: *Value, RHSConstant: *Value) *Value;
+
+pub const constFCmp = LLVMConstFCmp;
+extern fn LLVMConstFCmp(Predicate: RealPredicate, LHSConstant: *Value, RHSConstant: *Value) *Value;
+
 pub const getEnumAttributeKindForName = LLVMGetEnumAttributeKindForName;
 extern fn LLVMGetEnumAttributeKindForName(Name: [*]const u8, SLen: usize) c_uint;
 
src/codegen/llvm/Builder.zig
@@ -29,6 +29,7 @@ type_extra: std.ArrayListUnmanaged(u32) = .{},
 
 globals: std.AutoArrayHashMapUnmanaged(String, Global) = .{},
 next_unnamed_global: String = @enumFromInt(0),
+next_replaced_global: String = .none,
 next_unique_global_id: std.AutoHashMapUnmanaged(String, u32) = .{},
 aliases: std.ArrayListUnmanaged(Alias) = .{},
 variables: std.ArrayListUnmanaged(Variable) = .{},
@@ -55,6 +56,11 @@ pub const String = enum(u32) {
     empty,
     _,
 
+    pub fn isAnon(self: String) bool {
+        assert(self != .none);
+        return self.toIndex() == null;
+    }
+
     pub fn toSlice(self: String, b: *const Builder) ?[:0]const u8 {
         const index = self.toIndex() orelse return null;
         const start = b.string_indices.items[index];
@@ -743,18 +749,36 @@ pub const Global = struct {
         alias: Alias.Index,
         variable: Variable.Index,
         function: Function.Index,
+        replaced: Global.Index,
     },
 
     pub const Index = enum(u32) {
         none = std.math.maxInt(u32),
         _,
 
+        pub fn unwrap(self: Index, builder: *const Builder) Index {
+            var cur = self;
+            while (true) {
+                const replacement = cur.getReplacement(builder);
+                if (replacement == .none) return cur;
+                cur = replacement;
+            }
+        }
+
+        pub fn eql(self: Index, other: Index, builder: *const Builder) bool {
+            return self.unwrap(builder) == other.unwrap(builder);
+        }
+
+        pub fn name(self: Index, builder: *const Builder) String {
+            return builder.globals.keys()[@intFromEnum(self.unwrap(builder))];
+        }
+
         pub fn ptr(self: Index, builder: *Builder) *Global {
-            return &builder.globals.values()[@intFromEnum(self)];
+            return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];
         }
 
         pub fn ptrConst(self: Index, builder: *const Builder) *const Global {
-            return &builder.globals.values()[@intFromEnum(self)];
+            return &builder.globals.values()[@intFromEnum(self.unwrap(builder))];
         }
 
         pub fn toConst(self: Index) Constant {
@@ -763,7 +787,7 @@ pub const Global = struct {
 
         pub fn toLlvm(self: Index, builder: *const Builder) *llvm.Value {
             assert(builder.useLibLlvm());
-            return builder.llvm.globals.items[@intFromEnum(self)];
+            return builder.llvm.globals.items[@intFromEnum(self.unwrap(builder))];
         }
 
         const FormatData = struct {
@@ -777,44 +801,80 @@ pub const Global = struct {
             writer: anytype,
         ) @TypeOf(writer).Error!void {
             try writer.print("@{}", .{
-                data.builder.globals.keys()[@intFromEnum(data.global)].fmt(data.builder),
+                data.global.unwrap(data.builder).name(data.builder).fmt(data.builder),
             });
         }
         pub fn fmt(self: Index, builder: *const Builder) std.fmt.Formatter(format) {
             return .{ .data = .{ .global = self, .builder = builder } };
         }
 
-        pub fn rename(self: Index, builder: *Builder, name: String) Allocator.Error!void {
-            try builder.ensureUnusedCapacityGlobal(name);
-            self.renameAssumeCapacity(builder, name);
+        pub fn rename(self: Index, new_name: String, builder: *Builder) Allocator.Error!void {
+            try builder.ensureUnusedCapacityGlobal(new_name);
+            self.renameAssumeCapacity(new_name, builder);
         }
 
-        pub fn renameAssumeCapacity(self: Index, builder: *Builder, name: String) void {
-            const index = @intFromEnum(self);
-            if (builder.globals.keys()[index] == name) return;
-            if (builder.useLibLlvm()) builder.llvm.globals.appendAssumeCapacity(builder.llvm.globals.items[index]);
-            _ = builder.addGlobalAssumeCapacity(name, builder.globals.values()[index]);
-            if (builder.useLibLlvm()) _ = builder.llvm.globals.pop();
-            builder.globals.swapRemoveAt(index);
-            self.updateName(builder);
+        pub fn takeName(self: Index, other: Index, builder: *Builder) Allocator.Error!void {
+            try builder.ensureUnusedCapacityGlobal(.empty);
+            self.takeNameAssumeCapacity(other, builder);
         }
 
-        pub fn takeName(self: Index, builder: *Builder, other: Index) Allocator.Error!void {
+        pub fn replace(self: Index, other: Index, builder: *Builder) Allocator.Error!void {
             try builder.ensureUnusedCapacityGlobal(.empty);
-            self.takeNameAssumeCapacity(builder, other);
+            self.replaceAssumeCapacity(other, builder);
+        }
+
+        fn renameAssumeCapacity(self: Index, new_name: String, builder: *Builder) void {
+            const old_name = self.name(builder);
+            if (new_name == old_name) return;
+            const index = @intFromEnum(self.unwrap(builder));
+            if (builder.useLibLlvm())
+                builder.llvm.globals.appendAssumeCapacity(builder.llvm.globals.items[index]);
+            _ = builder.addGlobalAssumeCapacity(new_name, builder.globals.values()[index]);
+            if (builder.useLibLlvm()) _ = builder.llvm.globals.pop();
+            builder.globals.swapRemoveAt(index);
+            self.updateName(builder);
+            if (!old_name.isAnon()) return;
+            builder.next_unnamed_global = @enumFromInt(@intFromEnum(builder.next_unnamed_global) - 1);
+            if (builder.next_unnamed_global == old_name) return;
+            builder.getGlobal(builder.next_unnamed_global).?.renameAssumeCapacity(old_name, builder);
         }
 
-        pub fn takeNameAssumeCapacity(self: Index, builder: *Builder, other: Index) void {
-            const other_name = builder.globals.keys()[@intFromEnum(other)];
-            other.renameAssumeCapacity(builder, .none);
-            self.renameAssumeCapacity(builder, other_name);
+        fn takeNameAssumeCapacity(self: Index, other: Index, builder: *Builder) void {
+            const other_name = other.name(builder);
+            other.renameAssumeCapacity(.empty, builder);
+            self.renameAssumeCapacity(other_name, builder);
         }
 
         fn updateName(self: Index, builder: *const Builder) void {
             if (!builder.useLibLlvm()) return;
-            const index = @intFromEnum(self);
-            const slice = builder.globals.keys()[index].toSlice(builder) orelse "";
-            builder.llvm.globals.items[index].setValueName2(slice.ptr, slice.len);
+            const index = @intFromEnum(self.unwrap(builder));
+            const name_slice = self.name(builder).toSlice(builder) orelse "";
+            builder.llvm.globals.items[index].setValueName2(name_slice.ptr, name_slice.len);
+        }
+
+        fn replaceAssumeCapacity(self: Index, other: Index, builder: *Builder) void {
+            if (self.eql(other, builder)) return;
+            builder.next_replaced_global = @enumFromInt(@intFromEnum(builder.next_replaced_global) - 1);
+            self.renameAssumeCapacity(builder.next_replaced_global, builder);
+            if (builder.useLibLlvm()) {
+                const self_llvm = self.toLlvm(builder);
+                self_llvm.replaceAllUsesWith(other.toLlvm(builder));
+                switch (self.ptr(builder).kind) {
+                    .alias,
+                    .variable,
+                    => self_llvm.deleteGlobal(),
+                    .function => self_llvm.deleteFunction(),
+                    .replaced => unreachable,
+                }
+            }
+            self.ptr(builder).kind = .{ .replaced = other.unwrap(builder) };
+        }
+
+        fn getReplacement(self: Index, builder: *const Builder) Index {
+            return switch (builder.globals.values()[@intFromEnum(self)].kind) {
+                .replaced => |replacement| replacement,
+                else => .none,
+            };
         }
     };
 
@@ -1014,8 +1074,14 @@ pub const Constant = enum(u32) {
         insertelement,
         shufflevector,
         add,
+        @"add nsw",
+        @"add nuw",
         sub,
+        @"sub nsw",
+        @"sub nuw",
         mul,
+        @"mul nsw",
+        @"mul nuw",
         shl,
         lshr,
         ashr,
@@ -1084,24 +1150,24 @@ pub const Constant = enum(u32) {
         pub const Kind = enum { normal, inbounds };
     };
 
-    pub const Compare = struct {
+    pub const Compare = extern struct {
         cond: u32,
         lhs: Constant,
         rhs: Constant,
     };
 
-    pub const ExtractElement = struct {
+    pub const ExtractElement = extern struct {
         arg: Constant,
         index: Constant,
     };
 
-    pub const InsertElement = struct {
+    pub const InsertElement = extern struct {
         arg: Constant,
         elem: Constant,
         index: Constant,
     };
 
-    pub const ShuffleVector = struct {
+    pub const ShuffleVector = extern struct {
         lhs: Constant,
         rhs: Constant,
         mask: Constant,
@@ -1243,8 +1309,14 @@ pub const Constant = enum(u32) {
                         };
                     },
                     .add,
+                    .@"add nsw",
+                    .@"add nuw",
                     .sub,
+                    .@"sub nsw",
+                    .@"sub nuw",
                     .mul,
+                    .@"mul nsw",
+                    .@"mul nuw",
                     .shl,
                     .lshr,
                     .ashr,
@@ -1326,14 +1398,14 @@ pub const Constant = enum(u32) {
                 switch (item.tag) {
                     .positive_integer,
                     .negative_integer,
-                    => {
+                    => |tag| {
                         const extra: *align(@alignOf(std.math.big.Limb)) Integer =
                             @ptrCast(data.builder.constant_limbs.items[item.data..][0..Integer.limbs]);
                         const limbs = data.builder.constant_limbs
                             .items[item.data + Integer.limbs ..][0..extra.limbs_len];
                         const bigint = std.math.big.int.Const{
                             .limbs = limbs,
-                            .positive = item.tag == .positive_integer,
+                            .positive = tag == .positive_integer,
                         };
                         const ExpectedContents = extern struct {
                             string: [(64 * 8 / std.math.log2(10)) + 2]u8,
@@ -1352,23 +1424,63 @@ pub const Constant = enum(u32) {
                         defer allocator.free(str);
                         try writer.writeAll(str);
                     },
+                    .half,
+                    .bfloat,
+                    => |tag| try writer.print("0x{c}{X:0>4}", .{ @as(u8, switch (tag) {
+                        .half => 'H',
+                        .bfloat => 'R',
+                        else => unreachable,
+                    }), item.data >> switch (tag) {
+                        .half => 0,
+                        .bfloat => 16,
+                        else => unreachable,
+                    } }),
+                    .float => try writer.print("0x{X:0>16}", .{
+                        @as(u64, @bitCast(@as(f64, @as(f32, @bitCast(item.data))))),
+                    }),
+                    .double => {
+                        const extra = data.builder.constantExtraData(Double, item.data);
+                        try writer.print("0x{X:0>8}{X:0>8}", .{ extra.hi, extra.lo });
+                    },
+                    .fp128,
+                    .ppc_fp128,
+                    => |tag| {
+                        const extra = data.builder.constantExtraData(Fp128, item.data);
+                        try writer.print("0x{c}{X:0>8}{X:0>8}{X:0>8}{X:0>8}", .{
+                            @as(u8, switch (tag) {
+                                .fp128 => 'L',
+                                .ppc_fp128 => 'M',
+                                else => unreachable,
+                            }),
+                            extra.lo_hi,
+                            extra.lo_lo,
+                            extra.hi_hi,
+                            extra.hi_lo,
+                        });
+                    },
+                    .x86_fp80 => {
+                        const extra = data.builder.constantExtraData(Fp80, item.data);
+                        try writer.print("0xK{X:0>4}{X:0>8}{X:0>8}", .{
+                            extra.hi, extra.lo_hi, extra.lo_lo,
+                        });
+                    },
                     .null,
                     .none,
                     .zeroinitializer,
                     .undef,
                     .poison,
-                    => try writer.writeAll(@tagName(item.tag)),
+                    => |tag| try writer.writeAll(@tagName(tag)),
                     .structure,
                     .packed_structure,
                     .array,
                     .vector,
-                    => {
+                    => |tag| {
                         const extra = data.builder.constantExtraDataTrail(Aggregate, item.data);
                         const len = extra.data.type.aggregateLen(data.builder);
                         const vals: []const Constant =
                             @ptrCast(data.builder.constant_extra.items[extra.end..][0..len]);
 
-                        try writer.writeAll(switch (item.tag) {
+                        try writer.writeAll(switch (tag) {
                             .structure => "{ ",
                             .packed_structure => "<{ ",
                             .array => "[",
@@ -1379,7 +1491,7 @@ pub const Constant = enum(u32) {
                             if (index > 0) try writer.writeAll(", ");
                             try writer.print("{%}", .{val.fmt(data.builder)});
                         }
-                        try writer.writeAll(switch (item.tag) {
+                        try writer.writeAll(switch (tag) {
                             .structure => " }",
                             .packed_structure => " }>",
                             .array => "]",
@@ -1387,33 +1499,130 @@ pub const Constant = enum(u32) {
                             else => unreachable,
                         });
                     },
-                    .string => try writer.print(
-                        \\c{"}
-                    , .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}),
-                    .string_null => try writer.print(
-                        \\c{"@}
-                    , .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}),
-                    .blockaddress => {
+                    inline .string,
+                    .string_null,
+                    => |tag| try writer.print("c{\"" ++ switch (tag) {
+                        .string => "",
+                        .string_null => "@",
+                        else => unreachable,
+                    } ++ "}", .{@as(String, @enumFromInt(item.data)).fmt(data.builder)}),
+                    .blockaddress => |tag| {
                         const extra = data.builder.constantExtraData(BlockAddress, item.data);
                         const function = extra.function.ptrConst(data.builder);
                         try writer.print("{s}({}, %{d})", .{
-                            @tagName(item.tag),
+                            @tagName(tag),
                             function.global.fmt(data.builder),
                             @intFromEnum(extra.block), // TODO
                         });
                     },
                     .dso_local_equivalent,
                     .no_cfi,
-                    => {
+                    => |tag| {
                         const extra = data.builder.constantExtraData(FunctionReference, item.data);
                         try writer.print("{s} {}", .{
-                            @tagName(item.tag),
+                            @tagName(tag),
                             extra.function.ptrConst(data.builder).global.fmt(data.builder),
                         });
                     },
-                    else => try writer.print("<{s}:0x{X}>", .{
-                        @tagName(item.tag), @intFromEnum(data.constant),
-                    }),
+                    .trunc,
+                    .zext,
+                    .sext,
+                    .fptrunc,
+                    .fpext,
+                    .fptoui,
+                    .fptosi,
+                    .uitofp,
+                    .sitofp,
+                    .ptrtoint,
+                    .inttoptr,
+                    .bitcast,
+                    .addrspacecast,
+                    => |tag| {
+                        const extra = data.builder.constantExtraData(Cast, item.data);
+                        try writer.print("{s} ({%} to {%})", .{
+                            @tagName(tag),
+                            extra.arg.fmt(data.builder),
+                            extra.type.fmt(data.builder),
+                        });
+                    },
+                    .getelementptr,
+                    .@"getelementptr inbounds",
+                    => |tag| {
+                        const extra = data.builder.constantExtraDataTrail(GetElementPtr, item.data);
+                        const indices: []const Constant = @ptrCast(data.builder.constant_extra
+                            .items[extra.end..][0..extra.data.indices_len]);
+                        try writer.print("{s} ({%}, {%}", .{
+                            @tagName(tag),
+                            extra.data.type.fmt(data.builder),
+                            extra.data.base.fmt(data.builder),
+                        });
+                        for (indices) |index| try writer.print(", {%}", .{index.fmt(data.builder)});
+                        try writer.writeByte(')');
+                    },
+                    inline .icmp,
+                    .fcmp,
+                    => |tag| {
+                        const extra = data.builder.constantExtraData(Compare, item.data);
+                        try writer.print("{s} {s} ({%}, {%})", .{
+                            @tagName(tag),
+                            @tagName(@as(switch (tag) {
+                                .icmp => IntegerCondition,
+                                .fcmp => FloatCondition,
+                                else => unreachable,
+                            }, @enumFromInt(extra.cond))),
+                            extra.lhs.fmt(data.builder),
+                            extra.rhs.fmt(data.builder),
+                        });
+                    },
+                    .extractelement => |tag| {
+                        const extra = data.builder.constantExtraData(ExtractElement, item.data);
+                        try writer.print("{s} ({%}, {%})", .{
+                            @tagName(tag),
+                            extra.arg.fmt(data.builder),
+                            extra.index.fmt(data.builder),
+                        });
+                    },
+                    .insertelement => |tag| {
+                        const extra = data.builder.constantExtraData(InsertElement, item.data);
+                        try writer.print("{s} ({%}, {%}, {%})", .{
+                            @tagName(tag),
+                            extra.arg.fmt(data.builder),
+                            extra.elem.fmt(data.builder),
+                            extra.index.fmt(data.builder),
+                        });
+                    },
+                    .shufflevector => |tag| {
+                        const extra = data.builder.constantExtraData(ShuffleVector, item.data);
+                        try writer.print("{s} ({%}, {%}, {%})", .{
+                            @tagName(tag),
+                            extra.lhs.fmt(data.builder),
+                            extra.rhs.fmt(data.builder),
+                            extra.mask.fmt(data.builder),
+                        });
+                    },
+                    .add,
+                    .@"add nsw",
+                    .@"add nuw",
+                    .sub,
+                    .@"sub nsw",
+                    .@"sub nuw",
+                    .mul,
+                    .@"mul nsw",
+                    .@"mul nuw",
+                    .shl,
+                    .lshr,
+                    .ashr,
+                    .@"and",
+                    .@"or",
+                    .xor,
+                    => |tag| {
+                        const extra = data.builder.constantExtraData(Binary, item.data);
+                        try writer.print("{s} ({%}, {%})", .{
+                            @tagName(tag),
+                            extra.lhs.fmt(data.builder),
+                            extra.rhs.fmt(data.builder),
+                        });
+                    },
                 }
             },
             .global => |global| try writer.print("{}", .{global.fmt(data.builder)}),
@@ -1882,6 +2091,7 @@ pub fn namedTypeSetBody(
 }
 
 pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!Global.Index {
+    assert(!name.isAnon());
     try self.ensureUnusedTypeCapacity(1, null, 0);
     try self.ensureUnusedCapacityGlobal(name);
     return self.addGlobalAssumeCapacity(name, global);
@@ -1890,9 +2100,10 @@ pub fn addGlobal(self: *Builder, name: String, global: Global) Allocator.Error!G
 pub fn addGlobalAssumeCapacity(self: *Builder, name: String, global: Global) Global.Index {
     _ = self.ptrTypeAssumeCapacity(global.addr_space);
     var id = name;
-    if (id == .none) {
+    if (name == .empty) {
         id = self.next_unnamed_global;
-        self.next_unnamed_global = @enumFromInt(@intFromEnum(self.next_unnamed_global) + 1);
+        assert(id != self.next_replaced_global);
+        self.next_unnamed_global = @enumFromInt(@intFromEnum(id) + 1);
     }
     while (true) {
         const global_gop = self.globals.getOrPutAssumeCapacity(id);
@@ -2136,7 +2347,7 @@ pub fn binConst(
     return self.binConstAssumeCapacity(tag, lhs, rhs);
 }
 
-pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
+pub fn dump(self: *Builder, writer: anytype) (@TypeOf(writer).Error || Allocator.Error)!void {
     if (self.source_filename != .none) try writer.print(
         \\; ModuleID = '{s}'
         \\source_filename = {"}
@@ -2157,7 +2368,8 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
     , .{ id.fmt(self), ty.fmt(self) });
     try writer.writeByte('\n');
     for (self.variables.items) |variable| {
-        const global = self.globals.values()[@intFromEnum(variable.global)];
+        if (variable.global.getReplacement(self) != .none) continue;
+        const global = variable.global.ptrConst(self);
         try writer.print(
             \\{} ={}{}{}{}{}{}{}{} {s} {%}{ }{,}
             \\
@@ -2179,7 +2391,8 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
     }
     try writer.writeByte('\n');
     for (self.functions.items) |function| {
-        const global = self.globals.values()[@intFromEnum(function.global)];
+        if (function.global.getReplacement(self) != .none) continue;
+        const global = function.global.ptrConst(self);
         const item = self.type_items.items[@intFromEnum(global.type)];
         const extra = self.typeExtraDataTrail(Type.Function, item.data);
         const params: []const Type =
@@ -2207,14 +2420,51 @@ pub fn dump(self: *Builder, writer: anytype) @TypeOf(writer).Error!void {
             },
             else => unreachable,
         }
-        try writer.print(") {}{}", .{ global.unnamed_addr, global.alignment });
-        if (function.body) |_| try writer.print(
-            \\{{
-            \\  ret {%}
-            \\}}
-            \\
-        , .{extra.data.ret.fmt(self)});
-        try writer.writeByte('\n');
+        try writer.print("){}{}", .{ global.unnamed_addr, global.alignment });
+        if (function.body) |_| {
+            try writer.writeAll(" {\n  ret ");
+            void: {
+                try writer.print("{%}", .{switch (extra.data.ret) {
+                    .void => |tag| {
+                        try writer.writeAll(@tagName(tag));
+                        break :void;
+                    },
+                    inline .half,
+                    .bfloat,
+                    .float,
+                    .double,
+                    .fp128,
+                    .x86_fp80,
+                    => |tag| try @field(Builder, @tagName(tag) ++ "Const")(self, 0.0),
+                    .ppc_fp128 => try self.ppc_fp128Const(.{ 0.0, 0.0 }),
+                    .x86_amx,
+                    .x86_mmx,
+                    .label,
+                    .metadata,
+                    => unreachable,
+                    .token => Constant.none,
+                    else => switch (extra.data.ret.tag(self)) {
+                        .simple,
+                        .function,
+                        .vararg_function,
+                        => unreachable,
+                        .integer => try self.intConst(extra.data.ret, 0),
+                        .pointer => try self.nullConst(extra.data.ret),
+                        .target,
+                        .vector,
+                        .scalable_vector,
+                        .small_array,
+                        .array,
+                        .structure,
+                        .packed_structure,
+                        .named_structure,
+                        => try self.zeroInitConst(extra.data.ret),
+                    },
+                }.fmt(self)});
+            }
+            try writer.writeAll("\n}");
+        }
+        try writer.writeAll("\n\n");
     }
 }
 
@@ -2497,11 +2747,11 @@ fn opaqueTypeAssumeCapacity(self: *Builder, name: String) Type {
         }
     };
     var id = name;
-    if (name == .none) {
+    if (name == .empty) {
         id = self.next_unnamed_type;
         assert(id != .none);
         self.next_unnamed_type = @enumFromInt(@intFromEnum(id) + 1);
-    } else assert(name.toIndex() != null);
+    } else assert(!name.isAnon());
     while (true) {
         const type_gop = self.types.getOrPutAssumeCapacity(id);
         if (!type_gop.found_existing) {
@@ -2783,8 +3033,8 @@ fn doubleConstAssumeCapacity(self: *Builder, val: f64) Constant {
         self.constant_items.appendAssumeCapacity(.{
             .tag = .double,
             .data = self.addConstantExtraAssumeCapacity(Constant.Double{
-                .lo = @intCast(@as(u64, @bitCast(val)) >> 32),
-                .hi = @truncate(@as(u64, @bitCast(val))),
+                .lo = @truncate(@as(u64, @bitCast(val))),
+                .hi = @intCast(@as(u64, @bitCast(val)) >> 32),
             }),
         });
         if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
@@ -3401,6 +3651,190 @@ fn gepConstAssumeCapacity(
     return @enumFromInt(gop.index);
 }
 
+fn icmpConstAssumeCapacity(
+    self: *Builder,
+    cond: IntegerCondition,
+    lhs: Constant,
+    rhs: Constant,
+) Constant {
+    const Adapter = struct {
+        builder: *const Builder,
+        pub fn hash(_: @This(), key: Constant.Compare) u32 {
+            return @truncate(std.hash.Wyhash.hash(
+                std.hash.uint32(@intFromEnum(Constant.tag.icmp)),
+                std.mem.asBytes(&key),
+            ));
+        }
+        pub fn eql(ctx: @This(), lhs_key: Constant.Compare, _: void, rhs_index: usize) bool {
+            if (ctx.builder.constant_items.items(.tag)[rhs_index] != .icmp) return false;
+            const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
+            const rhs_extra = ctx.builder.constantExtraData(Constant.Compare, rhs_data);
+            return std.meta.eql(lhs_key, rhs_extra);
+        }
+    };
+    const data = Constant.Compare{ .cond = @intFromEnum(cond), .lhs = lhs, .rhs = rhs };
+    const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
+    if (!gop.found_existing) {
+        gop.key_ptr.* = {};
+        gop.value_ptr.* = {};
+        self.constant_items.appendAssumeCapacity(.{
+            .tag = .icmp,
+            .data = self.addConstantExtraAssumeCapacity(data),
+        });
+        if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
+            llvm.constICmp(@enumFromInt(@intFromEnum(cond)), lhs.toLlvm(self), rhs.toLlvm(self)),
+        );
+    }
+    return @enumFromInt(gop.index);
+}
+
+fn fcmpConstAssumeCapacity(
+    self: *Builder,
+    cond: FloatCondition,
+    lhs: Constant,
+    rhs: Constant,
+) Constant {
+    const Adapter = struct {
+        builder: *const Builder,
+        pub fn hash(_: @This(), key: Constant.Compare) u32 {
+            return @truncate(std.hash.Wyhash.hash(
+                std.hash.uint32(@intFromEnum(Constant.tag.fcmp)),
+                std.mem.asBytes(&key),
+            ));
+        }
+        pub fn eql(ctx: @This(), lhs_key: Constant.Compare, _: void, rhs_index: usize) bool {
+            if (ctx.builder.constant_items.items(.tag)[rhs_index] != .fcmp) return false;
+            const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
+            const rhs_extra = ctx.builder.constantExtraData(Constant.Compare, rhs_data);
+            return std.meta.eql(lhs_key, rhs_extra);
+        }
+    };
+    const data = Constant.Compare{ .cond = @intFromEnum(cond), .lhs = lhs, .rhs = rhs };
+    const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
+    if (!gop.found_existing) {
+        gop.key_ptr.* = {};
+        gop.value_ptr.* = {};
+        self.constant_items.appendAssumeCapacity(.{
+            .tag = .fcmp,
+            .data = self.addConstantExtraAssumeCapacity(data),
+        });
+        if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
+            llvm.constFCmp(@enumFromInt(@intFromEnum(cond)), lhs.toLlvm(self), rhs.toLlvm(self)),
+        );
+    }
+    return @enumFromInt(gop.index);
+}
+
+fn extractElementConstAssumeCapacity(
+    self: *Builder,
+    arg: Constant,
+    index: Constant,
+) Constant {
+    const Adapter = struct {
+        builder: *const Builder,
+        pub fn hash(_: @This(), key: Constant.ExtractElement) u32 {
+            return @truncate(std.hash.Wyhash.hash(
+                comptime std.hash.uint32(@intFromEnum(Constant.Tag.extractelement)),
+                std.mem.asBytes(&key),
+            ));
+        }
+        pub fn eql(ctx: @This(), lhs_key: Constant.ExtractElement, _: void, rhs_index: usize) bool {
+            if (ctx.builder.constant_items.items(.tag)[rhs_index] != .extractelement) return false;
+            const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
+            const rhs_extra = ctx.builder.constantExtraData(Constant.ExtractElement, rhs_data);
+            return std.meta.eql(lhs_key, rhs_extra);
+        }
+    };
+    const data = Constant.ExtractElement{ .arg = arg, .index = index };
+    const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
+    if (!gop.found_existing) {
+        gop.key_ptr.* = {};
+        gop.value_ptr.* = {};
+        self.constant_items.appendAssumeCapacity(.{
+            .tag = .extractelement,
+            .data = self.addConstantExtraAssumeCapacity(data),
+        });
+        if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
+            arg.toLlvm(self).constExtractElement(index.toLlvm(self)),
+        );
+    }
+    return @enumFromInt(gop.index);
+}
+
+fn insertElementConstAssumeCapacity(
+    self: *Builder,
+    arg: Constant,
+    elem: Constant,
+    index: Constant,
+) Constant {
+    const Adapter = struct {
+        builder: *const Builder,
+        pub fn hash(_: @This(), key: Constant.InsertElement) u32 {
+            return @truncate(std.hash.Wyhash.hash(
+                comptime std.hash.uint32(@intFromEnum(Constant.Tag.insertelement)),
+                std.mem.asBytes(&key),
+            ));
+        }
+        pub fn eql(ctx: @This(), lhs_key: Constant.InsertElement, _: void, rhs_index: usize) bool {
+            if (ctx.builder.constant_items.items(.tag)[rhs_index] != .insertelement) return false;
+            const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
+            const rhs_extra = ctx.builder.constantExtraData(Constant.InsertElement, rhs_data);
+            return std.meta.eql(lhs_key, rhs_extra);
+        }
+    };
+    const data = Constant.InsertElement{ .arg = arg, .elem = elem, .index = index };
+    const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
+    if (!gop.found_existing) {
+        gop.key_ptr.* = {};
+        gop.value_ptr.* = {};
+        self.constant_items.appendAssumeCapacity(.{
+            .tag = .insertelement,
+            .data = self.addConstantExtraAssumeCapacity(data),
+        });
+        if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
+            arg.toLlvm(self).constInsertElement(elem.toLlvm(self), index.toLlvm(self)),
+        );
+    }
+    return @enumFromInt(gop.index);
+}
+
+fn shuffleVectorConstAssumeCapacity(
+    self: *Builder,
+    lhs: Constant,
+    rhs: Constant,
+    mask: Constant,
+) Constant {
+    const Adapter = struct {
+        builder: *const Builder,
+        pub fn hash(_: @This(), key: Constant.ShuffleVector) u32 {
+            return @truncate(std.hash.Wyhash.hash(
+                comptime std.hash.uint32(@intFromEnum(Constant.Tag.shufflevector)),
+                std.mem.asBytes(&key),
+            ));
+        }
+        pub fn eql(ctx: @This(), lhs_key: Constant.ShuffleVector, _: void, rhs_index: usize) bool {
+            if (ctx.builder.constant_items.items(.tag)[rhs_index] != .shufflevector) return false;
+            const rhs_data = ctx.builder.constant_items.items(.data)[rhs_index];
+            const rhs_extra = ctx.builder.constantExtraData(Constant.ShuffleVector, rhs_data);
+            return std.meta.eql(lhs_key, rhs_extra);
+        }
+    };
+    const data = Constant.ShuffleVector{ .lhs = lhs, .rhs = rhs, .mask = mask };
+    const gop = self.constant_map.getOrPutAssumeCapacityAdapted(data, Adapter{ .builder = self });
+    if (!gop.found_existing) {
+        gop.key_ptr.* = {};
+        gop.value_ptr.* = {};
+        self.constant_items.appendAssumeCapacity(.{
+            .tag = .shufflevector,
+            .data = self.addConstantExtraAssumeCapacity(data),
+        });
+        if (self.useLibLlvm()) self.llvm.constants.appendAssumeCapacity(
+            lhs.toLlvm(self).constShuffleVector(rhs.toLlvm(self), mask.toLlvm(self)),
+        );
+    }
+    return @enumFromInt(gop.index);
+}
+
 fn binConstAssumeCapacity(
     self: *Builder,
     tag: Constant.Tag,
@@ -3408,7 +3842,22 @@ fn binConstAssumeCapacity(
     rhs: Constant,
 ) Constant {
     switch (tag) {
-        .add, .sub, .mul, .shl, .lshr, .ashr, .@"and", .@"or", .xor => {},
+        .add,
+        .@"add nsw",
+        .@"add nuw",
+        .sub,
+        .@"sub nsw",
+        .@"sub nuw",
+        .mul,
+        .@"mul nsw",
+        .@"mul nuw",
+        .shl,
+        .lshr,
+        .ashr,
+        .@"and",
+        .@"or",
+        .xor,
+        => {},
         else => unreachable,
     }
     const Key = struct { tag: Constant.Tag, bin: Constant.Binary };
src/codegen/llvm.zig
@@ -533,15 +533,6 @@ const DataLayoutBuilder = struct {
     }
 };
 
-/// TODO can this be done with simpler logic / different API binding?
-fn deleteLlvmGlobal(llvm_global: *llvm.Value) void {
-    if (llvm_global.globalGetValueType().getTypeKind() == .Function) {
-        llvm_global.deleteFunction();
-        return;
-    }
-    return llvm_global.deleteGlobal();
-}
-
 pub const Object = struct {
     gpa: Allocator,
     builder: Builder,
@@ -818,7 +809,7 @@ pub const Object = struct {
                 .init = str_init,
             };
             try o.builder.llvm.globals.append(o.gpa, str_global);
-            const str_global_index = try o.builder.addGlobal(.none, global);
+            const str_global_index = try o.builder.addGlobal(.empty, global);
             try o.builder.variables.append(o.gpa, variable);
 
             llvm_error.* = try o.builder.structConst(llvm_slice_ty, &.{
@@ -848,7 +839,7 @@ pub const Object = struct {
             .init = error_name_table_init,
         };
         try o.builder.llvm.globals.append(o.gpa, error_name_table_global);
-        _ = try o.builder.addGlobal(.none, global);
+        _ = try o.builder.addGlobal(.empty, global);
         try o.builder.variables.append(o.gpa, variable);
 
         const error_name_table_ptr = error_name_table_global;
@@ -904,35 +895,27 @@ pub const Object = struct {
         // This map has externs with incorrect symbol names.
         for (object.extern_collisions.keys()) |decl_index| {
             const global = object.decl_map.get(decl_index) orelse continue;
-            const llvm_global = global.toLlvm(&object.builder);
             // Same logic as below but for externs instead of exports.
             const decl_name = object.builder.stringIfExists(mod.intern_pool.stringToSlice(mod.declPtr(decl_index).name)) orelse continue;
             const other_global = object.builder.getGlobal(decl_name) orelse continue;
-            const other_llvm_global = other_global.toLlvm(&object.builder);
-            if (other_llvm_global == llvm_global) continue;
+            if (other_global.eql(global, &object.builder)) continue;
 
-            llvm_global.replaceAllUsesWith(other_llvm_global);
-            deleteLlvmGlobal(llvm_global);
-            object.builder.llvm.globals.items[@intFromEnum(global)] = other_llvm_global;
+            try global.replace(other_global, &object.builder);
         }
         object.extern_collisions.clearRetainingCapacity();
 
         for (mod.decl_exports.keys(), mod.decl_exports.values()) |decl_index, export_list| {
             const global = object.decl_map.get(decl_index) orelse continue;
-            const llvm_global = global.toLlvm(&object.builder);
             for (export_list.items) |exp| {
                 // Detect if the LLVM global has already been created as an extern. In such
                 // case, we need to replace all uses of it with this exported global.
                 const exp_name = object.builder.stringIfExists(mod.intern_pool.stringToSlice(exp.opts.name)) orelse continue;
 
                 const other_global = object.builder.getGlobal(exp_name) orelse continue;
-                const other_llvm_global = other_global.toLlvm(&object.builder);
-                if (other_llvm_global == llvm_global) continue;
+                if (other_global.eql(global, &object.builder)) continue;
 
-                other_llvm_global.replaceAllUsesWith(llvm_global);
-                try global.takeName(&object.builder, other_global);
-                deleteLlvmGlobal(other_llvm_global);
-                object.builder.llvm.globals.items[@intFromEnum(other_global)] = llvm_global;
+                try global.takeName(other_global, &object.builder);
+                try other_global.replace(global, &object.builder);
                 // Problem: now we need to replace in the decl_map that
                 // the extern decl index points to this new global. However we don't
                 // know the decl index.
@@ -1519,7 +1502,7 @@ pub const Object = struct {
                 }
             }
 
-            try global.rename(&self.builder, decl_name);
+            try global.rename(decl_name, &self.builder);
             global.ptr(&self.builder).unnamed_addr = .default;
             llvm_global.setUnnamedAddr(.False);
             global.ptr(&self.builder).linkage = .external;
@@ -1558,7 +1541,7 @@ pub const Object = struct {
             global.ptr(&self.builder).updateAttributes();
         } else if (exports.len != 0) {
             const exp_name = try self.builder.string(mod.intern_pool.stringToSlice(exports[0].opts.name));
-            try global.rename(&self.builder, exp_name);
+            try global.rename(exp_name, &self.builder);
             global.ptr(&self.builder).unnamed_addr = .default;
             llvm_global.setUnnamedAddr(.False);
             if (mod.wantDllExports()) {
@@ -1641,7 +1624,7 @@ pub const Object = struct {
             }
         } else {
             const fqn = try self.builder.string(mod.intern_pool.stringToSlice(try decl.getFullyQualifiedName(mod)));
-            try global.rename(&self.builder, fqn);
+            try global.rename(fqn, &self.builder);
             global.ptr(&self.builder).linkage = .internal;
             llvm_global.setLinkage(.Internal);
             if (mod.wantDllExports()) {
@@ -2738,7 +2721,7 @@ pub const Object = struct {
             .init = llvm_init,
         };
         try o.builder.llvm.globals.append(o.gpa, llvm_global);
-        _ = try o.builder.addGlobal(.none, global);
+        _ = try o.builder.addGlobal(.empty, global);
         try o.builder.variables.append(o.gpa, variable);
 
         const addrspace_casted_global = if (llvm_wanted_addrspace != llvm_actual_addrspace)
@@ -4473,8 +4456,8 @@ pub const DeclGen = struct {
             _ = try o.resolveLlvmFunction(extern_func.decl);
         } else {
             const target = mod.getTarget();
-            const object = try o.resolveGlobalDecl(decl_index);
-            const global = object.ptrConst(&o.builder).global;
+            const variable = try o.resolveGlobalDecl(decl_index);
+            const global = variable.ptrConst(&o.builder).global;
             var llvm_global = global.toLlvm(&o.builder);
             global.ptr(&o.builder).alignment = Builder.Alignment.fromByteUnits(decl.getAlignment(mod));
             llvm_global.setAlignment(decl.getAlignment(mod));
@@ -4483,18 +4466,18 @@ pub const DeclGen = struct {
                 llvm_global.setSection(section);
             }
             assert(decl.has_tv);
-            const init_val = if (decl.val.getVariable(mod)) |decl_var| init_val: {
-                object.ptr(&o.builder).mutability = .global;
-                break :init_val decl_var.init;
-            } else init_val: {
-                object.ptr(&o.builder).mutability = .constant;
+            const init_val = if (decl.val.getVariable(mod)) |decl_var| decl_var.init else init_val: {
+                variable.ptr(&o.builder).mutability = .constant;
                 llvm_global.setGlobalConstant(.True);
                 break :init_val decl.val.toIntern();
             };
             if (init_val != .none) {
                 const llvm_init = try o.lowerValue(init_val);
+                const llvm_init_ty = llvm_init.typeOf(&o.builder);
+                global.ptr(&o.builder).type = llvm_init_ty;
+                variable.ptr(&o.builder).mutability = .global;
+                variable.ptr(&o.builder).init = llvm_init;
                 if (llvm_global.globalGetValueType() == llvm_init.typeOf(&o.builder).toLlvm(&o.builder)) {
-                    object.ptr(&o.builder).init = llvm_init;
                     llvm_global.setInitializer(llvm_init.toLlvm(&o.builder));
                 } else {
                     // LLVM does not allow us to change the type of globals. So we must
@@ -4512,7 +4495,7 @@ pub const DeclGen = struct {
                     // Related: https://github.com/ziglang/zig/issues/13265
                     const llvm_global_addrspace = toLlvmGlobalAddressSpace(decl.@"addrspace", target);
                     const new_global = o.llvm_module.addGlobalInAddressSpace(
-                        llvm_init.typeOf(&o.builder).toLlvm(&o.builder),
+                        llvm_init_ty.toLlvm(&o.builder),
                         "",
                         @intFromEnum(llvm_global_addrspace),
                     );
@@ -4525,7 +4508,7 @@ pub const DeclGen = struct {
                     // TODO: How should this work then the address space of a global changed?
                     llvm_global.replaceAllUsesWith(new_global);
                     new_global.takeName(llvm_global);
-                    o.builder.llvm.globals.items[@intFromEnum(object.ptrConst(&o.builder).global)] =
+                    o.builder.llvm.globals.items[@intFromEnum(variable.ptrConst(&o.builder).global)] =
                         new_global;
                     llvm_global.deleteGlobal();
                     llvm_global = new_global;
@@ -4672,7 +4655,7 @@ pub const FuncGen = struct {
             .init = llvm_val,
         };
         try o.builder.llvm.globals.append(o.gpa, llvm_global);
-        _ = try o.builder.addGlobal(.none, global);
+        _ = try o.builder.addGlobal(.empty, global);
         try o.builder.variables.append(o.gpa, variable);
 
         const addrspace_casted_ptr = if (llvm_actual_addrspace != llvm_wanted_addrspace)
@@ -9312,6 +9295,7 @@ pub const FuncGen = struct {
         };
         var function = Builder.Function{
             .global = @enumFromInt(o.builder.globals.count()),
+            .body = {},
         };
 
         const prev_block = self.builder.getInsertBlock();
@@ -9395,6 +9379,7 @@ pub const FuncGen = struct {
         };
         var function = Builder.Function{
             .global = @enumFromInt(o.builder.globals.count()),
+            .body = {},
         };
 
         const prev_block = self.builder.getInsertBlock();
@@ -9485,6 +9470,7 @@ pub const FuncGen = struct {
         };
         var function = Builder.Function{
             .global = @enumFromInt(o.builder.globals.count()),
+            .body = {},
         };
 
         try o.builder.llvm.globals.append(self.gpa, llvm_fn);