diff --git a/src/Sema.zig b/src/Sema.zig index 338980d56f5e..42babb3fd7c2 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -14562,8 +14562,9 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const mutable_alloc = try block.addTy(.alloc, alloc_ty); - // if both the source and destination are arrays - // we can hotpath via a memcpy. + // there's nothing to copy + if (result_len == 0 and res_sent_val == null) return mutable_alloc; + if (lhs_ty.zigTypeTag(zcu) == .pointer and rhs_ty.zigTypeTag(zcu) == .pointer) { @@ -14576,48 +14577,75 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai }); const many_ty = slice_ty.slicePtrFieldType(zcu); - const many_alloc = try block.addBitCast(many_ty, mutable_alloc); + const many_ty_ref = Air.internedToRef(many_ty.toIntern()); - // lhs_dest_slice = dest[0..lhs.len] - const slice_ty_ref = Air.internedToRef(slice_ty.toIntern()); const lhs_len_ref = try pt.intRef(.usize, lhs_len); - const lhs_dest_slice = try block.addInst(.{ - .tag = .slice, - .data = .{ .ty_pl = .{ - .ty = slice_ty_ref, - .payload = try sema.addExtra(Air.Bin{ - .lhs = many_alloc, - .rhs = lhs_len_ref, - }), - } }, - }); - _ = try block.addBinOp(.memcpy, lhs_dest_slice, lhs); + // @memcpy(@as(*[lhs.len]T, dst[0..lhs.len]), lhs.ptr) + if (lhs_len != 0) { + // [lhs.len]T + const array_ty = try pt.arrayType(.{ + .child = resolved_elem_ty.toIntern(), + .len = lhs_len, + }); + // *[lhs.len]T + const mutable_ty = try pt.ptrTypeSema(.{ + .child = array_ty.toIntern(), + .flags = .{ .address_space = ptr_as }, + }); + const lhs_dest_slice = try block.addBitCast(mutable_ty, mutable_alloc); + + const lhs_src_pointer = if (lhs_ty.isSlice(zcu)) + try block.addInst(.{ + .tag = .slice_ptr, + .data = .{ .ty_op = .{ + .ty = many_ty_ref, + .operand = lhs, + } }, + }) + else + lhs; + _ = try block.addBinOp(.memcpy, lhs_dest_slice, lhs_src_pointer); + } - // rhs_dest_slice = dest[lhs.len..][0..rhs.len] - const rhs_len_ref = try pt.intRef(.usize, rhs_len); - const rhs_dest_offset = try block.addInst(.{ - .tag = .ptr_add, - .data = .{ .ty_pl = .{ - .ty = Air.internedToRef(many_ty.toIntern()), - .payload = try sema.addExtra(Air.Bin{ - .lhs = many_alloc, - .rhs = lhs_len_ref, - }), - } }, - }); - const rhs_dest_slice = try block.addInst(.{ - .tag = .slice, - .data = .{ .ty_pl = .{ - .ty = slice_ty_ref, - .payload = try sema.addExtra(Air.Bin{ - .lhs = rhs_dest_offset, - .rhs = rhs_len_ref, - }), - } }, - }); + if (rhs_len != 0) { + const many_alloc = try block.addBitCast(many_ty, mutable_alloc); + const rhs_dest_offset = try block.addInst(.{ + .tag = .ptr_add, + .data = .{ .ty_pl = .{ + .ty = many_ty_ref, + .payload = try sema.addExtra(Air.Bin{ + .lhs = many_alloc, + .rhs = lhs_len_ref, + }), + } }, + }); + + // [rhs.len]T + const array_ty = try pt.arrayType(.{ + .child = resolved_elem_ty.toIntern(), + .len = rhs_len, + }); + // *[rhs.len]T + const mutable_ty = try pt.ptrTypeSema(.{ + .child = array_ty.toIntern(), + .flags = .{ .address_space = ptr_as }, + }); - _ = try block.addBinOp(.memcpy, rhs_dest_slice, rhs); + const rhs_dest_slice = try block.addBitCast(mutable_ty, rhs_dest_offset); + + const rhs_src_pointer = if (rhs_ty.isSlice(zcu)) + try block.addInst(.{ + .tag = .slice_ptr, + .data = .{ .ty_op = .{ + .ty = many_ty_ref, + .operand = rhs, + } }, + }) + else + rhs; + _ = try block.addBinOp(.memcpy, rhs_dest_slice, rhs_src_pointer); + } if (res_sent_val) |sent_val| { const elem_index = try pt.intRef(.usize, result_len); diff --git a/test/behavior/array.zig b/test/behavior/array.zig index b28ee267c2e0..06929dd0c776 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -92,6 +92,12 @@ test "array init with concat" { try expect(std.mem.eql(u8, &i, "abcd")); } +test "array concat zero length pointers" { + var x: *const [0]u8 = &.{}; + _ = &x; + _ = @as([]const u8, "") ++ x; +} + test "array init with mult" { if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest; if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO