@@ -25793,7 +25793,6 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
25793
25793
const src_len = try indexablePtrLenOrNone(sema, block, src_src, src_ptr);
25794
25794
const pt = sema.pt;
25795
25795
const zcu = pt.zcu;
25796
- const target = zcu.getTarget();
25797
25796
25798
25797
if (dest_ty.isConstPtr(zcu)) {
25799
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
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
25840
var len_val: ?Value = null;
25818
25841
25819
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
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
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
- // for loop that copies element-wise.
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.
25899
+ // Because comptime pointer access is a somewhat expensive operation, we implement @memcpy
25900
+ // as one load and store of an array, rather than N loads and stores of individual elements.
25903
25901
25904
- if (dest_ty.zigTypeTag(zcu) != .pointer or src_ty.zigTypeTag(zcu) != .pointer) {
25905
- return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the source or destination iterable is a tuple", .{});
25906
- }
25902
+ const array_ty = try pt.arrayType(.{
25903
+ .child = dest_elem_ty.toIntern(),
25904
+ .len = len_u64,
25905
+ });
25907
25906
25908
- const dest_elem_ty = dest_ty.elemType2(zcu);
25909
- const src_elem_ty = src_ty.elemType2(zcu);
25910
- if (.ok != try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, true, target, dest_src, src_src, null)) {
25911
- return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the element types have different ABI sizes", .{});
25912
- }
25907
+ const dest_array_ptr_ty = try pt.ptrType(info: {
25908
+ var info = dest_ty.ptrInfo(zcu);
25909
+ info.flags.size = .one;
25910
+ info.child = array_ty.toIntern();
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
25928
// If the length is comptime-known, then upgrade src and destination types
25915
25929
// into pointer-to-array. At this point we know they are both pointers
0 commit comments