Commit a0cb03ed99

Jacob Young <jacobly0@users.noreply.github.com>
2023-08-07 15:35:38
llvm: finish converting instructions
1 parent 49cc1bf
Changed files (4)
src/codegen/llvm/bindings.zig
@@ -330,10 +330,7 @@ pub const Value = opaque {
     pub const fnSetSubprogram = ZigLLVMFnSetSubprogram;
     extern fn ZigLLVMFnSetSubprogram(f: *Value, subprogram: *DISubprogram) void;
 
-    pub const setValueName = LLVMSetValueName;
-    extern fn LLVMSetValueName(Val: *Value, Name: [*:0]const u8) void;
-
-    pub const setValueName2 = LLVMSetValueName2;
+    pub const setValueName = LLVMSetValueName2;
     extern fn LLVMSetValueName2(Val: *Value, Name: [*]const u8, NameLen: usize) void;
 
     pub const getValueName = LLVMGetValueName;
src/codegen/llvm/Builder.zig
@@ -2177,7 +2177,7 @@ pub const Global = struct {
             if (!builder.useLibLlvm()) return;
             const index = @intFromEnum(self.unwrap(builder));
             const name_slice = self.name(builder).slice(builder) orelse "";
-            builder.llvm.globals.items[index].setValueName2(name_slice.ptr, name_slice.len);
+            builder.llvm.globals.items[index].setValueName(name_slice.ptr, name_slice.len);
         }
 
         fn replaceAssumeCapacity(self: Index, other: Index, builder: *Builder) void {
@@ -3759,12 +3759,15 @@ pub const Function = struct {
             arg,
             ashr,
             @"ashr exact",
+            atomicrmw,
             bitcast,
             block,
             br,
             br_cond,
             call,
             @"call fast",
+            cmpxchg,
+            @"cmpxchg weak",
             extractelement,
             extractvalue,
             fadd,
@@ -3833,8 +3836,6 @@ pub const Function = struct {
             inttoptr,
             load,
             @"load atomic",
-            @"load atomic volatile",
-            @"load volatile",
             lshr,
             @"lshr exact",
             mul,
@@ -3865,8 +3866,6 @@ pub const Function = struct {
             srem,
             store,
             @"store atomic",
-            @"store atomic volatile",
-            @"store volatile",
             sub,
             @"sub nsw",
             @"sub nuw",
@@ -3879,7 +3878,6 @@ pub const Function = struct {
             @"udiv exact",
             urem,
             uitofp,
-            unimplemented,
             @"unreachable",
             va_arg,
             xor,
@@ -3920,8 +3918,6 @@ pub const Function = struct {
                     .@"ret void",
                     .store,
                     .@"store atomic",
-                    .@"store atomic volatile",
-                    .@"store volatile",
                     .@"switch",
                     .@"unreachable",
                     => false,
@@ -3933,7 +3929,6 @@ pub const Function = struct {
                     .@"notail call fast",
                     .@"tail call",
                     .@"tail call fast",
-                    .unimplemented,
                     => self.typeOfWip(wip) != .void,
                     else => true,
                 };
@@ -4003,6 +3998,7 @@ pub const Function = struct {
                     ),
                     .arg => wip.function.typeOf(wip.builder)
                         .functionParameters(wip.builder)[instruction.data],
+                    .atomicrmw => wip.extraData(AtomicRmw, instruction.data).val.typeOfWip(wip),
                     .block => .label,
                     .br,
                     .br_cond,
@@ -4011,8 +4007,6 @@ pub const Function = struct {
                     .@"ret void",
                     .store,
                     .@"store atomic",
-                    .@"store atomic volatile",
-                    .@"store volatile",
                     .@"switch",
                     .@"unreachable",
                     => .none,
@@ -4025,6 +4019,12 @@ pub const Function = struct {
                     .@"tail call",
                     .@"tail call fast",
                     => wip.extraData(Call, instruction.data).ty.functionReturn(wip.builder),
+                    .cmpxchg,
+                    .@"cmpxchg weak",
+                    => wip.builder.structTypeAssumeCapacity(.normal, &.{
+                        wip.extraData(CmpXchg, instruction.data).cmp.typeOfWip(wip),
+                        .i1,
+                    }) catch unreachable,
                     .extractelement => wip.extraData(ExtractElement, instruction.data)
                         .val.typeOfWip(wip).childType(wip.builder),
                     .extractvalue => {
@@ -4096,8 +4096,6 @@ pub const Function = struct {
                     .insertvalue => wip.extraData(InsertValue, instruction.data).val.typeOfWip(wip),
                     .load,
                     .@"load atomic",
-                    .@"load atomic volatile",
-                    .@"load volatile",
                     => wip.extraData(Load, instruction.data).type,
                     .phi,
                     .@"phi fast",
@@ -4112,7 +4110,6 @@ pub const Function = struct {
                             wip.builder,
                         );
                     },
-                    .unimplemented => @enumFromInt(instruction.data),
                     .va_arg => wip.extraData(VaArg, instruction.data).type,
                 };
             }
@@ -4186,6 +4183,8 @@ pub const Function = struct {
                     ),
                     .arg => function.global.typeOf(builder)
                         .functionParameters(builder)[instruction.data],
+                    .atomicrmw => function.extraData(AtomicRmw, instruction.data)
+                        .val.typeOf(function_index, builder),
                     .block => .label,
                     .br,
                     .br_cond,
@@ -4194,8 +4193,6 @@ pub const Function = struct {
                     .@"ret void",
                     .store,
                     .@"store atomic",
-                    .@"store atomic volatile",
-                    .@"store volatile",
                     .@"switch",
                     .@"unreachable",
                     => .none,
@@ -4208,6 +4205,13 @@ pub const Function = struct {
                     .@"tail call",
                     .@"tail call fast",
                     => function.extraData(Call, instruction.data).ty.functionReturn(builder),
+                    .cmpxchg,
+                    .@"cmpxchg weak",
+                    => builder.structTypeAssumeCapacity(.normal, &.{
+                        function.extraData(CmpXchg, instruction.data)
+                            .cmp.typeOf(function_index, builder),
+                        .i1,
+                    }) catch unreachable,
                     .extractelement => function.extraData(ExtractElement, instruction.data)
                         .val.typeOf(function_index, builder).childType(builder),
                     .extractvalue => {
@@ -4282,8 +4286,6 @@ pub const Function = struct {
                         .val.typeOf(function_index, builder),
                     .load,
                     .@"load atomic",
-                    .@"load atomic volatile",
-                    .@"load volatile",
                     => function.extraData(Load, instruction.data).type,
                     .phi,
                     .@"phi fast",
@@ -4298,7 +4300,6 @@ pub const Function = struct {
                             builder,
                         );
                     },
-                    .unimplemented => @enumFromInt(instruction.data),
                     .va_arg => function.extraData(VaArg, instruction.data).type,
                 };
             }
@@ -4346,7 +4347,7 @@ pub const Function = struct {
                 return wip.llvm.instructions.items[@intFromEnum(self)];
             }
 
-            fn llvmName(self: Instruction.Index, wip: *const WipFunction) [*:0]const u8 {
+            fn llvmName(self: Instruction.Index, wip: *const WipFunction) [:0]const u8 {
                 return if (wip.builder.strip)
                     ""
                 else
@@ -4419,15 +4420,49 @@ pub const Function = struct {
         };
 
         pub const Load = struct {
+            info: MemoryAccessInfo,
             type: Type,
             ptr: Value,
-            info: MemoryAccessInfo,
         };
 
         pub const Store = struct {
+            info: MemoryAccessInfo,
             val: Value,
             ptr: Value,
+        };
+
+        pub const CmpXchg = struct {
             info: MemoryAccessInfo,
+            ptr: Value,
+            cmp: Value,
+            new: Value,
+
+            pub const Kind = enum { strong, weak };
+        };
+
+        pub const AtomicRmw = struct {
+            info: MemoryAccessInfo,
+            ptr: Value,
+            val: Value,
+
+            pub const Operation = enum(u5) {
+                xchg,
+                add,
+                sub,
+                @"and",
+                nand,
+                @"or",
+                xor,
+                max,
+                min,
+                umax,
+                umin,
+                fadd,
+                fsub,
+                fmax,
+                fmin,
+                none = std.math.maxInt(u5),
+            };
         };
 
         pub const GetElementPtr = struct {
@@ -5163,21 +5198,21 @@ pub const WipFunction = struct {
 
     pub fn load(
         self: *WipFunction,
-        kind: MemoryAccessKind,
+        access_kind: MemoryAccessKind,
         ty: Type,
         ptr: Value,
         alignment: Alignment,
         name: []const u8,
     ) Allocator.Error!Value {
-        return self.loadAtomic(kind, ty, ptr, .system, .none, alignment, name);
+        return self.loadAtomic(access_kind, ty, ptr, .system, .none, alignment, name);
     }
 
     pub fn loadAtomic(
         self: *WipFunction,
-        kind: MemoryAccessKind,
+        access_kind: MemoryAccessKind,
         ty: Type,
         ptr: Value,
-        scope: SyncScope,
+        sync_scope: SyncScope,
         ordering: AtomicOrdering,
         alignment: Alignment,
         name: []const u8,
@@ -5186,22 +5221,21 @@ pub const WipFunction = struct {
         try self.ensureUnusedExtraCapacity(1, Instruction.Load, 0);
         const instruction = try self.addInst(name, .{
             .tag = switch (ordering) {
-                .none => switch (kind) {
-                    .normal => .load,
-                    .@"volatile" => .@"load volatile",
-                },
-                else => switch (kind) {
-                    .normal => .@"load atomic",
-                    .@"volatile" => .@"load atomic volatile",
-                },
+                .none => .load,
+                else => .@"load atomic",
             },
             .data = self.addExtraAssumeCapacity(Instruction.Load{
+                .info = .{
+                    .access_kind = access_kind,
+                    .sync_scope = switch (ordering) {
+                        .none => .system,
+                        else => sync_scope,
+                    },
+                    .success_ordering = ordering,
+                    .alignment = alignment,
+                },
                 .type = ty,
                 .ptr = ptr,
-                .info = .{ .scope = switch (ordering) {
-                    .none => .system,
-                    else => scope,
-                }, .ordering = ordering, .alignment = alignment },
             }),
         });
         if (self.builder.useLibLlvm()) {
@@ -5210,6 +5244,7 @@ pub const WipFunction = struct {
                 ptr.toLlvm(self),
                 instruction.llvmName(self),
             );
+            if (access_kind == .@"volatile") llvm_instruction.setVolatile(.True);
             if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
             if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
             self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
@@ -5229,10 +5264,10 @@ pub const WipFunction = struct {
 
     pub fn storeAtomic(
         self: *WipFunction,
-        kind: MemoryAccessKind,
+        access_kind: MemoryAccessKind,
         val: Value,
         ptr: Value,
-        scope: SyncScope,
+        sync_scope: SyncScope,
         ordering: AtomicOrdering,
         alignment: Alignment,
     ) Allocator.Error!Instruction.Index {
@@ -5240,30 +5275,26 @@ pub const WipFunction = struct {
         try self.ensureUnusedExtraCapacity(1, Instruction.Store, 0);
         const instruction = try self.addInst(null, .{
             .tag = switch (ordering) {
-                .none => switch (kind) {
-                    .normal => .store,
-                    .@"volatile" => .@"store volatile",
-                },
-                else => switch (kind) {
-                    .normal => .@"store atomic",
-                    .@"volatile" => .@"store atomic volatile",
-                },
+                .none => .store,
+                else => .@"store atomic",
             },
             .data = self.addExtraAssumeCapacity(Instruction.Store{
+                .info = .{
+                    .access_kind = access_kind,
+                    .sync_scope = switch (ordering) {
+                        .none => .system,
+                        else => sync_scope,
+                    },
+                    .success_ordering = ordering,
+                    .alignment = alignment,
+                },
                 .val = val,
                 .ptr = ptr,
-                .info = .{ .scope = switch (ordering) {
-                    .none => .system,
-                    else => scope,
-                }, .ordering = ordering, .alignment = alignment },
             }),
         });
         if (self.builder.useLibLlvm()) {
             const llvm_instruction = self.llvm.builder.buildStore(val.toLlvm(self), ptr.toLlvm(self));
-            switch (kind) {
-                .normal => {},
-                .@"volatile" => llvm_instruction.setVolatile(.True),
-            }
+            if (access_kind == .@"volatile") llvm_instruction.setVolatile(.True);
             if (ordering != .none) llvm_instruction.setOrdering(@enumFromInt(@intFromEnum(ordering)));
             if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
             self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
@@ -5273,7 +5304,7 @@ pub const WipFunction = struct {
 
     pub fn fence(
         self: *WipFunction,
-        scope: SyncScope,
+        sync_scope: SyncScope,
         ordering: AtomicOrdering,
     ) Allocator.Error!Instruction.Index {
         assert(ordering != .none);
@@ -5281,21 +5312,130 @@ pub const WipFunction = struct {
         const instruction = try self.addInst(null, .{
             .tag = .fence,
             .data = @bitCast(MemoryAccessInfo{
-                .scope = scope,
-                .ordering = ordering,
-                .alignment = undefined,
+                .sync_scope = sync_scope,
+                .success_ordering = ordering,
             }),
         });
         if (self.builder.useLibLlvm()) self.llvm.instructions.appendAssumeCapacity(
             self.llvm.builder.buildFence(
                 @enumFromInt(@intFromEnum(ordering)),
-                llvm.Bool.fromBool(scope == .singlethread),
+                llvm.Bool.fromBool(sync_scope == .singlethread),
                 "",
             ),
         );
         return instruction;
     }
 
+    pub fn cmpxchg(
+        self: *WipFunction,
+        kind: Instruction.CmpXchg.Kind,
+        access_kind: MemoryAccessKind,
+        ptr: Value,
+        cmp: Value,
+        new: Value,
+        sync_scope: SyncScope,
+        success_ordering: AtomicOrdering,
+        failure_ordering: AtomicOrdering,
+        alignment: Alignment,
+        name: []const u8,
+    ) Allocator.Error!Value {
+        assert(ptr.typeOfWip(self).isPointer(self.builder));
+        const ty = cmp.typeOfWip(self);
+        assert(ty == new.typeOfWip(self));
+        assert(success_ordering != .none);
+        assert(failure_ordering != .none);
+
+        _ = try self.builder.structType(.normal, &.{ ty, .i1 });
+        try self.ensureUnusedExtraCapacity(1, Instruction.CmpXchg, 0);
+        const instruction = try self.addInst(name, .{
+            .tag = switch (kind) {
+                .strong => .cmpxchg,
+                .weak => .@"cmpxchg weak",
+            },
+            .data = self.addExtraAssumeCapacity(Instruction.CmpXchg{
+                .info = .{
+                    .access_kind = access_kind,
+                    .sync_scope = sync_scope,
+                    .success_ordering = success_ordering,
+                    .failure_ordering = failure_ordering,
+                    .alignment = alignment,
+                },
+                .ptr = ptr,
+                .cmp = cmp,
+                .new = new,
+            }),
+        });
+        if (self.builder.useLibLlvm()) {
+            const llvm_instruction = self.llvm.builder.buildAtomicCmpXchg(
+                ptr.toLlvm(self),
+                cmp.toLlvm(self),
+                new.toLlvm(self),
+                @enumFromInt(@intFromEnum(success_ordering)),
+                @enumFromInt(@intFromEnum(failure_ordering)),
+                llvm.Bool.fromBool(sync_scope == .singlethread),
+            );
+            if (kind == .weak) llvm_instruction.setWeak(.True);
+            if (access_kind == .@"volatile") llvm_instruction.setVolatile(.True);
+            if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
+            const llvm_name = instruction.llvmName(self);
+            if (llvm_name.len > 0) llvm_instruction.setValueName(
+                llvm_name.ptr,
+                @intCast(llvm_name.len),
+            );
+            self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
+        }
+        return instruction.toValue();
+    }
+
+    pub fn atomicrmw(
+        self: *WipFunction,
+        access_kind: MemoryAccessKind,
+        operation: Instruction.AtomicRmw.Operation,
+        ptr: Value,
+        val: Value,
+        sync_scope: SyncScope,
+        ordering: AtomicOrdering,
+        alignment: Alignment,
+        name: []const u8,
+    ) Allocator.Error!Value {
+        assert(ptr.typeOfWip(self).isPointer(self.builder));
+        assert(ordering != .none);
+
+        try self.ensureUnusedExtraCapacity(1, Instruction.AtomicRmw, 0);
+        const instruction = try self.addInst(name, .{
+            .tag = .atomicrmw,
+            .data = self.addExtraAssumeCapacity(Instruction.AtomicRmw{
+                .info = .{
+                    .access_kind = access_kind,
+                    .atomic_rmw_operation = operation,
+                    .sync_scope = sync_scope,
+                    .success_ordering = ordering,
+                    .alignment = alignment,
+                },
+                .ptr = ptr,
+                .val = val,
+            }),
+        });
+        if (self.builder.useLibLlvm()) {
+            const llvm_instruction = self.llvm.builder.buildAtomicRmw(
+                @enumFromInt(@intFromEnum(operation)),
+                ptr.toLlvm(self),
+                val.toLlvm(self),
+                @enumFromInt(@intFromEnum(ordering)),
+                llvm.Bool.fromBool(sync_scope == .singlethread),
+            );
+            if (access_kind == .@"volatile") llvm_instruction.setVolatile(.True);
+            if (alignment.toByteUnits()) |bytes| llvm_instruction.setAlignment(@intCast(bytes));
+            const llvm_name = instruction.llvmName(self);
+            if (llvm_name.len > 0) llvm_instruction.setValueName(
+                llvm_name.ptr,
+                @intCast(llvm_name.len),
+            );
+            self.llvm.instructions.appendAssumeCapacity(llvm_instruction);
+        }
+        return instruction.toValue();
+    }
+
     pub fn gep(
         self: *WipFunction,
         kind: Instruction.GetElementPtr.Kind,
@@ -5747,30 +5887,6 @@ pub const WipFunction = struct {
         return instruction.toValue();
     }
 
-    pub const WipUnimplemented = struct {
-        instruction: Instruction.Index,
-
-        pub fn finish(self: WipUnimplemented, val: *llvm.Value, wip: *WipFunction) Value {
-            assert(wip.builder.useLibLlvm());
-            wip.llvm.instructions.items[@intFromEnum(self.instruction)] = val;
-            return self.instruction.toValue();
-        }
-    };
-
-    pub fn unimplemented(
-        self: *WipFunction,
-        ty: Type,
-        name: []const u8,
-    ) Allocator.Error!WipUnimplemented {
-        try self.ensureUnusedExtraCapacity(1, NoExtra, 0);
-        const instruction = try self.addInst(name, .{
-            .tag = .unimplemented,
-            .data = @intFromEnum(ty),
-        });
-        if (self.builder.useLibLlvm()) _ = self.llvm.instructions.addOneAssumeCapacity();
-        return .{ .instruction = instruction };
-    }
-
     pub fn finish(self: *WipFunction) Allocator.Error!void {
         const gpa = self.builder.gpa;
         const function = self.function.ptr(self.builder);
@@ -6035,19 +6151,19 @@ pub const WipFunction = struct {
                     .arg,
                     .block,
                     => unreachable,
+                    .atomicrmw => {
+                        const extra = self.extraData(Instruction.AtomicRmw, instruction.data);
+                        instruction.data = wip_extra.addExtra(Instruction.AtomicRmw{
+                            .info = extra.info,
+                            .ptr = instructions.map(extra.ptr),
+                            .val = instructions.map(extra.val),
+                        });
+                    },
                     .br,
                     .fence,
                     .@"ret void",
-                    .unimplemented,
                     .@"unreachable",
                     => {},
-                    .extractelement => {
-                        const extra = self.extraData(Instruction.ExtractElement, instruction.data);
-                        instruction.data = wip_extra.addExtra(Instruction.ExtractElement{
-                            .val = instructions.map(extra.val),
-                            .index = instructions.map(extra.index),
-                        });
-                    },
                     .br_cond => {
                         const extra = self.extraData(Instruction.BrCond, instruction.data);
                         instruction.data = wip_extra.addExtra(Instruction.BrCond{
@@ -6076,6 +6192,24 @@ pub const WipFunction = struct {
                         });
                         wip_extra.appendMappedValues(args, instructions);
                     },
+                    .cmpxchg,
+                    .@"cmpxchg weak",
+                    => {
+                        const extra = self.extraData(Instruction.CmpXchg, instruction.data);
+                        instruction.data = wip_extra.addExtra(Instruction.CmpXchg{
+                            .info = extra.info,
+                            .ptr = instructions.map(extra.ptr),
+                            .cmp = instructions.map(extra.cmp),
+                            .new = instructions.map(extra.new),
+                        });
+                    },
+                    .extractelement => {
+                        const extra = self.extraData(Instruction.ExtractElement, instruction.data);
+                        instruction.data = wip_extra.addExtra(Instruction.ExtractElement{
+                            .val = instructions.map(extra.val),
+                            .index = instructions.map(extra.index),
+                        });
+                    },
                     .extractvalue => {
                         var extra = self.extraDataTrail(Instruction.ExtractValue, instruction.data);
                         const indices = extra.trail.next(extra.data.indices_len, u32, self);
@@ -6121,8 +6255,6 @@ pub const WipFunction = struct {
                     },
                     .load,
                     .@"load atomic",
-                    .@"load atomic volatile",
-                    .@"load volatile",
                     => {
                         const extra = self.extraData(Instruction.Load, instruction.data);
                         instruction.data = wip_extra.addExtra(Instruction.Load{
@@ -6164,8 +6296,6 @@ pub const WipFunction = struct {
                     },
                     .store,
                     .@"store atomic",
-                    .@"store atomic volatile",
-                    .@"store volatile",
                     => {
                         const extra = self.extraData(Instruction.Store, instruction.data);
                         instruction.data = wip_extra.addExtra(Instruction.Store{
@@ -6619,6 +6749,15 @@ pub const IntegerCondition = enum(u6) {
 pub const MemoryAccessKind = enum(u1) {
     normal,
     @"volatile",
+
+    pub fn format(
+        self: MemoryAccessKind,
+        comptime prefix: []const u8,
+        _: std.fmt.FormatOptions,
+        writer: anytype,
+    ) @TypeOf(writer).Error!void {
+        if (self != .normal) try writer.print("{s}{s}", .{ prefix, @tagName(self) });
+    }
 };
 
 pub const SyncScope = enum(u1) {
@@ -6632,7 +6771,7 @@ pub const SyncScope = enum(u1) {
         writer: anytype,
     ) @TypeOf(writer).Error!void {
         if (self != .system) try writer.print(
-            \\{s} syncscope("{s}")
+            \\{s}syncscope("{s}")
         , .{ prefix, @tagName(self) });
     }
 };
@@ -6652,15 +6791,18 @@ pub const AtomicOrdering = enum(u3) {
         _: std.fmt.FormatOptions,
         writer: anytype,
     ) @TypeOf(writer).Error!void {
-        if (self != .none) try writer.print("{s} {s}", .{ prefix, @tagName(self) });
+        if (self != .none) try writer.print("{s}{s}", .{ prefix, @tagName(self) });
     }
 };
 
 const MemoryAccessInfo = packed struct(u32) {
-    scope: SyncScope,
-    ordering: AtomicOrdering,
-    alignment: Alignment,
-    _: u22 = undefined,
+    access_kind: MemoryAccessKind = .normal,
+    atomic_rmw_operation: Function.Instruction.AtomicRmw.Operation = .none,
+    sync_scope: SyncScope,
+    success_ordering: AtomicOrdering,
+    failure_ordering: AtomicOrdering = .none,
+    alignment: Alignment = .default,
+    _: u13 = undefined,
 };
 
 pub const FastMath = packed struct(u32) {
@@ -7542,7 +7684,7 @@ pub fn init(options: Options) InitError!Builder {
     if (options.name.len > 0) self.source_filename = try self.string(options.name);
     self.initializeLLVMTarget(options.target.cpu.arch);
     if (self.useLibLlvm()) self.llvm.module = llvm.Module.createWithName(
-        (self.source_filename.slice(&self) orelse "").ptr,
+        (self.source_filename.slice(&self) orelse ""),
         self.llvm.context,
     );
 
@@ -8983,6 +9125,21 @@ pub fn printUnbuffered(
                             });
                         },
                         .arg => unreachable,
+                        .atomicrmw => |tag| {
+                            const extra =
+                                function.extraData(Function.Instruction.AtomicRmw, instruction.data);
+                            try writer.print("  %{} = {s}{ } {s} {%}, {%}{ }{ }{, }\n", .{
+                                instruction_index.name(&function).fmt(self),
+                                @tagName(tag),
+                                extra.info.access_kind,
+                                @tagName(extra.info.atomic_rmw_operation),
+                                extra.ptr.fmt(function_index, self),
+                                extra.val.fmt(function_index, self),
+                                extra.info.sync_scope,
+                                extra.info.success_ordering,
+                                extra.info.alignment,
+                            });
+                        },
                         .block => {
                             block_incoming_len = instruction.data;
                             const name = instruction_index.name(&function);
@@ -9056,6 +9213,24 @@ pub fn printUnbuffered(
                             });
                             try writer.writeByte('\n');
                         },
+                        .cmpxchg,
+                        .@"cmpxchg weak",
+                        => |tag| {
+                            const extra =
+                                function.extraData(Function.Instruction.CmpXchg, instruction.data);
+                            try writer.print("  %{} = {s}{ } {%}, {%}, {%}{ }{ }{ }{, }\n", .{
+                                instruction_index.name(&function).fmt(self),
+                                @tagName(tag),
+                                extra.info.access_kind,
+                                extra.ptr.fmt(function_index, self),
+                                extra.cmp.fmt(function_index, self),
+                                extra.new.fmt(function_index, self),
+                                extra.info.sync_scope,
+                                extra.info.success_ordering,
+                                extra.info.failure_ordering,
+                                extra.info.alignment,
+                            });
+                        },
                         .extractelement => |tag| {
                             const extra = function.extraData(
                                 Function.Instruction.ExtractElement,
@@ -9084,7 +9259,11 @@ pub fn printUnbuffered(
                         },
                         .fence => |tag| {
                             const info: MemoryAccessInfo = @bitCast(instruction.data);
-                            try writer.print("  {s}{}{}", .{ @tagName(tag), info.scope, info.ordering });
+                            try writer.print("  {s}{ }{ }", .{
+                                @tagName(tag),
+                                info.sync_scope,
+                                info.success_ordering,
+                            });
                         },
                         .fneg,
                         .@"fneg fast",
@@ -9145,18 +9324,17 @@ pub fn printUnbuffered(
                         },
                         .load,
                         .@"load atomic",
-                        .@"load atomic volatile",
-                        .@"load volatile",
                         => |tag| {
                             const extra =
                                 function.extraData(Function.Instruction.Load, instruction.data);
-                            try writer.print("  %{} = {s} {%}, {%}{}{}{, }\n", .{
+                            try writer.print("  %{} = {s}{ } {%}, {%}{ }{ }{, }\n", .{
                                 instruction_index.name(&function).fmt(self),
                                 @tagName(tag),
+                                extra.info.access_kind,
                                 extra.type.fmt(self),
                                 extra.ptr.fmt(function_index, self),
-                                extra.info.scope,
-                                extra.info.ordering,
+                                extra.info.sync_scope,
+                                extra.info.success_ordering,
                                 extra.info.alignment,
                             });
                         },
@@ -9220,17 +9398,16 @@ pub fn printUnbuffered(
                         },
                         .store,
                         .@"store atomic",
-                        .@"store atomic volatile",
-                        .@"store volatile",
                         => |tag| {
                             const extra =
                                 function.extraData(Function.Instruction.Store, instruction.data);
-                            try writer.print("  {s} {%}, {%}{}{}{, }\n", .{
+                            try writer.print("  {s}{ } {%}, {%}{ }{ }{, }\n", .{
                                 @tagName(tag),
+                                extra.info.access_kind,
                                 extra.val.fmt(function_index, self),
                                 extra.ptr.fmt(function_index, self),
-                                extra.info.scope,
-                                extra.info.ordering,
+                                extra.info.sync_scope,
+                                extra.info.success_ordering,
                                 extra.info.alignment,
                             });
                         },
@@ -9254,25 +9431,6 @@ pub fn printUnbuffered(
                             );
                             try writer.writeAll("  ]\n");
                         },
-                        .unimplemented => |tag| {
-                            const ty: Type = @enumFromInt(instruction.data);
-                            if (true) {
-                                try writer.writeAll("  ");
-                                switch (ty) {
-                                    .none, .void => {},
-                                    else => try writer.print("%{} = ", .{
-                                        instruction_index.name(&function).fmt(self),
-                                    }),
-                                }
-                                try writer.print("{s} {%}\n", .{ @tagName(tag), ty.fmt(self) });
-                            } else switch (ty) {
-                                .none, .void => {},
-                                else => try writer.print("  %{} = load {%}, ptr undef\n", .{
-                                    instruction_index.name(&function).fmt(self),
-                                    ty.fmt(self),
-                                }),
-                            }
-                        },
                         .va_arg => |tag| {
                             const extra =
                                 function.extraData(Function.Instruction.VaArg, instruction.data);
src/codegen/llvm.zig
@@ -4911,8 +4911,8 @@ pub const FuncGen = struct {
 
                 .array_to_slice => try self.airArrayToSlice(inst),
                 .float_from_int   => try self.airFloatFromInt(inst),
-                .cmpxchg_weak   => try self.airCmpxchg(inst, true),
-                .cmpxchg_strong => try self.airCmpxchg(inst, false),
+                .cmpxchg_weak   => try self.airCmpxchg(inst, .weak),
+                .cmpxchg_strong => try self.airCmpxchg(inst, .strong),
                 .fence          => try self.airFence(inst),
                 .atomic_rmw     => try self.airAtomicRmw(inst),
                 .atomic_load    => try self.airAtomicLoad(inst),
@@ -8723,15 +8723,20 @@ pub const FuncGen = struct {
         return .none;
     }
 
-    fn airCmpxchg(self: *FuncGen, inst: Air.Inst.Index, is_weak: bool) !Builder.Value {
+    fn airCmpxchg(
+        self: *FuncGen,
+        inst: Air.Inst.Index,
+        kind: Builder.Function.Instruction.CmpXchg.Kind,
+    ) !Builder.Value {
         const o = self.dg.object;
         const mod = o.module;
         const ty_pl = self.air.instructions.items(.data)[inst].ty_pl;
         const extra = self.air.extraData(Air.Cmpxchg, ty_pl.payload).data;
         const ptr = try self.resolveInst(extra.ptr);
+        const ptr_ty = self.typeOf(extra.ptr);
         var expected_value = try self.resolveInst(extra.expected_value);
         var new_value = try self.resolveInst(extra.new_value);
-        const operand_ty = self.typeOf(extra.ptr).childType(mod);
+        const operand_ty = ptr_ty.childType(mod);
         const llvm_operand_ty = try o.lowerType(operand_ty);
         const llvm_abi_ty = try o.getAtomicAbiType(operand_ty, false);
         if (llvm_abi_ty != .none) {
@@ -8742,22 +8747,18 @@ pub const FuncGen = struct {
             new_value = try self.wip.conv(signedness, new_value, llvm_abi_ty, "");
         }
 
-        const llvm_result_ty = try o.builder.structType(.normal, &.{
-            if (llvm_abi_ty != .none) llvm_abi_ty else llvm_operand_ty,
-            .i1,
-        });
-        const result = (try self.wip.unimplemented(llvm_result_ty, "")).finish(
-            self.builder.buildAtomicCmpXchg(
-                ptr.toLlvm(&self.wip),
-                expected_value.toLlvm(&self.wip),
-                new_value.toLlvm(&self.wip),
-                @enumFromInt(@intFromEnum(toLlvmAtomicOrdering(extra.successOrder()))),
-                @enumFromInt(@intFromEnum(toLlvmAtomicOrdering(extra.failureOrder()))),
-                llvm.Bool.fromBool(self.sync_scope == .singlethread),
-            ),
-            &self.wip,
+        const result = try self.wip.cmpxchg(
+            kind,
+            if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal,
+            ptr,
+            expected_value,
+            new_value,
+            self.sync_scope,
+            toLlvmAtomicOrdering(extra.successOrder()),
+            toLlvmAtomicOrdering(extra.failureOrder()),
+            Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)),
+            "",
         );
-        result.toLlvm(&self.wip).setWeak(llvm.Bool.fromBool(is_weak));
 
         const optional_ty = self.typeOfIndex(inst);
 
@@ -8789,63 +8790,54 @@ pub const FuncGen = struct {
         const is_float = operand_ty.isRuntimeFloat();
         const op = toLlvmAtomicRmwBinOp(extra.op(), is_signed_int, is_float);
         const ordering = toLlvmAtomicOrdering(extra.ordering());
-        const single_threaded = llvm.Bool.fromBool(self.sync_scope == .singlethread);
-        const llvm_abi_ty = try o.getAtomicAbiType(operand_ty, op == .Xchg);
+        const llvm_abi_ty = try o.getAtomicAbiType(operand_ty, op == .xchg);
         const llvm_operand_ty = try o.lowerType(operand_ty);
+
+        const access_kind: Builder.MemoryAccessKind =
+            if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;
+        const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
+
         if (llvm_abi_ty != .none) {
             // operand needs widening and truncating or bitcasting.
-            const casted_operand = try self.wip.cast(
-                if (is_float) .bitcast else if (is_signed_int) .sext else .zext,
-                @enumFromInt(@intFromEnum(operand)),
-                llvm_abi_ty,
-                "",
-            );
-
-            const uncasted_result = (try self.wip.unimplemented(llvm_abi_ty, "")).finish(
-                self.builder.buildAtomicRmw(
-                    op,
-                    ptr.toLlvm(&self.wip),
-                    casted_operand.toLlvm(&self.wip),
-                    @enumFromInt(@intFromEnum(ordering)),
-                    single_threaded,
+            return self.wip.cast(if (is_float) .bitcast else .trunc, try self.wip.atomicrmw(
+                access_kind,
+                op,
+                ptr,
+                try self.wip.cast(
+                    if (is_float) .bitcast else if (is_signed_int) .sext else .zext,
+                    operand,
+                    llvm_abi_ty,
+                    "",
                 ),
-                &self.wip,
-            );
-
-            if (is_float) {
-                return self.wip.cast(.bitcast, uncasted_result, llvm_operand_ty, "");
-            } else {
-                return self.wip.cast(.trunc, uncasted_result, llvm_operand_ty, "");
-            }
+                self.sync_scope,
+                ordering,
+                ptr_alignment,
+                "",
+            ), llvm_operand_ty, "");
         }
 
-        if (!llvm_operand_ty.isPointer(&o.builder)) {
-            return (try self.wip.unimplemented(llvm_operand_ty, "")).finish(
-                self.builder.buildAtomicRmw(
-                    op,
-                    ptr.toLlvm(&self.wip),
-                    operand.toLlvm(&self.wip),
-                    @enumFromInt(@intFromEnum(ordering)),
-                    single_threaded,
-                ),
-                &self.wip,
-            );
-        }
+        if (!llvm_operand_ty.isPointer(&o.builder)) return self.wip.atomicrmw(
+            access_kind,
+            op,
+            ptr,
+            operand,
+            self.sync_scope,
+            ordering,
+            ptr_alignment,
+            "",
+        );
 
         // It's a pointer but we need to treat it as an int.
-        const llvm_usize = try o.lowerType(Type.usize);
-        const casted_operand = try self.wip.cast(.ptrtoint, operand, llvm_usize, "");
-        const uncasted_result = (try self.wip.unimplemented(llvm_usize, "")).finish(
-            self.builder.buildAtomicRmw(
-                op,
-                ptr.toLlvm(&self.wip),
-                casted_operand.toLlvm(&self.wip),
-                @enumFromInt(@intFromEnum(ordering)),
-                single_threaded,
-            ),
-            &self.wip,
-        );
-        return self.wip.cast(.inttoptr, uncasted_result, llvm_operand_ty, "");
+        return self.wip.cast(.inttoptr, try self.wip.atomicrmw(
+            access_kind,
+            op,
+            ptr,
+            try self.wip.cast(.ptrtoint, operand, try o.lowerType(Type.usize), ""),
+            self.sync_scope,
+            ordering,
+            ptr_alignment,
+            "",
+        ), llvm_operand_ty, "");
     }
 
     fn airAtomicLoad(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
@@ -10581,17 +10573,17 @@ fn toLlvmAtomicRmwBinOp(
     op: std.builtin.AtomicRmwOp,
     is_signed: bool,
     is_float: bool,
-) llvm.AtomicRMWBinOp {
+) Builder.Function.Instruction.AtomicRmw.Operation {
     return switch (op) {
-        .Xchg => .Xchg,
-        .Add => if (is_float) .FAdd else return .Add,
-        .Sub => if (is_float) .FSub else return .Sub,
-        .And => .And,
-        .Nand => .Nand,
-        .Or => .Or,
-        .Xor => .Xor,
-        .Max => if (is_float) .FMax else if (is_signed) .Max else return .UMax,
-        .Min => if (is_float) .FMin else if (is_signed) .Min else return .UMin,
+        .Xchg => .xchg,
+        .Add => if (is_float) .fadd else return .add,
+        .Sub => if (is_float) .fsub else return .sub,
+        .And => .@"and",
+        .Nand => .nand,
+        .Or => .@"or",
+        .Xor => .xor,
+        .Max => if (is_float) .fmax else if (is_signed) .max else return .umax,
+        .Min => if (is_float) .fmin else if (is_signed) .min else return .umin,
     };
 }
 
src/zig_llvm.cpp
@@ -1123,11 +1123,11 @@ void ZigLLVMTakeName(LLVMValueRef new_owner, LLVMValueRef victim) {
 }
 
 ZigLLVMDIGlobalVariable* ZigLLVMGlobalGetVariable(ZigLLVMDIGlobalVariableExpression *global_variable_expression) {
-	return reinterpret_cast<ZigLLVMDIGlobalVariable*>(reinterpret_cast<DIGlobalVariableExpression*>(global_variable_expression)->getVariable());
+    return reinterpret_cast<ZigLLVMDIGlobalVariable*>(reinterpret_cast<DIGlobalVariableExpression*>(global_variable_expression)->getVariable());
 }
 
 void ZigLLVMAttachMetaData(LLVMValueRef Val, ZigLLVMDIGlobalVariableExpression *global_variable_expression) {
-	unwrap<GlobalVariable>(Val)->addDebugInfo(reinterpret_cast<DIGlobalVariableExpression*>(global_variable_expression));
+    unwrap<GlobalVariable>(Val)->addDebugInfo(reinterpret_cast<DIGlobalVariableExpression*>(global_variable_expression));
 }
 
 static_assert((Triple::ArchType)ZigLLVM_UnknownArch == Triple::UnknownArch, "");