Skip to content

Commit 9511dbe

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

File tree

2 files changed

+78
-40
lines changed

2 files changed

+78
-40
lines changed

src/Sema.zig

Lines changed: 72 additions & 40 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,79 @@ 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());
14581+
// only used when both are non-zero lengths
14582+
const many_alloc = if (lhs_len != 0 and rhs_len != 0)
14583+
try block.addBitCast(many_ty, mutable_alloc)
14584+
else
14585+
undefined;
1458014586

14581-
// lhs_dest_slice = dest[0..lhs.len]
14582-
const slice_ty_ref = Air.internedToRef(slice_ty.toIntern());
1458314587
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-
});
14594-
14595-
_ = try block.addBinOp(.memcpy, lhs_dest_slice, lhs);
14588+
const slice_ty_ref = Air.internedToRef(slice_ty.toIntern());
1459614589

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,
14590+
if (lhs_len != 0) {
14591+
const lhs_dest_slice = switch (rhs_len) {
14592+
0 => try block.addTyOp(.array_to_slice, slice_ty, mutable_alloc),
14593+
else => try block.addInst(.{
14594+
.tag = .slice,
14595+
.data = .{ .ty_pl = .{
14596+
.ty = slice_ty_ref,
14597+
.payload = try sema.addExtra(Air.Bin{ .lhs = many_alloc, .rhs = lhs_len_ref }),
14598+
} },
1461614599
}),
14617-
} },
14618-
});
14619-
14620-
_ = try block.addBinOp(.memcpy, rhs_dest_slice, rhs);
14600+
};
14601+
const lhs_src_pointer = if (lhs_ty.isSlice(zcu))
14602+
try block.addInst(.{
14603+
.tag = .slice_ptr,
14604+
.data = .{ .ty_op = .{
14605+
.ty = many_ty_ref,
14606+
.operand = lhs,
14607+
} },
14608+
})
14609+
else
14610+
lhs;
14611+
_ = try block.addBinOp(.memcpy, lhs_dest_slice, lhs_src_pointer);
14612+
}
14613+
14614+
if (rhs_len != 0) {
14615+
const rhs_dest_slice = switch (lhs_len) {
14616+
0 => try block.addTyOp(.array_to_slice, slice_ty, mutable_alloc),
14617+
else => s: {
14618+
const rhs_len_ref = try pt.intRef(.usize, rhs_len);
14619+
const rhs_dest_offset = switch (lhs_len) {
14620+
0 => many_alloc,
14621+
else => try block.addInst(.{
14622+
.tag = .ptr_add,
14623+
.data = .{ .ty_pl = .{
14624+
.ty = many_ty_ref,
14625+
.payload = try sema.addExtra(Air.Bin{ .lhs = many_alloc, .rhs = lhs_len_ref }),
14626+
} },
14627+
}),
14628+
};
14629+
break :s try block.addInst(.{
14630+
.tag = .slice,
14631+
.data = .{ .ty_pl = .{
14632+
.ty = slice_ty_ref,
14633+
.payload = try sema.addExtra(Air.Bin{
14634+
.lhs = rhs_dest_offset,
14635+
.rhs = rhs_len_ref,
14636+
}),
14637+
} },
14638+
});
14639+
},
14640+
};
14641+
const rhs_src_pointer = if (rhs_ty.isSlice(zcu))
14642+
try block.addInst(.{
14643+
.tag = .slice_ptr,
14644+
.data = .{ .ty_op = .{
14645+
.ty = many_ty_ref,
14646+
.operand = rhs,
14647+
} },
14648+
})
14649+
else
14650+
rhs;
14651+
_ = try block.addBinOp(.memcpy, rhs_dest_slice, rhs_src_pointer);
14652+
}
1462114653

1462214654
if (res_sent_val) |sent_val| {
1462314655
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)