| ... | @@ -25793,7 +25793,6 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -25793,7 +25793,6 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 25793 | const src_len = try indexablePtrLenOrNone(sema, block, src_src, src_ptr); | 25793 | const src_len = try indexablePtrLenOrNone(sema, block, src_src, src_ptr); |
| 25794 | const pt = sema.pt; | 25794 | const pt = sema.pt; |
| 25795 | const zcu = pt.zcu; | 25795 | const zcu = pt.zcu; |
| 25796 | const target = zcu.getTarget(); | | |
| 25797 | | 25796 | |
| 25798 | if (dest_ty.isConstPtr(zcu)) { | 25797 | if (dest_ty.isConstPtr(zcu)) { |
| 25799 | return sema.fail(block, dest_src, "cannot memcpy to constant pointer", .{}); | 25798 | return sema.fail(block, dest_src, "cannot memcpy to constant pointer", .{}); |
| ... | @@ -25814,6 +25813,30 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -25814,6 +25813,30 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 25814 | return sema.failWithOwnedErrorMsg(block, msg); | 25813 | return sema.failWithOwnedErrorMsg(block, msg); |
| 25815 | } | 25814 | } |
| 25816 | | 25815 | |
| | 25816 | const dest_elem_ty = dest_ty.indexablePtrElem(zcu); |
| | 25817 | const src_elem_ty = src_ty.indexablePtrElem(zcu); |
| | 25818 | |
| | 25819 | const imc = try sema.coerceInMemoryAllowed( |
| | 25820 | block, |
| | 25821 | dest_elem_ty, |
| | 25822 | src_elem_ty, |
| | 25823 | false, |
| | 25824 | zcu.getTarget(), |
| | 25825 | dest_src, |
| | 25826 | src_src, |
| | 25827 | null, |
| | 25828 | ); |
| | 25829 | if (imc != .ok) return sema.failWithOwnedErrorMsg(block, msg: { |
| | 25830 | const msg = try sema.errMsg( |
| | 25831 | src, |
| | 25832 | "pointer element type '{}' cannot coerce into element type '{}'", |
| | 25833 | .{ src_elem_ty.fmt(pt), dest_elem_ty.fmt(pt) }, |
| | 25834 | ); |
| | 25835 | errdefer msg.destroy(sema.gpa); |
| | 25836 | try imc.report(sema, src, msg); |
| | 25837 | break :msg msg; |
| | 25838 | }); |
| | 25839 | |
| 25817 | var len_val: ?Value = null; | 25840 | var len_val: ?Value = null; |
| 25818 | | 25841 | |
| 25819 | if (dest_len != .none and src_len != .none) check: { | 25842 | if (dest_len != .none and src_len != .none) check: { |
| ... | @@ -25855,61 +25878,52 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -25855,61 +25878,52 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 25855 | } | 25878 | } |
| 25856 | } | 25879 | } |
| 25857 | | 25880 | |
| 25858 | const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: { | 25881 | const runtime_src = rs: { |
| | 25882 | const dest_ptr_val = try sema.resolveDefinedValue(block, dest_src, dest_ptr) orelse break :rs dest_src; |
| | 25883 | const src_ptr_val = try sema.resolveDefinedValue(block, src_src, src_ptr) orelse break :rs src_src; |
| | 25884 | |
| | 25885 | const raw_dest_ptr = if (dest_ty.isSlice(zcu)) dest_ptr_val.slicePtr(zcu) else dest_ptr_val; |
| | 25886 | const raw_src_ptr = if (src_ty.isSlice(zcu)) src_ptr_val.slicePtr(zcu) else src_ptr_val; |
| | 25887 | |
| | 25888 | const len_u64 = try len_val.?.toUnsignedIntSema(pt); |
| | 25889 | |
| | 25890 | if (Value.doPointersOverlap( |
| | 25891 | raw_src_ptr, |
| | 25892 | raw_dest_ptr, |
| | 25893 | len_u64, |
| | 25894 | zcu, |
| | 25895 | )) return sema.fail(block, src, "'@memcpy' arguments alias", .{}); |
| | 25896 | |
| 25859 | if (!sema.isComptimeMutablePtr(dest_ptr_val)) break :rs dest_src; | 25897 | if (!sema.isComptimeMutablePtr(dest_ptr_val)) break :rs dest_src; |
| 25860 | if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| { | | |
| 25861 | const len_u64 = try len_val.?.toUnsignedIntSema(pt); | | |
| 25862 | const len = try sema.usizeCast(block, dest_src, len_u64); | | |
| 25863 | for (0..len) |i| { | | |
| 25864 | const elem_index = try pt.intRef(Type.usize, i); | | |
| 25865 | const dest_elem_ptr = try sema.elemPtrOneLayerOnly( | | |
| 25866 | block, | | |
| 25867 | src, | | |
| 25868 | dest_ptr, | | |
| 25869 | elem_index, | | |
| 25870 | src, | | |
| 25871 | true, // init | | |
| 25872 | false, // oob_safety | | |
| 25873 | ); | | |
| 25874 | const src_elem_ptr = try sema.elemPtrOneLayerOnly( | | |
| 25875 | block, | | |
| 25876 | src, | | |
| 25877 | src_ptr, | | |
| 25878 | elem_index, | | |
| 25879 | src, | | |
| 25880 | false, // init | | |
| 25881 | false, // oob_safety | | |
| 25882 | ); | | |
| 25883 | const uncoerced_elem = try sema.analyzeLoad(block, src, src_elem_ptr, src_src); | | |
| 25884 | try sema.storePtr2( | | |
| 25885 | block, | | |
| 25886 | src, | | |
| 25887 | dest_elem_ptr, | | |
| 25888 | dest_src, | | |
| 25889 | uncoerced_elem, | | |
| 25890 | src_src, | | |
| 25891 | .store, | | |
| 25892 | ); | | |
| 25893 | } | | |
| 25894 | return; | | |
| 25895 | } else break :rs src_src; | | |
| 25896 | } else dest_src; | | |
| 25897 | | 25898 | |
| 25898 | // If in-memory coercion is not allowed, explode this memcpy call into a | 25899 | // Because comptime pointer access is a somewhat expensive operation, we implement @memcpy |
| 25899 | // for loop that copies element-wise. | 25900 | // as one load and store of an array, rather than N loads and stores of individual elements. |
| 25900 | // Likewise if this is an iterable rather than a pointer, do the same | | |
| 25901 | // lowering. The AIR instruction requires pointers with element types of | | |
| 25902 | // equal ABI size. | | |
| 25903 | | 25901 | |
| 25904 | if (dest_ty.zigTypeTag(zcu) != .pointer or src_ty.zigTypeTag(zcu) != .pointer) { | 25902 | const array_ty = try pt.arrayType(.{ |
| 25905 | return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the source or destination iterable is a tuple", .{}); | 25903 | .child = dest_elem_ty.toIntern(), |
| 25906 | } | 25904 | .len = len_u64, |
| | 25905 | }); |
| 25907 | | 25906 | |
| 25908 | const dest_elem_ty = dest_ty.elemType2(zcu); | 25907 | const dest_array_ptr_ty = try pt.ptrType(info: { |
| 25909 | const src_elem_ty = src_ty.elemType2(zcu); | 25908 | var info = dest_ty.ptrInfo(zcu); |
| 25910 | if (.ok != try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, true, target, dest_src, src_src, null)) { | 25909 | info.flags.size = .one; |
| 25911 | return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the element types have different ABI sizes", .{}); | 25910 | info.child = array_ty.toIntern(); |
| 25912 | } | 25911 | break :info info; |
| | 25912 | }); |
| | 25913 | const src_array_ptr_ty = try pt.ptrType(info: { |
| | 25914 | var info = src_ty.ptrInfo(zcu); |
| | 25915 | info.flags.size = .one; |
| | 25916 | info.child = array_ty.toIntern(); |
| | 25917 | break :info info; |
| | 25918 | }); |
| | 25919 | |
| | 25920 | const coerced_dest_ptr = try pt.getCoerced(raw_dest_ptr, dest_array_ptr_ty); |
| | 25921 | const coerced_src_ptr = try pt.getCoerced(raw_src_ptr, src_array_ptr_ty); |
| | 25922 | |
| | 25923 | const array_val = try sema.pointerDeref(block, src_src, coerced_src_ptr, src_array_ptr_ty) orelse break :rs src_src; |
| | 25924 | try sema.storePtrVal(block, dest_src, coerced_dest_ptr, array_val, array_ty); |
| | 25925 | return; |
| | 25926 | }; |
| 25913 | | 25927 | |
| 25914 | // If the length is comptime-known, then upgrade src and destination types | 25928 | // If the length is comptime-known, then upgrade src and destination types |
| 25915 | // into pointer-to-array. At this point we know they are both pointers | 25929 | // into pointer-to-array. At this point we know they are both pointers |