| ... | ... | @@ -9766,14 +9766,6 @@ pub const FuncGen = struct { |
| 9766 | 9766 | const access_kind: Builder.MemoryAccessKind = |
| 9767 | 9767 | if (ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; |
| 9768 | 9768 | |
| 9769 | | // Any WebAssembly runtime will trap when the destination pointer is out-of-bounds, regardless |
| 9770 | | // of the length. This means we need to emit a check where we skip the memset when the length |
| 9771 | | // is 0 as we allow for undefined pointers in 0-sized slices. |
| 9772 | | // This logic can be removed once https://github.com/ziglang/zig/issues/16360 is done. |
| 9773 | | const intrinsic_len0_traps = o.target.cpu.arch.isWasm() and |
| 9774 | | ptr_ty.isSlice(zcu) and |
| 9775 | | std.Target.wasm.featureSetHas(o.target.cpu.features, .bulk_memory); |
| 9776 | | |
| 9777 | 9769 | if (try self.air.value(bin_op.rhs, pt)) |elem_val| { |
| 9778 | 9770 | if (elem_val.isUndefDeep(zcu)) { |
| 9779 | 9771 | // Even if safety is disabled, we still emit a memset to undefined since it conveys |
| ... | ... | @@ -9784,24 +9776,14 @@ pub const FuncGen = struct { |
| 9784 | 9776 | else |
| 9785 | 9777 | try o.builder.undefValue(.i8); |
| 9786 | 9778 | const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); |
| 9787 | | if (intrinsic_len0_traps) { |
| 9788 | | try self.safeWasmMemset( |
| 9789 | | dest_ptr, |
| 9790 | | fill_byte, |
| 9791 | | len, |
| 9792 | | dest_ptr_align, |
| 9793 | | access_kind, |
| 9794 | | ); |
| 9795 | | } else { |
| 9796 | | _ = try self.wip.callMemSet( |
| 9797 | | dest_ptr, |
| 9798 | | dest_ptr_align, |
| 9799 | | fill_byte, |
| 9800 | | len, |
| 9801 | | access_kind, |
| 9802 | | self.disable_intrinsics, |
| 9803 | | ); |
| 9804 | | } |
| 9779 | _ = try self.wip.callMemSet( |
| 9780 | dest_ptr, |
| 9781 | dest_ptr_align, |
| 9782 | fill_byte, |
| 9783 | len, |
| 9784 | access_kind, |
| 9785 | self.disable_intrinsics, |
| 9786 | ); |
| 9805 | 9787 | const owner_mod = self.ng.ownerModule(); |
| 9806 | 9788 | if (safety and owner_mod.valgrind) { |
| 9807 | 9789 | try self.valgrindMarkUndef(dest_ptr, len); |
| ... | ... | @@ -9816,24 +9798,14 @@ pub const FuncGen = struct { |
| 9816 | 9798 | if (try elem_val.hasRepeatedByteRepr(pt)) |byte_val| { |
| 9817 | 9799 | const fill_byte = try o.builder.intValue(.i8, byte_val); |
| 9818 | 9800 | const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); |
| 9819 | | if (intrinsic_len0_traps) { |
| 9820 | | try self.safeWasmMemset( |
| 9821 | | dest_ptr, |
| 9822 | | fill_byte, |
| 9823 | | len, |
| 9824 | | dest_ptr_align, |
| 9825 | | access_kind, |
| 9826 | | ); |
| 9827 | | } else { |
| 9828 | | _ = try self.wip.callMemSet( |
| 9829 | | dest_ptr, |
| 9830 | | dest_ptr_align, |
| 9831 | | fill_byte, |
| 9832 | | len, |
| 9833 | | access_kind, |
| 9834 | | self.disable_intrinsics, |
| 9835 | | ); |
| 9836 | | } |
| 9801 | _ = try self.wip.callMemSet( |
| 9802 | dest_ptr, |
| 9803 | dest_ptr_align, |
| 9804 | fill_byte, |
| 9805 | len, |
| 9806 | access_kind, |
| 9807 | self.disable_intrinsics, |
| 9808 | ); |
| 9837 | 9809 | return .none; |
| 9838 | 9810 | } |
| 9839 | 9811 | } |
| ... | ... | @@ -9846,24 +9818,14 @@ pub const FuncGen = struct { |
| 9846 | 9818 | const fill_byte = try self.bitCast(value, elem_ty, Type.u8); |
| 9847 | 9819 | const len = try self.sliceOrArrayLenInBytes(dest_slice, ptr_ty); |
| 9848 | 9820 | |
| 9849 | | if (intrinsic_len0_traps) { |
| 9850 | | try self.safeWasmMemset( |
| 9851 | | dest_ptr, |
| 9852 | | fill_byte, |
| 9853 | | len, |
| 9854 | | dest_ptr_align, |
| 9855 | | access_kind, |
| 9856 | | ); |
| 9857 | | } else { |
| 9858 | | _ = try self.wip.callMemSet( |
| 9859 | | dest_ptr, |
| 9860 | | dest_ptr_align, |
| 9861 | | fill_byte, |
| 9862 | | len, |
| 9863 | | access_kind, |
| 9864 | | self.disable_intrinsics, |
| 9865 | | ); |
| 9866 | | } |
| 9821 | _ = try self.wip.callMemSet( |
| 9822 | dest_ptr, |
| 9823 | dest_ptr_align, |
| 9824 | fill_byte, |
| 9825 | len, |
| 9826 | access_kind, |
| 9827 | self.disable_intrinsics, |
| 9828 | ); |
| 9867 | 9829 | return .none; |
| 9868 | 9830 | } |
| 9869 | 9831 | |
| ... | ... | @@ -9927,33 +9889,6 @@ pub const FuncGen = struct { |
| 9927 | 9889 | return .none; |
| 9928 | 9890 | } |
| 9929 | 9891 | |
| 9930 | | fn safeWasmMemset( |
| 9931 | | self: *FuncGen, |
| 9932 | | dest_ptr: Builder.Value, |
| 9933 | | fill_byte: Builder.Value, |
| 9934 | | len: Builder.Value, |
| 9935 | | dest_ptr_align: Builder.Alignment, |
| 9936 | | access_kind: Builder.MemoryAccessKind, |
| 9937 | | ) !void { |
| 9938 | | const o = self.ng.object; |
| 9939 | | const usize_zero = try o.builder.intValue(try o.lowerType(Type.usize), 0); |
| 9940 | | const cond = try self.cmp(.normal, .neq, Type.usize, len, usize_zero); |
| 9941 | | const memset_block = try self.wip.block(1, "MemsetTrapSkip"); |
| 9942 | | const end_block = try self.wip.block(2, "MemsetTrapEnd"); |
| 9943 | | _ = try self.wip.brCond(cond, memset_block, end_block, .none); |
| 9944 | | self.wip.cursor = .{ .block = memset_block }; |
| 9945 | | _ = try self.wip.callMemSet( |
| 9946 | | dest_ptr, |
| 9947 | | dest_ptr_align, |
| 9948 | | fill_byte, |
| 9949 | | len, |
| 9950 | | access_kind, |
| 9951 | | self.disable_intrinsics, |
| 9952 | | ); |
| 9953 | | _ = try self.wip.br(end_block); |
| 9954 | | self.wip.cursor = .{ .block = end_block }; |
| 9955 | | } |
| 9956 | | |
| 9957 | 9892 | fn airMemcpy(self: *FuncGen, inst: Air.Inst.Index) !Builder.Value { |
| 9958 | 9893 | const o = self.ng.object; |
| 9959 | 9894 | const pt = o.pt; |
| ... | ... | @@ -9969,35 +9904,6 @@ pub const FuncGen = struct { |
| 9969 | 9904 | const access_kind: Builder.MemoryAccessKind = if (src_ptr_ty.isVolatilePtr(zcu) or |
| 9970 | 9905 | dest_ptr_ty.isVolatilePtr(zcu)) .@"volatile" else .normal; |
| 9971 | 9906 | |
| 9972 | | // When bulk-memory is enabled, this will be lowered to WebAssembly's memory.copy instruction. |
| 9973 | | // This instruction will trap on an invalid address, regardless of the length. |
| 9974 | | // For this reason we must add a check for 0-sized slices as its pointer field can be undefined. |
| 9975 | | // We only have to do this for slices as arrays will have a valid pointer. |
| 9976 | | // This logic can be removed once https://github.com/ziglang/zig/issues/16360 is done. |
| 9977 | | if (o.target.cpu.arch.isWasm() and |
| 9978 | | std.Target.wasm.featureSetHas(o.target.cpu.features, .bulk_memory) and |
| 9979 | | dest_ptr_ty.isSlice(zcu)) |
| 9980 | | { |
| 9981 | | const usize_zero = try o.builder.intValue(try o.lowerType(Type.usize), 0); |
| 9982 | | const cond = try self.cmp(.normal, .neq, Type.usize, len, usize_zero); |
| 9983 | | const memcpy_block = try self.wip.block(1, "MemcpyTrapSkip"); |
| 9984 | | const end_block = try self.wip.block(2, "MemcpyTrapEnd"); |
| 9985 | | _ = try self.wip.brCond(cond, memcpy_block, end_block, .none); |
| 9986 | | self.wip.cursor = .{ .block = memcpy_block }; |
| 9987 | | _ = try self.wip.callMemCpy( |
| 9988 | | dest_ptr, |
| 9989 | | dest_ptr_ty.ptrAlignment(zcu).toLlvm(), |
| 9990 | | src_ptr, |
| 9991 | | src_ptr_ty.ptrAlignment(zcu).toLlvm(), |
| 9992 | | len, |
| 9993 | | access_kind, |
| 9994 | | self.disable_intrinsics, |
| 9995 | | ); |
| 9996 | | _ = try self.wip.br(end_block); |
| 9997 | | self.wip.cursor = .{ .block = end_block }; |
| 9998 | | return .none; |
| 9999 | | } |
| 10000 | | |
| 10001 | 9907 | _ = try self.wip.callMemCpy( |
| 10002 | 9908 | dest_ptr, |
| 10003 | 9909 | dest_ptr_ty.ptrAlignment(zcu).toLlvm(), |