Skip to content

Commit d01082f

Browse files
committed
Sema: correct AIR semantics around array concat optimization
1 parent 493ad58 commit d01082f

File tree

2 files changed

+73
-39
lines changed

2 files changed

+73
-39
lines changed

src/Sema.zig

Lines changed: 67 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -14562,8 +14562,9 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1456214562

1456314563
const mutable_alloc = try block.addTy(.alloc, alloc_ty);
1456414564

14565-
// if both the source and destination are arrays
14566-
// we can hotpath via a memcpy.
14565+
// there's nothing to copy
14566+
if (result_len == 0 and res_sent_val == null) return mutable_alloc;
14567+
1456714568
if (lhs_ty.zigTypeTag(zcu) == .pointer and
1456814569
rhs_ty.zigTypeTag(zcu) == .pointer)
1456914570
{
@@ -14576,48 +14577,75 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1457614577
});
1457714578

1457814579
const many_ty = slice_ty.slicePtrFieldType(zcu);
14579-
const many_alloc = try block.addBitCast(many_ty, mutable_alloc);
14580+
const many_ty_ref = Air.internedToRef(many_ty.toIntern());
1458014581

14581-
// lhs_dest_slice = dest[0..lhs.len]
14582-
const slice_ty_ref = Air.internedToRef(slice_ty.toIntern());
1458314582
const lhs_len_ref = try pt.intRef(.usize, lhs_len);
14584-
const lhs_dest_slice = try block.addInst(.{
14585-
.tag = .slice,
14586-
.data = .{ .ty_pl = .{
14587-
.ty = slice_ty_ref,
14588-
.payload = try sema.addExtra(Air.Bin{
14589-
.lhs = many_alloc,
14590-
.rhs = lhs_len_ref,
14591-
}),
14592-
} },
14593-
});
1459414583

14595-
_ = try block.addBinOp(.memcpy, lhs_dest_slice, lhs);
14584+
// @memcpy(@as(*[lhs.len]T, dst[0..lhs.len]), lhs.ptr)
14585+
if (lhs_len != 0) {
14586+
// [lhs.len]T
14587+
const array_ty = try pt.arrayType(.{
14588+
.child = resolved_elem_ty.toIntern(),
14589+
.len = lhs_len,
14590+
});
14591+
// *[lhs.len]T
14592+
const mutable_ty = try pt.ptrTypeSema(.{
14593+
.child = array_ty.toIntern(),
14594+
.flags = .{ .address_space = ptr_as },
14595+
});
14596+
const lhs_dest_slice = try block.addBitCast(mutable_ty, mutable_alloc);
14597+
14598+
const lhs_src_pointer = if (lhs_ty.isSlice(zcu))
14599+
try block.addInst(.{
14600+
.tag = .slice_ptr,
14601+
.data = .{ .ty_op = .{
14602+
.ty = many_ty_ref,
14603+
.operand = lhs,
14604+
} },
14605+
})
14606+
else
14607+
lhs;
14608+
_ = try block.addBinOp(.memcpy, lhs_dest_slice, lhs_src_pointer);
14609+
}
1459614610

14597-
// rhs_dest_slice = dest[lhs.len..][0..rhs.len]
14598-
const rhs_len_ref = try pt.intRef(.usize, rhs_len);
14599-
const rhs_dest_offset = try block.addInst(.{
14600-
.tag = .ptr_add,
14601-
.data = .{ .ty_pl = .{
14602-
.ty = Air.internedToRef(many_ty.toIntern()),
14603-
.payload = try sema.addExtra(Air.Bin{
14604-
.lhs = many_alloc,
14605-
.rhs = lhs_len_ref,
14606-
}),
14607-
} },
14608-
});
14609-
const rhs_dest_slice = try block.addInst(.{
14610-
.tag = .slice,
14611-
.data = .{ .ty_pl = .{
14612-
.ty = slice_ty_ref,
14613-
.payload = try sema.addExtra(Air.Bin{
14614-
.lhs = rhs_dest_offset,
14615-
.rhs = rhs_len_ref,
14616-
}),
14617-
} },
14618-
});
14611+
if (rhs_len != 0) {
14612+
const many_alloc = try block.addBitCast(many_ty, mutable_alloc);
14613+
const rhs_dest_offset = try block.addInst(.{
14614+
.tag = .ptr_add,
14615+
.data = .{ .ty_pl = .{
14616+
.ty = many_ty_ref,
14617+
.payload = try sema.addExtra(Air.Bin{
14618+
.lhs = many_alloc,
14619+
.rhs = lhs_len_ref,
14620+
}),
14621+
} },
14622+
});
1461914623

14620-
_ = try block.addBinOp(.memcpy, rhs_dest_slice, rhs);
14624+
// [rhs.len]T
14625+
const array_ty = try pt.arrayType(.{
14626+
.child = resolved_elem_ty.toIntern(),
14627+
.len = lhs_len,
14628+
});
14629+
// *[rhs.len]T
14630+
const mutable_ty = try pt.ptrTypeSema(.{
14631+
.child = array_ty.toIntern(),
14632+
.flags = .{ .address_space = ptr_as },
14633+
});
14634+
14635+
const rhs_dest_slice = try block.addBitCast(mutable_ty, rhs_dest_offset);
14636+
14637+
const rhs_src_pointer = if (rhs_ty.isSlice(zcu))
14638+
try block.addInst(.{
14639+
.tag = .slice_ptr,
14640+
.data = .{ .ty_op = .{
14641+
.ty = many_ty_ref,
14642+
.operand = rhs,
14643+
} },
14644+
})
14645+
else
14646+
rhs;
14647+
_ = try block.addBinOp(.memcpy, rhs_dest_slice, rhs_src_pointer);
14648+
}
1462114649

1462214650
if (res_sent_val) |sent_val| {
1462314651
const elem_index = try pt.intRef(.usize, result_len);

test/behavior/array.zig

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ test "array init with concat" {
9292
try expect(std.mem.eql(u8, &i, "abcd"));
9393
}
9494

95+
test "array concat zero length pointers" {
96+
var x: *const [0]u8 = &.{};
97+
_ = &x;
98+
_ = @as([]const u8, "") ++ x;
99+
}
100+
95101
test "array init with mult" {
96102
if (builtin.zig_backend == .stage2_spirv) return error.SkipZigTest;
97103
if (builtin.zig_backend == .stage2_sparc64) return error.SkipZigTest; // TODO

0 commit comments

Comments
 (0)