Commit 49cc1bff08

Jacob Young <jacobly0@users.noreply.github.com>
2023-08-07 13:45:36
llvm: finish converting intrinsics
1 parent 6577f52
src/codegen/llvm/bindings.zig
@@ -951,27 +951,6 @@ pub const Builder = opaque {
         Name: [*:0]const u8,
     ) *Value;
 
-    pub const buildMemSet = ZigLLVMBuildMemSet;
-    extern fn ZigLLVMBuildMemSet(
-        B: *Builder,
-        Ptr: *Value,
-        Val: *Value,
-        Len: *Value,
-        Align: c_uint,
-        is_volatile: bool,
-    ) *Value;
-
-    pub const buildMemCpy = ZigLLVMBuildMemCpy;
-    extern fn ZigLLVMBuildMemCpy(
-        B: *Builder,
-        Dst: *Value,
-        DstAlign: c_uint,
-        Src: *Value,
-        SrcAlign: c_uint,
-        Size: *Value,
-        is_volatile: bool,
-    ) *Value;
-
     pub const buildExactUDiv = LLVMBuildExactUDiv;
     extern fn LLVMBuildExactUDiv(*Builder, LHS: *Value, RHS: *Value, Name: [*:0]const u8) *Value;
 
src/codegen/llvm/Builder.zig
@@ -2397,7 +2397,7 @@ pub const Intrinsic = enum {
     @"udiv.fix.sat",
 
     // Specialised Arithmetic
-    canonicalisze,
+    canonicalize,
     fmuladd,
 
     // Vector Reduction
@@ -2416,14 +2416,15 @@ pub const Intrinsic = enum {
     @"vector.reduce.fmin",
     @"vector.reduce.fmaximum",
     @"vector.reduce.fminimum",
-    @"vector.reduce.insert",
-    @"vector.reduce.extract",
     @"vector.insert",
     @"vector.extract",
 
+    // Floating-Point Test
+    @"is.fpclass",
+
     // General
-    @"llvm.var.annotation",
-    @"llvm.ptr.annotation",
+    @"var.annotation",
+    @"ptr.annotation",
     annotation,
     @"codeview.annotation",
     trap,
@@ -2442,7 +2443,7 @@ pub const Intrinsic = enum {
     @"arithmetic.fence",
     donothing,
     @"load.relative",
-    @"llvm.sideeffect",
+    sideeffect,
     @"is.constant",
     ptrmask,
     @"threadlocal.address",
@@ -2483,10 +2484,7 @@ pub const Intrinsic = enum {
         };
     };
 
-    const signatures = std.enums.EnumArray(Intrinsic, Signature).initDefault(.{
-        .ret_len = 0,
-        .params = &.{},
-    }, .{
+    const signatures = std.enums.EnumArray(Intrinsic, Signature).init(.{
         .va_start = .{
             .ret_len = 0,
             .params = &.{
@@ -2603,6 +2601,56 @@ pub const Intrinsic = enum {
             },
             .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
         },
+        .memcpy = .{
+            .ret_len = 0,
+            .params = &.{
+                .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .writeonly } },
+                .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .readonly } },
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },
+        },
+        .@"memcpy.inline" = .{
+            .ret_len = 0,
+            .params = &.{
+                .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .writeonly } },
+                .{ .kind = .overloaded, .attrs = &.{ .@"noalias", .nocapture, .readonly } },
+                .{ .kind = .overloaded, .attrs = &.{.immarg} },
+                .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },
+        },
+        .memmove = .{
+            .ret_len = 0,
+            .params = &.{
+                .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },
+                .{ .kind = .overloaded, .attrs = &.{ .nocapture, .readonly } },
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .readwrite } } },
+        },
+        .memset = .{
+            .ret_len = 0,
+            .params = &.{
+                .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },
+                .{ .kind = .{ .type = .i8 } },
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .write } } },
+        },
+        .@"memset.inline" = .{
+            .ret_len = 0,
+            .params = &.{
+                .{ .kind = .overloaded, .attrs = &.{ .nocapture, .writeonly } },
+                .{ .kind = .{ .type = .i8 } },
+                .{ .kind = .overloaded, .attrs = &.{.immarg} },
+                .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nounwind, .willreturn, .{ .memory = .{ .argmem = .write } } },
+        },
         .sqrt = .{
             .ret_len = 1,
             .params = &.{
@@ -2884,7 +2932,7 @@ pub const Intrinsic = enum {
             .params = &.{
                 .{ .kind = .overloaded },
                 .{ .kind = .{ .matches = 0 } },
-                .{ .kind = .{ .type = .i1 } },
+                .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
             },
             .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
         },
@@ -2893,7 +2941,7 @@ pub const Intrinsic = enum {
             .params = &.{
                 .{ .kind = .overloaded },
                 .{ .kind = .{ .matches = 0 } },
-                .{ .kind = .{ .type = .i1 } },
+                .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
             },
             .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
         },
@@ -3115,6 +3163,25 @@ pub const Intrinsic = enum {
             .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
         },
 
+        .canonicalize = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .matches = 0 } },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+        .fmuladd = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .matches = 0 } },
+                .{ .kind = .{ .matches = 0 } },
+                .{ .kind = .{ .matches = 0 } },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+
         .@"vector.reduce.add" = .{
             .ret_len = 1,
             .params = &.{
@@ -3257,6 +3324,57 @@ pub const Intrinsic = enum {
             .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
         },
 
+        .@"is.fpclass" = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .{ .matches_changed_scalar = .{ .index = 1, .scalar = .i1 } } },
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .type = .i32 }, .attrs = &.{.immarg} },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+
+        .@"var.annotation" = .{
+            .ret_len = 0,
+            .params = &.{
+                .{ .kind = .overloaded },
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .matches = 1 } },
+                .{ .kind = .{ .type = .i32 } },
+                .{ .kind = .{ .matches = 1 } },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
+        },
+        .@"ptr.annotation" = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .matches = 0 } },
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .matches = 2 } },
+                .{ .kind = .{ .type = .i32 } },
+                .{ .kind = .{ .matches = 2 } },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
+        },
+        .annotation = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .matches = 0 } },
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .matches = 2 } },
+                .{ .kind = .{ .type = .i32 } },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
+        },
+        .@"codeview.annotation" = .{
+            .ret_len = 0,
+            .params = &.{
+                .{ .kind = .{ .type = .metadata } },
+            },
+            .attrs = &.{ .nocallback, .noduplicate, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
+        },
         .trap = .{
             .ret_len = 0,
             .params = &.{},
@@ -3274,6 +3392,156 @@ pub const Intrinsic = enum {
             },
             .attrs = &.{ .cold, .noreturn, .nounwind },
         },
+        .stackprotector = .{
+            .ret_len = 0,
+            .params = &.{
+                .{ .kind = .{ .type = .ptr } },
+                .{ .kind = .{ .type = .ptr } },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
+        },
+        .stackguard = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .{ .type = .ptr } },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn },
+        },
+        .objectsize = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .overloaded },
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+                .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+                .{ .kind = .{ .type = .i1 }, .attrs = &.{.immarg} },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+        .expect = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .matches = 0 } },
+                .{ .kind = .{ .matches = 0 } },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+        .@"expect.with.probability" = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .matches = 0 } },
+                .{ .kind = .{ .matches = 0 } },
+                .{ .kind = .{ .type = .double }, .attrs = &.{.immarg} },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+        .assume = .{
+            .ret_len = 0,
+            .params = &.{
+                .{ .kind = .{ .type = .i1 }, .attrs = &.{.noundef} },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .write } } },
+        },
+        .@"ssa.copy" = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .matches = 0 }, .attrs = &.{.returned} },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+        .@"type.test" = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .{ .type = .i1 } },
+                .{ .kind = .{ .type = .ptr } },
+                .{ .kind = .{ .type = .metadata } },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+        .@"type.checked.load" = .{
+            .ret_len = 2,
+            .params = &.{
+                .{ .kind = .{ .type = .ptr } },
+                .{ .kind = .{ .type = .i1 } },
+                .{ .kind = .{ .type = .ptr } },
+                .{ .kind = .{ .type = .i32 } },
+                .{ .kind = .{ .type = .metadata } },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+        .@"type.checked.load.relative" = .{
+            .ret_len = 2,
+            .params = &.{
+                .{ .kind = .{ .type = .ptr } },
+                .{ .kind = .{ .type = .i1 } },
+                .{ .kind = .{ .type = .ptr } },
+                .{ .kind = .{ .type = .i32 } },
+                .{ .kind = .{ .type = .metadata } },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+        .@"arithmetic.fence" = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .matches = 0 } },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+        .donothing = .{
+            .ret_len = 0,
+            .params = &.{},
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+        .@"load.relative" = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .{ .type = .ptr } },
+                .{ .kind = .{ .type = .ptr } },
+                .{ .kind = .overloaded },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .argmem = .read } } },
+        },
+        .sideeffect = .{
+            .ret_len = 0,
+            .params = &.{},
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = .{ .inaccessiblemem = .readwrite } } },
+        },
+        .@"is.constant" = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .{ .type = .i1 } },
+                .{ .kind = .overloaded },
+            },
+            .attrs = &.{ .convergent, .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+        .ptrmask = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .overloaded },
+                .{ .kind = .{ .matches = 0 } },
+                .{ .kind = .overloaded },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+        .@"threadlocal.address" = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .overloaded, .attrs = &.{.nonnull} },
+                .{ .kind = .{ .matches = 0 }, .attrs = &.{.nonnull} },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .speculatable, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
+        .vscale = .{
+            .ret_len = 1,
+            .params = &.{
+                .{ .kind = .overloaded },
+            },
+            .attrs = &.{ .nocallback, .nofree, .nosync, .nounwind, .willreturn, .{ .memory = Attribute.Memory.all(.none) } },
+        },
 
         .@"amdgcn.workitem.id.x" = .{
             .ret_len = 1,
@@ -5391,6 +5659,7 @@ pub const WipFunction = struct {
 
     pub fn callIntrinsic(
         self: *WipFunction,
+        function_attributes: FunctionAttributes,
         id: Intrinsic,
         overload: []const Type,
         args: []const Value,
@@ -5400,7 +5669,7 @@ pub const WipFunction = struct {
         return self.call(
             .normal,
             CallConv.default,
-            .none,
+            function_attributes,
             intrinsic.typeOf(self.builder),
             intrinsic.toValue(self.builder),
             args,
@@ -5408,6 +5677,57 @@ pub const WipFunction = struct {
         );
     }
 
+    pub fn callMemCpy(
+        self: *WipFunction,
+        dst: Value,
+        dst_align: Alignment,
+        src: Value,
+        src_align: Alignment,
+        len: Value,
+        kind: MemoryAccessKind,
+    ) Allocator.Error!Instruction.Index {
+        var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
+        var src_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = src_align })};
+        const value = try self.callIntrinsic(
+            try self.builder.fnAttrs(&.{
+                .none,
+                .none,
+                try self.builder.attrs(&dst_attrs),
+                try self.builder.attrs(&src_attrs),
+            }),
+            .memcpy,
+            &.{ dst.typeOfWip(self), src.typeOfWip(self), len.typeOfWip(self) },
+            &.{ dst, src, len, switch (kind) {
+                .normal => Value.false,
+                .@"volatile" => Value.true,
+            } },
+            undefined,
+        );
+        return value.unwrap().instruction;
+    }
+
+    pub fn callMemSet(
+        self: *WipFunction,
+        dst: Value,
+        dst_align: Alignment,
+        val: Value,
+        len: Value,
+        kind: MemoryAccessKind,
+    ) Allocator.Error!Instruction.Index {
+        var dst_attrs = [_]Attribute.Index{try self.builder.attr(.{ .@"align" = dst_align })};
+        const value = try self.callIntrinsic(
+            try self.builder.fnAttrs(&.{ .none, .none, try self.builder.attrs(&dst_attrs) }),
+            .memset,
+            &.{ dst.typeOfWip(self), len.typeOfWip(self) },
+            &.{ dst, val, len, switch (kind) {
+                .normal => Value.false,
+                .@"volatile" => Value.true,
+            } },
+            undefined,
+        );
+        return value.unwrap().instruction;
+    }
+
     pub fn vaArg(self: *WipFunction, list: Value, ty: Type, name: []const u8) Allocator.Error!Value {
         try self.ensureUnusedExtraCapacity(1, Instruction.VaArg, 0);
         const instruction = try self.addInst(name, .{
src/codegen/llvm.zig
@@ -5466,7 +5466,7 @@ pub const FuncGen = struct {
         const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod));
         const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
 
-        _ = try self.wip.callIntrinsic(.va_copy, &.{}, &.{ dest_list, src_list }, "");
+        _ = try self.wip.callIntrinsic(.none, .va_copy, &.{}, &.{ dest_list, src_list }, "");
         return if (isByRef(va_list_ty, mod))
             dest_list
         else
@@ -5477,7 +5477,7 @@ pub const FuncGen = struct {
         const un_op = self.air.instructions.items(.data)[inst].un_op;
         const src_list = try self.resolveInst(un_op);
 
-        _ = try self.wip.callIntrinsic(.va_end, &.{}, &.{src_list}, "");
+        _ = try self.wip.callIntrinsic(.none, .va_end, &.{}, &.{src_list}, "");
         return .none;
     }
 
@@ -5490,7 +5490,7 @@ pub const FuncGen = struct {
         const result_alignment = Builder.Alignment.fromByteUnits(va_list_ty.abiAlignment(mod));
         const dest_list = try self.buildAlloca(llvm_va_list_ty, result_alignment);
 
-        _ = try self.wip.callIntrinsic(.va_start, &.{}, &.{dest_list}, "");
+        _ = try self.wip.callIntrinsic(.none, .va_start, &.{}, &.{dest_list}, "");
         return if (isByRef(va_list_ty, mod))
             dest_list
         else
@@ -5600,8 +5600,8 @@ pub const FuncGen = struct {
                 const both_pl_block_end = self.wip.cursor.block;
 
                 self.wip.cursor = .{ .block = end_block };
-                const llvm_i1_0 = try o.builder.intValue(.i1, 0);
-                const llvm_i1_1 = try o.builder.intValue(.i1, 1);
+                const llvm_i1_0 = Builder.Value.false;
+                const llvm_i1_1 = Builder.Value.true;
                 const incoming_values: [3]Builder.Value = .{
                     switch (op) {
                         .eq => llvm_i1_1,
@@ -5822,7 +5822,7 @@ pub const FuncGen = struct {
                 if (can_elide_load)
                     return payload_ptr;
 
-                return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
+                return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal);
             }
             const load_ty = err_union_llvm_ty.structFields(&o.builder)[offset];
             return fg.wip.load(.normal, load_ty, payload_ptr, payload_alignment, "");
@@ -6121,7 +6121,7 @@ pub const FuncGen = struct {
                 return ptr;
 
             const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
-            return self.loadByRef(ptr, elem_ty, elem_alignment, false);
+            return self.loadByRef(ptr, elem_ty, elem_alignment, .normal);
         }
 
         return self.load(ptr, slice_ty);
@@ -6161,7 +6161,7 @@ pub const FuncGen = struct {
                     try self.wip.gep(.inbounds, array_llvm_ty, array_llvm_val, &indices, "");
                 if (canElideLoad(self, body_tail)) return elem_ptr;
                 const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
-                return self.loadByRef(elem_ptr, elem_ty, elem_alignment, false);
+                return self.loadByRef(elem_ptr, elem_ty, elem_alignment, .normal);
             } else {
                 const elem_llvm_ty = try o.lowerType(elem_ty);
                 if (Air.refToIndex(bin_op.lhs)) |lhs_index| {
@@ -6221,7 +6221,7 @@ pub const FuncGen = struct {
         if (isByRef(elem_ty, mod)) {
             if (self.canElideLoad(body_tail)) return ptr;
             const elem_alignment = Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod));
-            return self.loadByRef(ptr, elem_ty, elem_alignment, false);
+            return self.loadByRef(ptr, elem_ty, elem_alignment, .normal);
         }
 
         return self.load(ptr, ptr_ty);
@@ -6351,7 +6351,7 @@ pub const FuncGen = struct {
 
                     assert(llvm_field.alignment != 0);
                     const field_alignment = Builder.Alignment.fromByteUnits(llvm_field.alignment);
-                    return self.loadByRef(field_ptr, field_ty, field_alignment, false);
+                    return self.loadByRef(field_ptr, field_ty, field_alignment, .normal);
                 } else {
                     return self.load(field_ptr, field_ptr_ty);
                 }
@@ -6366,7 +6366,7 @@ pub const FuncGen = struct {
                 const payload_alignment = Builder.Alignment.fromByteUnits(layout.payload_align);
                 if (isByRef(field_ty, mod)) {
                     if (canElideLoad(self, body_tail)) return field_ptr;
-                    return self.loadByRef(field_ptr, field_ty, payload_alignment, false);
+                    return self.loadByRef(field_ptr, field_ty, payload_alignment, .normal);
                 } else {
                     return self.wip.load(.normal, llvm_field_ty, field_ptr, payload_alignment, "");
                 }
@@ -7150,7 +7150,7 @@ pub const FuncGen = struct {
             const payload_ptr = try self.wip.gepStruct(err_union_llvm_ty, operand, offset, "");
             if (isByRef(payload_ty, mod)) {
                 if (self.canElideLoad(body_tail)) return payload_ptr;
-                return self.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
+                return self.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal);
             }
             const payload_llvm_ty = err_union_llvm_ty.structFields(&o.builder)[offset];
             return self.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, "");
@@ -7346,7 +7346,7 @@ pub const FuncGen = struct {
         const o = self.dg.object;
         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
         const index = pl_op.payload;
-        return self.wip.callIntrinsic(.@"wasm.memory.size", &.{.i32}, &.{
+        return self.wip.callIntrinsic(.none, .@"wasm.memory.size", &.{.i32}, &.{
             try o.builder.intValue(.i32, index),
         }, "");
     }
@@ -7355,7 +7355,7 @@ pub const FuncGen = struct {
         const o = self.dg.object;
         const pl_op = self.air.instructions.items(.data)[inst].pl_op;
         const index = pl_op.payload;
-        return self.wip.callIntrinsic(.@"wasm.memory.grow", &.{.i32}, &.{
+        return self.wip.callIntrinsic(.none, .@"wasm.memory.grow", &.{.i32}, &.{
             try o.builder.intValue(.i32, index), try self.resolveInst(pl_op.operand),
         }, "");
     }
@@ -7371,13 +7371,11 @@ pub const FuncGen = struct {
         const index = try self.resolveInst(extra.lhs);
         const operand = try self.resolveInst(extra.rhs);
 
-        const kind: Builder.MemoryAccessKind = switch (vector_ptr_ty.isVolatilePtr(mod)) {
-            false => .normal,
-            true => .@"volatile",
-        };
+        const access_kind: Builder.MemoryAccessKind =
+            if (vector_ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;
         const elem_llvm_ty = try o.lowerType(vector_ptr_ty.childType(mod));
         const alignment = Builder.Alignment.fromByteUnits(vector_ptr_ty.ptrAlignment(mod));
-        const loaded = try self.wip.load(kind, elem_llvm_ty, vector_ptr, alignment, "");
+        const loaded = try self.wip.load(access_kind, elem_llvm_ty, vector_ptr, alignment, "");
 
         const new_vector = try self.wip.insertElement(loaded, operand, index, "");
         _ = try self.store(vector_ptr, vector_ptr_ty, new_vector, .none);
@@ -7395,6 +7393,7 @@ pub const FuncGen = struct {
 
         if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmin, inst_ty, 2, .{ lhs, rhs });
         return self.wip.callIntrinsic(
+            .none,
             if (scalar_ty.isSignedInt(mod)) .smin else .umin,
             &.{try o.lowerType(inst_ty)},
             &.{ lhs, rhs },
@@ -7413,6 +7412,7 @@ pub const FuncGen = struct {
 
         if (scalar_ty.isAnyFloat()) return self.buildFloatOp(.fmax, inst_ty, 2, .{ lhs, rhs });
         return self.wip.callIntrinsic(
+            .none,
             if (scalar_ty.isSignedInt(mod)) .smax else .umax,
             &.{try o.lowerType(inst_ty)},
             &.{ lhs, rhs },
@@ -7462,12 +7462,19 @@ pub const FuncGen = struct {
 
         const intrinsic = if (scalar_ty.isSignedInt(mod)) signed_intrinsic else unsigned_intrinsic;
         const llvm_inst_ty = try o.lowerType(inst_ty);
-        const results = try fg.wip.callIntrinsic(intrinsic, &.{llvm_inst_ty}, &.{ lhs, rhs }, "");
+        const results =
+            try fg.wip.callIntrinsic(.none, intrinsic, &.{llvm_inst_ty}, &.{ lhs, rhs }, "");
 
         const overflow_bits = try fg.wip.extractValue(results, &.{1}, "");
         const overflow_bits_ty = overflow_bits.typeOfWip(&fg.wip);
         const overflow_bit = if (overflow_bits_ty.isVector(&o.builder))
-            try fg.wip.callIntrinsic(.@"vector.reduce.or", &.{overflow_bits_ty}, &.{overflow_bits}, "")
+            try fg.wip.callIntrinsic(
+                .none,
+                .@"vector.reduce.or",
+                &.{overflow_bits_ty},
+                &.{overflow_bits},
+                "",
+            )
         else
             overflow_bits;
 
@@ -7501,6 +7508,7 @@ pub const FuncGen = struct {
 
         if (scalar_ty.isAnyFloat()) return self.todo("saturating float add", .{});
         return self.wip.callIntrinsic(
+            .none,
             if (scalar_ty.isSignedInt(mod)) .@"sadd.sat" else .@"uadd.sat",
             &.{try o.lowerType(inst_ty)},
             &.{ lhs, rhs },
@@ -7542,6 +7550,7 @@ pub const FuncGen = struct {
 
         if (scalar_ty.isAnyFloat()) return self.todo("saturating float sub", .{});
         return self.wip.callIntrinsic(
+            .none,
             if (scalar_ty.isSignedInt(mod)) .@"ssub.sat" else .@"usub.sat",
             &.{try o.lowerType(inst_ty)},
             &.{ lhs, rhs },
@@ -7583,6 +7592,7 @@ pub const FuncGen = struct {
 
         if (scalar_ty.isAnyFloat()) return self.todo("saturating float mul", .{});
         return self.wip.callIntrinsic(
+            .none,
             if (scalar_ty.isSignedInt(mod)) .@"smul.fix.sat" else .@"umul.fix.sat",
             &.{try o.lowerType(inst_ty)},
             &.{ lhs, rhs, try o.builder.intValue(.i32, 0) },
@@ -7793,7 +7803,8 @@ pub const FuncGen = struct {
         const intrinsic = if (scalar_ty.isSignedInt(mod)) signed_intrinsic else unsigned_intrinsic;
         const llvm_inst_ty = try o.lowerType(inst_ty);
         const llvm_lhs_ty = try o.lowerType(lhs_ty);
-        const results = try self.wip.callIntrinsic(intrinsic, &.{llvm_lhs_ty}, &.{ lhs, rhs }, "");
+        const results =
+            try self.wip.callIntrinsic(.none, intrinsic, &.{llvm_lhs_ty}, &.{ lhs, rhs }, "");
 
         const result_val = try self.wip.extractValue(results, &.{0}, "");
         const overflow_bit = try self.wip.extractValue(results, &.{1}, "");
@@ -7998,27 +8009,49 @@ pub const FuncGen = struct {
         if (op != .tan and intrinsicsAllowed(scalar_ty, target)) switch (op) {
             // Some operations are dedicated LLVM instructions, not available as intrinsics
             .neg => return self.wip.un(.fneg, params[0], ""),
-            .add => return self.wip.bin(.fadd, params[0], params[1], ""),
-            .sub => return self.wip.bin(.fsub, params[0], params[1], ""),
-            .mul => return self.wip.bin(.fmul, params[0], params[1], ""),
-            .div => return self.wip.bin(.fdiv, params[0], params[1], ""),
-            .fmod => return self.wip.bin(.frem, params[0], params[1], ""),
-            .fmax => return self.wip.callIntrinsic(.maxnum, &.{llvm_ty}, &params, ""),
-            .fmin => return self.wip.callIntrinsic(.minnum, &.{llvm_ty}, &params, ""),
-            .ceil => return self.wip.callIntrinsic(.ceil, &.{llvm_ty}, &params, ""),
-            .cos => return self.wip.callIntrinsic(.cos, &.{llvm_ty}, &params, ""),
-            .exp => return self.wip.callIntrinsic(.exp, &.{llvm_ty}, &params, ""),
-            .exp2 => return self.wip.callIntrinsic(.exp2, &.{llvm_ty}, &params, ""),
-            .fabs => return self.wip.callIntrinsic(.fabs, &.{llvm_ty}, &params, ""),
-            .floor => return self.wip.callIntrinsic(.floor, &.{llvm_ty}, &params, ""),
-            .log => return self.wip.callIntrinsic(.log, &.{llvm_ty}, &params, ""),
-            .log10 => return self.wip.callIntrinsic(.log10, &.{llvm_ty}, &params, ""),
-            .log2 => return self.wip.callIntrinsic(.log2, &.{llvm_ty}, &params, ""),
-            .round => return self.wip.callIntrinsic(.round, &.{llvm_ty}, &params, ""),
-            .sin => return self.wip.callIntrinsic(.sin, &.{llvm_ty}, &params, ""),
-            .sqrt => return self.wip.callIntrinsic(.sqrt, &.{llvm_ty}, &params, ""),
-            .trunc => return self.wip.callIntrinsic(.trunc, &.{llvm_ty}, &params, ""),
-            .fma => return self.wip.callIntrinsic(.fma, &.{llvm_ty}, &params, ""),
+            .add, .sub, .mul, .div, .fmod => return self.wip.bin(switch (op) {
+                .add => .fadd,
+                .sub => .fsub,
+                .mul => .fmul,
+                .div => .fdiv,
+                .fmod => .frem,
+                else => unreachable,
+            }, params[0], params[1], ""),
+            .fmax,
+            .fmin,
+            .ceil,
+            .cos,
+            .exp,
+            .exp2,
+            .fabs,
+            .floor,
+            .log,
+            .log10,
+            .log2,
+            .round,
+            .sin,
+            .sqrt,
+            .trunc,
+            .fma,
+            => return self.wip.callIntrinsic(.none, switch (op) {
+                .fmax => .maxnum,
+                .fmin => .minnum,
+                .ceil => .ceil,
+                .cos => .cos,
+                .exp => .exp,
+                .exp2 => .exp2,
+                .fabs => .fabs,
+                .floor => .floor,
+                .log => .log,
+                .log10 => .log10,
+                .log2 => .log2,
+                .round => .round,
+                .sin => .sin,
+                .sqrt => .sqrt,
+                .trunc => .trunc,
+                .fma => .fma,
+                else => unreachable,
+            }, &.{llvm_ty}, &params, ""),
             .tan => unreachable,
         };
 
@@ -8215,6 +8248,7 @@ pub const FuncGen = struct {
         const llvm_lhs_ty = try o.lowerType(lhs_ty);
         const llvm_lhs_scalar_ty = llvm_lhs_ty.scalarType(&o.builder);
         const result = try self.wip.callIntrinsic(
+            .none,
             if (lhs_scalar_ty.isSignedInt(mod)) .@"sshl.sat" else .@"ushl.sat",
             &.{llvm_lhs_ty},
             &.{ lhs, casted_rhs },
@@ -8588,21 +8622,14 @@ pub const FuncGen = struct {
             // Even if safety is disabled, we still emit a memset to undefined since it conveys
             // extra information to LLVM. However, safety makes the difference between using
             // 0xaa or actual undefined for the fill byte.
-            const fill_byte = if (safety)
-                try o.builder.intConst(.i8, 0xaa)
-            else
-                try o.builder.undefConst(.i8);
-            const operand_size = operand_ty.abiSize(mod);
-            const usize_ty = try o.lowerType(Type.usize);
-            const len = try o.builder.intValue(usize_ty, operand_size);
-            const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
-            _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
-                dest_ptr.toLlvm(&self.wip),
-                fill_byte.toLlvm(&o.builder),
-                len.toLlvm(&self.wip),
-                @intCast(dest_ptr_align.toByteUnits() orelse 0),
-                ptr_ty.isVolatilePtr(mod),
-            ), &self.wip);
+            const len = try o.builder.intValue(try o.lowerType(Type.usize), operand_ty.abiSize(mod));
+            _ = try self.wip.callMemSet(
+                dest_ptr,
+                Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod)),
+                if (safety) try o.builder.intValue(.i8, 0xaa) else try o.builder.undefValue(.i8),
+                len,
+                if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal,
+            );
             if (safety and mod.comp.bin_file.options.valgrind) {
                 try self.valgrindMarkUndef(dest_ptr, len);
             }
@@ -8655,14 +8682,14 @@ pub const FuncGen = struct {
 
     fn airTrap(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
         _ = inst;
-        _ = try self.wip.callIntrinsic(.trap, &.{}, &.{}, "");
+        _ = try self.wip.callIntrinsic(.none, .trap, &.{}, &.{}, "");
         _ = try self.wip.@"unreachable"();
         return .none;
     }
 
     fn airBreakpoint(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
         _ = inst;
-        _ = try self.wip.callIntrinsic(.debugtrap, &.{}, &.{}, "");
+        _ = try self.wip.callIntrinsic(.none, .debugtrap, &.{}, &.{}, "");
         return .none;
     }
 
@@ -8674,7 +8701,7 @@ pub const FuncGen = struct {
             // https://github.com/ziglang/zig/issues/11946
             return o.builder.intValue(llvm_usize, 0);
         }
-        const result = try self.wip.callIntrinsic(.returnaddress, &.{}, &.{
+        const result = try self.wip.callIntrinsic(.none, .returnaddress, &.{}, &.{
             try o.builder.intValue(.i32, 0),
         }, "");
         return self.wip.cast(.ptrtoint, result, llvm_usize, "");
@@ -8683,7 +8710,7 @@ pub const FuncGen = struct {
     fn airFrameAddress(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
         _ = inst;
         const o = self.dg.object;
-        const result = try self.wip.callIntrinsic(.frameaddress, &.{.ptr}, &.{
+        const result = try self.wip.callIntrinsic(.none, .frameaddress, &.{.ptr}, &.{
             try o.builder.intValue(.i32, 0),
         }, "");
         return self.wip.cast(.ptrtoint, result, try o.lowerType(Type.usize), "");
@@ -8835,16 +8862,14 @@ pub const FuncGen = struct {
         const ptr_alignment = Builder.Alignment.fromByteUnits(
             info.flags.alignment.toByteUnitsOptional() orelse info.child.toType().abiAlignment(mod),
         );
-        const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
-            false => .normal,
-            true => .@"volatile",
-        };
+        const access_kind: Builder.MemoryAccessKind =
+            if (info.flags.is_volatile) .@"volatile" else .normal;
         const elem_llvm_ty = try o.lowerType(elem_ty);
 
         if (llvm_abi_ty != .none) {
             // operand needs widening and truncating
             const loaded = try self.wip.loadAtomic(
-                ptr_kind,
+                access_kind,
                 llvm_abi_ty,
                 ptr,
                 self.sync_scope,
@@ -8855,7 +8880,7 @@ pub const FuncGen = struct {
             return self.wip.cast(.trunc, loaded, elem_llvm_ty, "");
         }
         return self.wip.loadAtomic(
-            ptr_kind,
+            access_kind,
             elem_llvm_ty,
             ptr,
             self.sync_scope,
@@ -8902,7 +8927,8 @@ pub const FuncGen = struct {
         const elem_ty = self.typeOf(bin_op.rhs);
         const dest_ptr_align = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
         const dest_ptr = try self.sliceOrArrayPtr(dest_slice, ptr_ty);
-        const is_volatile = ptr_ty.isVolatilePtr(mod);
+        const access_kind: Builder.MemoryAccessKind =
+            if (ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;
 
         // Any WebAssembly runtime will trap when the destination pointer is out-of-bounds, regardless
         // of the length. This means we need to emit a check where we skip the memset when the length
@@ -8923,17 +8949,10 @@ pub const FuncGen = struct {
                     try o.builder.undefValue(.i8);
                 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
                 if (intrinsic_len0_traps) {
-                    try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
+                    try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, access_kind);
                 } else {
-                    _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
-                        dest_ptr.toLlvm(&self.wip),
-                        fill_byte.toLlvm(&self.wip),
-                        len.toLlvm(&self.wip),
-                        @intCast(dest_ptr_align.toByteUnits() orelse 0),
-                        is_volatile,
-                    ), &self.wip);
+                    _ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind);
                 }
-
                 if (safety and mod.comp.bin_file.options.valgrind) {
                     try self.valgrindMarkUndef(dest_ptr, len);
                 }
@@ -8945,19 +8964,12 @@ pub const FuncGen = struct {
             // repeating byte pattern of 0 bytes. In such case, the memset
             // intrinsic can be used.
             if (try elem_val.hasRepeatedByteRepr(elem_ty, mod)) |byte_val| {
-                const fill_byte = try self.resolveValue(.{ .ty = Type.u8, .val = byte_val });
+                const fill_byte = try o.builder.intValue(.i8, byte_val);
                 const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
-
                 if (intrinsic_len0_traps) {
-                    try self.safeWasmMemset(dest_ptr, fill_byte.toValue(), len, dest_ptr_align, is_volatile);
+                    try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, access_kind);
                 } else {
-                    _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
-                        dest_ptr.toLlvm(&self.wip),
-                        fill_byte.toLlvm(&o.builder),
-                        len.toLlvm(&self.wip),
-                        @intCast(dest_ptr_align.toByteUnits() orelse 0),
-                        is_volatile,
-                    ), &self.wip);
+                    _ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind);
                 }
                 return .none;
             }
@@ -8972,15 +8984,9 @@ pub const FuncGen = struct {
             const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty);
 
             if (intrinsic_len0_traps) {
-                try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, is_volatile);
+                try self.safeWasmMemset(dest_ptr, fill_byte, len, dest_ptr_align, access_kind);
             } else {
-                _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
-                    dest_ptr.toLlvm(&self.wip),
-                    fill_byte.toLlvm(&self.wip),
-                    len.toLlvm(&self.wip),
-                    @intCast(dest_ptr_align.toByteUnits() orelse 0),
-                    is_volatile,
-                ), &self.wip);
+                _ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind);
             }
             return .none;
         }
@@ -9006,10 +9012,10 @@ pub const FuncGen = struct {
         const body_block = try self.wip.block(1, "InlineMemsetBody");
         const end_block = try self.wip.block(1, "InlineMemsetEnd");
 
-        const usize_ty = try o.lowerType(Type.usize);
+        const llvm_usize_ty = try o.lowerType(Type.usize);
         const len = switch (ptr_ty.ptrSize(mod)) {
             .Slice => try self.wip.extractValue(dest_slice, &.{1}, ""),
-            .One => try o.builder.intValue(usize_ty, ptr_ty.childType(mod).arrayLen(mod)),
+            .One => try o.builder.intValue(llvm_usize_ty, ptr_ty.childType(mod).arrayLen(mod)),
             .Many, .C => unreachable,
         };
         const elem_llvm_ty = try o.lowerType(elem_ty);
@@ -9022,25 +9028,22 @@ pub const FuncGen = struct {
         _ = try self.wip.brCond(end, body_block, end_block);
 
         self.wip.cursor = .{ .block = body_block };
-        const elem_abi_alignment = elem_ty.abiAlignment(mod);
-        const it_ptr_alignment = Builder.Alignment.fromByteUnits(
-            @min(elem_abi_alignment, dest_ptr_align.toByteUnits() orelse std.math.maxInt(u64)),
+        const elem_abi_align = elem_ty.abiAlignment(mod);
+        const it_ptr_align = Builder.Alignment.fromByteUnits(
+            @min(elem_abi_align, dest_ptr_align.toByteUnits() orelse std.math.maxInt(u64)),
         );
         if (isByRef(elem_ty, mod)) {
-            _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
-                it_ptr.toValue().toLlvm(&self.wip),
-                @intCast(it_ptr_alignment.toByteUnits() orelse 0),
-                value.toLlvm(&self.wip),
-                elem_abi_alignment,
-                (try o.builder.intConst(usize_ty, elem_abi_size)).toLlvm(&o.builder),
-                is_volatile,
-            ), &self.wip);
-        } else _ = try self.wip.store(switch (is_volatile) {
-            false => .normal,
-            true => .@"volatile",
-        }, value, it_ptr.toValue(), it_ptr_alignment);
+            _ = try self.wip.callMemCpy(
+                it_ptr.toValue(),
+                it_ptr_align,
+                value,
+                Builder.Alignment.fromByteUnits(elem_abi_align),
+                try o.builder.intValue(llvm_usize_ty, elem_abi_size),
+                access_kind,
+            );
+        } else _ = try self.wip.store(access_kind, value, it_ptr.toValue(), it_ptr_align);
         const next_ptr = try self.wip.gep(.inbounds, elem_llvm_ty, it_ptr.toValue(), &.{
-            try o.builder.intValue(usize_ty, 1),
+            try o.builder.intValue(llvm_usize_ty, 1),
         }, "");
         _ = try self.wip.br(loop_block);
 
@@ -9055,7 +9058,7 @@ pub const FuncGen = struct {
         fill_byte: Builder.Value,
         len: Builder.Value,
         dest_ptr_align: Builder.Alignment,
-        is_volatile: bool,
+        access_kind: Builder.MemoryAccessKind,
     ) !void {
         const o = self.dg.object;
         const llvm_usize_ty = try o.lowerType(Type.usize);
@@ -9064,13 +9067,7 @@ pub const FuncGen = struct {
         const end_block = try self.wip.block(2, "MemsetTrapEnd");
         _ = try self.wip.brCond(cond, memset_block, end_block);
         self.wip.cursor = .{ .block = memset_block };
-        _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemSet(
-            dest_ptr.toLlvm(&self.wip),
-            fill_byte.toLlvm(&self.wip),
-            len.toLlvm(&self.wip),
-            @intCast(dest_ptr_align.toByteUnits() orelse 0),
-            is_volatile,
-        ), &self.wip);
+        _ = try self.wip.callMemSet(dest_ptr, dest_ptr_align, fill_byte, len, access_kind);
         _ = try self.wip.br(end_block);
         self.wip.cursor = .{ .block = end_block };
     }
@@ -9086,7 +9083,8 @@ pub const FuncGen = struct {
         const src_ptr = try self.sliceOrArrayPtr(src_slice, src_ptr_ty);
         const len = try self.sliceOrArrayLenInBytes(dest_slice, dest_ptr_ty);
         const dest_ptr = try self.sliceOrArrayPtr(dest_slice, dest_ptr_ty);
-        const is_volatile = src_ptr_ty.isVolatilePtr(mod) or dest_ptr_ty.isVolatilePtr(mod);
+        const access_kind: Builder.MemoryAccessKind = if (src_ptr_ty.isVolatilePtr(mod) or
+            dest_ptr_ty.isVolatilePtr(mod)) .@"volatile" else .normal;
 
         // When bulk-memory is enabled, this will be lowered to WebAssembly's memory.copy instruction.
         // This instruction will trap on an invalid address, regardless of the length.
@@ -9103,27 +9101,27 @@ pub const FuncGen = struct {
             const end_block = try self.wip.block(2, "MemcpyTrapEnd");
             _ = try self.wip.brCond(cond, memcpy_block, end_block);
             self.wip.cursor = .{ .block = memcpy_block };
-            _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
-                dest_ptr.toLlvm(&self.wip),
-                dest_ptr_ty.ptrAlignment(mod),
-                src_ptr.toLlvm(&self.wip),
-                src_ptr_ty.ptrAlignment(mod),
-                len.toLlvm(&self.wip),
-                is_volatile,
-            ), &self.wip);
+            _ = try self.wip.callMemCpy(
+                dest_ptr,
+                Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)),
+                src_ptr,
+                Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)),
+                len,
+                access_kind,
+            );
             _ = try self.wip.br(end_block);
             self.wip.cursor = .{ .block = end_block };
             return .none;
         }
 
-        _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
-            dest_ptr.toLlvm(&self.wip),
-            dest_ptr_ty.ptrAlignment(mod),
-            src_ptr.toLlvm(&self.wip),
-            src_ptr_ty.ptrAlignment(mod),
-            len.toLlvm(&self.wip),
-            is_volatile,
-        ), &self.wip);
+        _ = try self.wip.callMemCpy(
+            dest_ptr,
+            Builder.Alignment.fromByteUnits(dest_ptr_ty.ptrAlignment(mod)),
+            src_ptr,
+            Builder.Alignment.fromByteUnits(src_ptr_ty.ptrAlignment(mod)),
+            len,
+            access_kind,
+        );
         return .none;
     }
 
@@ -9196,8 +9194,8 @@ pub const FuncGen = struct {
         const operand_ty = self.typeOf(ty_op.operand);
         const operand = try self.resolveInst(ty_op.operand);
 
-        const result =
-            try self.wip.callIntrinsic(
+        const result = try self.wip.callIntrinsic(
+            .none,
             intrinsic,
             &.{try o.lowerType(operand_ty)},
             &.{ operand, .false },
@@ -9214,6 +9212,7 @@ pub const FuncGen = struct {
         const operand = try self.resolveInst(ty_op.operand);
 
         const result = try self.wip.callIntrinsic(
+            .none,
             intrinsic,
             &.{try o.lowerType(operand_ty)},
             &.{operand},
@@ -9251,7 +9250,7 @@ pub const FuncGen = struct {
             bits = bits + 8;
         }
 
-        const result = try self.wip.callIntrinsic(.bswap, &.{llvm_operand_ty}, &.{operand}, "");
+        const result = try self.wip.callIntrinsic(.none, .bswap, &.{llvm_operand_ty}, &.{operand}, "");
         return self.wip.conv(.unsigned, result, try o.lowerType(inst_ty), "");
     }
 
@@ -9646,14 +9645,14 @@ pub const FuncGen = struct {
         const llvm_scalar_ty = try o.lowerType(scalar_ty);
 
         switch (reduce.operation) {
-            .And, .Or, .Xor => return self.wip.callIntrinsic(switch (reduce.operation) {
+            .And, .Or, .Xor => return self.wip.callIntrinsic(.none, switch (reduce.operation) {
                 .And => .@"vector.reduce.and",
                 .Or => .@"vector.reduce.or",
                 .Xor => .@"vector.reduce.xor",
                 else => unreachable,
             }, &.{llvm_operand_ty}, &.{operand}, ""),
             .Min, .Max => switch (scalar_ty.zigTypeTag(mod)) {
-                .Int => return self.wip.callIntrinsic(switch (reduce.operation) {
+                .Int => return self.wip.callIntrinsic(.none, switch (reduce.operation) {
                     .Min => if (scalar_ty.isSignedInt(mod))
                         .@"vector.reduce.smin"
                     else
@@ -9665,7 +9664,7 @@ pub const FuncGen = struct {
                     else => unreachable,
                 }, &.{llvm_operand_ty}, &.{operand}, ""),
                 .Float => if (intrinsicsAllowed(scalar_ty, target))
-                    return self.wip.callIntrinsic(switch (reduce.operation) {
+                    return self.wip.callIntrinsic(.none, switch (reduce.operation) {
                         .Min => .@"vector.reduce.fmin",
                         .Max => .@"vector.reduce.fmax",
                         else => unreachable,
@@ -9673,13 +9672,13 @@ pub const FuncGen = struct {
                 else => unreachable,
             },
             .Add, .Mul => switch (scalar_ty.zigTypeTag(mod)) {
-                .Int => return self.wip.callIntrinsic(switch (reduce.operation) {
+                .Int => return self.wip.callIntrinsic(.none, switch (reduce.operation) {
                     .Add => .@"vector.reduce.add",
                     .Mul => .@"vector.reduce.mul",
                     else => unreachable,
                 }, &.{llvm_operand_ty}, &.{operand}, ""),
                 .Float => if (intrinsicsAllowed(scalar_ty, target))
-                    return self.wip.callIntrinsic(switch (reduce.operation) {
+                    return self.wip.callIntrinsic(.none, switch (reduce.operation) {
                         .Add => .@"vector.reduce.fadd",
                         .Mul => .@"vector.reduce.fmul",
                         else => unreachable,
@@ -10032,7 +10031,7 @@ pub const FuncGen = struct {
             .data => {},
         }
 
-        _ = try self.wip.callIntrinsic(.prefetch, &.{.ptr}, &.{
+        _ = try self.wip.callIntrinsic(.none, .prefetch, &.{.ptr}, &.{
             try self.resolveInst(prefetch.ptr),
             try o.builder.intValue(.i32, prefetch.rw),
             try o.builder.intValue(.i32, prefetch.locality),
@@ -10056,14 +10055,12 @@ pub const FuncGen = struct {
         default: u32,
         comptime basename: []const u8,
     ) !Builder.Value {
-        const o = self.dg.object;
-        const intrinsic = switch (dimension) {
+        return self.wip.callIntrinsic(.none, switch (dimension) {
             0 => @field(Builder.Intrinsic, basename ++ ".x"),
             1 => @field(Builder.Intrinsic, basename ++ ".y"),
             2 => @field(Builder.Intrinsic, basename ++ ".z"),
-            else => return o.builder.intValue(.i32, default),
-        };
-        return self.wip.callIntrinsic(intrinsic, &.{}, &.{}, "");
+            else => return self.dg.object.builder.intValue(.i32, default),
+        }, &.{}, &.{}, "");
     }
 
     fn airWorkItemId(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value {
@@ -10087,7 +10084,7 @@ pub const FuncGen = struct {
 
         // Fetch the dispatch pointer, which points to this structure:
         // https://github.com/RadeonOpenCompute/ROCR-Runtime/blob/adae6c61e10d371f7cbc3d0e94ae2c070cab18a4/src/inc/hsa.h#L2913
-        const dispatch_ptr = try self.wip.callIntrinsic(.@"amdgcn.dispatch.ptr", &.{}, &.{}, "");
+        const dispatch_ptr = try self.wip.callIntrinsic(.none, .@"amdgcn.dispatch.ptr", &.{}, &.{}, "");
 
         // Load the work_group_* member from the struct as u16.
         // Just treat the dispatch pointer as an array of u16 to keep things simple.
@@ -10188,7 +10185,7 @@ pub const FuncGen = struct {
                 if (can_elide_load)
                     return payload_ptr;
 
-                return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, false);
+                return fg.loadByRef(payload_ptr, payload_ty, payload_alignment, .normal);
             }
             const payload_llvm_ty = try o.lowerType(payload_ty);
             return fg.wip.load(.normal, payload_llvm_ty, payload_ptr, payload_alignment, "");
@@ -10297,7 +10294,7 @@ pub const FuncGen = struct {
         ptr: Builder.Value,
         pointee_type: Type,
         ptr_alignment: Builder.Alignment,
-        is_volatile: bool,
+        access_kind: Builder.MemoryAccessKind,
     ) !Builder.Value {
         const o = fg.dg.object;
         const mod = o.module;
@@ -10306,16 +10303,15 @@ pub const FuncGen = struct {
             @max(ptr_alignment.toByteUnits() orelse 0, pointee_type.abiAlignment(mod)),
         );
         const result_ptr = try fg.buildAlloca(pointee_llvm_ty, result_align);
-        const usize_ty = try o.lowerType(Type.usize);
         const size_bytes = pointee_type.abiSize(mod);
-        _ = (try fg.wip.unimplemented(.void, "")).finish(fg.builder.buildMemCpy(
-            result_ptr.toLlvm(&fg.wip),
-            @intCast(result_align.toByteUnits() orelse 0),
-            ptr.toLlvm(&fg.wip),
-            @intCast(ptr_alignment.toByteUnits() orelse 0),
-            (try o.builder.intConst(usize_ty, size_bytes)).toLlvm(&o.builder),
-            is_volatile,
-        ), &fg.wip);
+        _ = try fg.wip.callMemCpy(
+            result_ptr,
+            result_align,
+            ptr,
+            ptr_alignment,
+            try o.builder.intValue(try o.lowerType(Type.usize), size_bytes),
+            access_kind,
+        );
         return result_ptr;
     }
 
@@ -10332,10 +10328,8 @@ pub const FuncGen = struct {
         const ptr_alignment = Builder.Alignment.fromByteUnits(
             info.flags.alignment.toByteUnitsOptional() orelse elem_ty.abiAlignment(mod),
         );
-        const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
-            false => .normal,
-            true => .@"volatile",
-        };
+        const access_kind: Builder.MemoryAccessKind =
+            if (info.flags.is_volatile) .@"volatile" else .normal;
 
         assert(info.flags.vector_index != .runtime);
         if (info.flags.vector_index != .none) {
@@ -10343,19 +10337,20 @@ pub const FuncGen = struct {
             const vec_elem_ty = try o.lowerType(elem_ty);
             const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty);
 
-            const loaded_vector = try self.wip.load(ptr_kind, vec_ty, ptr, ptr_alignment, "");
+            const loaded_vector = try self.wip.load(access_kind, vec_ty, ptr, ptr_alignment, "");
             return self.wip.extractElement(loaded_vector, index_u32, "");
         }
 
         if (info.packed_offset.host_size == 0) {
             if (isByRef(elem_ty, mod)) {
-                return self.loadByRef(ptr, elem_ty, ptr_alignment, info.flags.is_volatile);
+                return self.loadByRef(ptr, elem_ty, ptr_alignment, access_kind);
             }
-            return self.wip.load(ptr_kind, try o.lowerType(elem_ty), ptr, ptr_alignment, "");
+            return self.wip.load(access_kind, try o.lowerType(elem_ty), ptr, ptr_alignment, "");
         }
 
         const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8));
-        const containing_int = try self.wip.load(ptr_kind, containing_int_ty, ptr, ptr_alignment, "");
+        const containing_int =
+            try self.wip.load(access_kind, containing_int_ty, ptr, ptr_alignment, "");
 
         const elem_bits = ptr_ty.childType(mod).bitSize(mod);
         const shift_amt = try o.builder.intValue(containing_int_ty, info.packed_offset.bit_offset);
@@ -10402,10 +10397,8 @@ pub const FuncGen = struct {
             return;
         }
         const ptr_alignment = Builder.Alignment.fromByteUnits(ptr_ty.ptrAlignment(mod));
-        const ptr_kind: Builder.MemoryAccessKind = switch (info.flags.is_volatile) {
-            false => .normal,
-            true => .@"volatile",
-        };
+        const access_kind: Builder.MemoryAccessKind =
+            if (info.flags.is_volatile) .@"volatile" else .normal;
 
         assert(info.flags.vector_index != .runtime);
         if (info.flags.vector_index != .none) {
@@ -10413,12 +10406,12 @@ pub const FuncGen = struct {
             const vec_elem_ty = try o.lowerType(elem_ty);
             const vec_ty = try o.builder.vectorType(.normal, info.packed_offset.host_size, vec_elem_ty);
 
-            const loaded_vector = try self.wip.load(ptr_kind, vec_ty, ptr, ptr_alignment, "");
+            const loaded_vector = try self.wip.load(access_kind, vec_ty, ptr, ptr_alignment, "");
 
             const modified_vector = try self.wip.insertElement(loaded_vector, elem, index_u32, "");
 
             assert(ordering == .none);
-            _ = try self.wip.store(ptr_kind, modified_vector, ptr, ptr_alignment);
+            _ = try self.wip.store(access_kind, modified_vector, ptr, ptr_alignment);
             return;
         }
 
@@ -10426,7 +10419,7 @@ pub const FuncGen = struct {
             const containing_int_ty = try o.builder.intType(@intCast(info.packed_offset.host_size * 8));
             assert(ordering == .none);
             const containing_int =
-                try self.wip.load(ptr_kind, containing_int_ty, ptr, ptr_alignment, "");
+                try self.wip.load(access_kind, containing_int_ty, ptr, ptr_alignment, "");
             const elem_bits = ptr_ty.childType(mod).bitSize(mod);
             const shift_amt = try o.builder.intConst(containing_int_ty, info.packed_offset.bit_offset);
             // Convert to equally-sized integer type in order to perform the bit
@@ -10450,23 +10443,29 @@ pub const FuncGen = struct {
             const ored_value = try self.wip.bin(.@"or", shifted_value, anded_containing_int, "");
 
             assert(ordering == .none);
-            _ = try self.wip.store(ptr_kind, ored_value, ptr, ptr_alignment);
+            _ = try self.wip.store(access_kind, ored_value, ptr, ptr_alignment);
             return;
         }
         if (!isByRef(elem_ty, mod)) {
-            _ = try self.wip.storeAtomic(ptr_kind, elem, ptr, self.sync_scope, ordering, ptr_alignment);
+            _ = try self.wip.storeAtomic(
+                access_kind,
+                elem,
+                ptr,
+                self.sync_scope,
+                ordering,
+                ptr_alignment,
+            );
             return;
         }
         assert(ordering == .none);
-        const size_bytes = elem_ty.abiSize(mod);
-        _ = (try self.wip.unimplemented(.void, "")).finish(self.builder.buildMemCpy(
-            ptr.toLlvm(&self.wip),
-            @intCast(ptr_alignment.toByteUnits() orelse 0),
-            elem.toLlvm(&self.wip),
-            elem_ty.abiAlignment(mod),
-            (try o.builder.intConst(try o.lowerType(Type.usize), size_bytes)).toLlvm(&o.builder),
-            info.flags.is_volatile,
-        ), &self.wip);
+        _ = try self.wip.callMemCpy(
+            ptr,
+            ptr_alignment,
+            elem,
+            Builder.Alignment.fromByteUnits(elem_ty.abiAlignment(mod)),
+            try o.builder.intValue(try o.lowerType(Type.usize), elem_ty.abiSize(mod)),
+            access_kind,
+        );
     }
 
     fn valgrindMarkUndef(fg: *FuncGen, ptr: Builder.Value, len: Builder.Value) Allocator.Error!void {
src/value.zig
@@ -3831,7 +3831,7 @@ pub const Value = struct {
 
     /// If the value is represented in-memory as a series of bytes that all
     /// have the same value, return that byte value, otherwise null.
-    pub fn hasRepeatedByteRepr(val: Value, ty: Type, mod: *Module) !?Value {
+    pub fn hasRepeatedByteRepr(val: Value, ty: Type, mod: *Module) !?u8 {
         const abi_size = std.math.cast(usize, ty.abiSize(mod)) orelse return null;
         assert(abi_size >= 1);
         const byte_buffer = try mod.gpa.alloc(u8, abi_size);
@@ -3852,7 +3852,7 @@ pub const Value = struct {
         for (byte_buffer[1..]) |byte| {
             if (byte != first_byte) return null;
         }
-        return try mod.intValue(Type.u8, first_byte);
+        return first_byte;
     }
 
     pub fn isGenericPoison(val: Value) bool {
src/zig_llvm.cpp
@@ -408,22 +408,6 @@ void ZigLLVMSetTailCallKind(LLVMValueRef Call, enum ZigLLVMTailCallKind TailCall
     unwrap<CallInst>(Call)->setTailCallKind(TCK);
 }
 
-LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
-        LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile)
-{
-    CallInst *call_inst = unwrap(B)->CreateMemCpy(unwrap(Dst),
-        MaybeAlign(DstAlign), unwrap(Src), MaybeAlign(SrcAlign), unwrap(Size), isVolatile);
-    return wrap(call_inst);
-}
-
-LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMValueRef Val, LLVMValueRef Size,
-        unsigned Align, bool isVolatile)
-{
-    CallInst *call_inst = unwrap(B)->CreateMemSet(unwrap(Ptr), unwrap(Val), unwrap(Size),
-            MaybeAlign(Align), isVolatile);
-    return wrap(call_inst);
-}
-
 void ZigLLVMFnSetSubprogram(LLVMValueRef fn, ZigLLVMDISubprogram *subprogram) {
     assert( isa<Function>(unwrap(fn)) );
     Function *unwrapped_function = reinterpret_cast<Function*>(unwrap(fn));
src/zig_llvm.h
@@ -122,12 +122,6 @@ enum ZigLLVM_CallingConv {
     ZigLLVM_MaxID = 1023,
 };
 
-ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemCpy(LLVMBuilderRef B, LLVMValueRef Dst, unsigned DstAlign,
-        LLVMValueRef Src, unsigned SrcAlign, LLVMValueRef Size, bool isVolatile);
-
-ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildMemSet(LLVMBuilderRef B, LLVMValueRef Ptr, LLVMValueRef Val, LLVMValueRef Size,
-        unsigned Align, bool isVolatile);
-
 ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildNSWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,
         const char *name);
 ZIG_EXTERN_C LLVMValueRef ZigLLVMBuildNUWShl(LLVMBuilderRef builder, LLVMValueRef LHS, LLVMValueRef RHS,