Skip to content

Commit 7b57c10

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

2 files changed

Lines changed: 81 additions & 39 deletions

File tree

src/Sema.zig

Lines changed: 75 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,83 @@ 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+
const lhs_dest_slice = switch (rhs_len) {
14587+
0 => mutable_alloc,
14588+
else => s: {
14589+
// [lhs.len]T
14590+
const array_ty = try pt.arrayType(.{
14591+
.child = resolved_elem_ty.toIntern(),
14592+
.len = lhs_len,
14593+
});
14594+
// *[lhs.len]T
14595+
const mutable_ty = try pt.ptrTypeSema(.{
14596+
.child = array_ty.toIntern(),
14597+
.flags = .{ .address_space = ptr_as },
14598+
});
14599+
break :s try block.addBitCast(mutable_ty, mutable_alloc);
14600+
},
14601+
};
14602+
const lhs_src_pointer = if (lhs_ty.isSlice(zcu))
14603+
try block.addInst(.{
14604+
.tag = .slice_ptr,
14605+
.data = .{ .ty_op = .{
14606+
.ty = many_ty_ref,
14607+
.operand = lhs,
14608+
} },
14609+
})
14610+
else
14611+
lhs;
14612+
_ = try block.addBinOp(.memcpy, lhs_dest_slice, lhs_src_pointer);
14613+
}
14614+
14615+
if (rhs_len != 0) {
14616+
const rhs_dest_slice = switch (lhs_len) {
14617+
0 => mutable_alloc,
14618+
else => s: {
14619+
const many_alloc = try block.addBitCast(many_ty, mutable_alloc);
14620+
const rhs_dest_offset = try block.addInst(.{
14621+
.tag = .ptr_add,
14622+
.data = .{ .ty_pl = .{
14623+
.ty = many_ty_ref,
14624+
.payload = try sema.addExtra(Air.Bin{
14625+
.lhs = many_alloc,
14626+
.rhs = lhs_len_ref,
14627+
}),
14628+
} },
14629+
});
1459614630

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-
});
14631+
// [rhs.len]T
14632+
const array_ty = try pt.arrayType(.{
14633+
.child = resolved_elem_ty.toIntern(),
14634+
.len = lhs_len,
14635+
});
14636+
// *[rhs.len]T
14637+
const mutable_ty = try pt.ptrTypeSema(.{
14638+
.child = array_ty.toIntern(),
14639+
.flags = .{ .address_space = ptr_as },
14640+
});
1461914641

14620-
_ = try block.addBinOp(.memcpy, rhs_dest_slice, rhs);
14642+
break :s try block.addBitCast(mutable_ty, rhs_dest_offset);
14643+
},
14644+
};
14645+
const rhs_src_pointer = if (rhs_ty.isSlice(zcu))
14646+
try block.addInst(.{
14647+
.tag = .slice_ptr,
14648+
.data = .{ .ty_op = .{
14649+
.ty = many_ty_ref,
14650+
.operand = rhs,
14651+
} },
14652+
})
14653+
else
14654+
rhs;
14655+
_ = try block.addBinOp(.memcpy, rhs_dest_slice, rhs_src_pointer);
14656+
}
1462114657

1462214658
if (res_sent_val) |sent_val| {
1462314659
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)