From b0e89ee499b8110bca6964e996c5862337147e32 Mon Sep 17 00:00:00 2001 From: Jacob G-W Date: Thu, 30 Sep 2021 21:29:52 -0400 Subject: [PATCH 1/2] stage2 llvm backend: implement codegen for Value.repeated --- src/codegen/llvm.zig | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index a1e9f47df4..5954bd0b26 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1021,6 +1021,7 @@ pub const DeclGen = struct { else => |tag| return self.todo("implement const of pointer type '{}' ({})", .{ tv.ty, tag }), }, .Array => { + const gpa = self.gpa; if (tv.val.castTag(.bytes)) |payload| { const zero_sentinel = if (tv.ty.sentinel()) |sentinel| blk: { if (sentinel.tag() == .zero) break :blk true; @@ -1034,7 +1035,6 @@ pub const DeclGen = struct { ); } if (tv.val.castTag(.array)) |payload| { - const gpa = self.gpa; const elem_ty = tv.ty.elemType(); const elem_vals = payload.data; const sento = tv.ty.sentinel(); @@ -1050,6 +1050,23 @@ pub const DeclGen = struct { @intCast(c_uint, llvm_elems.len), ); } + if (tv.val.castTag(.repeated)) |payload| { + const val = payload.data; + const elem_ty = tv.ty.elemType(); + const len = tv.ty.arrayLen(); + + const llvm_elems = try gpa.alloc(*const llvm.Value, len); + defer gpa.free(llvm_elems); + var i: u64 = 0; + while (i < len) : (i += 1) { + llvm_elems[i] = try self.genTypedValue(.{ .ty = elem_ty, .val = val }); + } + const llvm_elem_ty = try self.llvmType(elem_ty); + return llvm_elem_ty.constArray( + llvm_elems.ptr, + @intCast(c_uint, llvm_elems.len), + ); + } return self.todo("handle more array values", .{}); }, .Optional => { From 83dcd9f0386a6bd70cf8d7dee3892f3b8d31d506 Mon Sep 17 00:00:00 2001 From: Jacob G-W Date: Thu, 30 Sep 2021 21:31:46 -0400 Subject: [PATCH 2/2] stage2: emit Value.repeated for `**` where the array size is one This takes advantage of the repeated value. --- src/Sema.zig | 24 +++++++++++++++--------- test/behavior/array.zig | 5 +++++ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/src/Sema.zig b/src/Sema.zig index 7c2ef32ad3..8842a55dcc 100644 --- a/src/Sema.zig +++ b/src/Sema.zig @@ -6189,16 +6189,22 @@ fn zirArrayMul(sema: *Sema, block: *Scope.Block, inst: Zir.Inst.Index) CompileEr try Type.Tag.array.create(anon_decl.arena(), .{ .len = final_len, .elem_type = mulinfo.elem_type }); const buf = try anon_decl.arena().alloc(Value, final_len); - // the actual loop - var i: u64 = 0; - while (i < tomulby) : (i += 1) { - var j: u64 = 0; - while (j < mulinfo.len) : (j += 1) { - const val = try lhs_sub_val.elemValue(sema.arena, j); - buf[mulinfo.len * i + j] = try val.copy(anon_decl.arena()); + // handles the optimisation where arr.len == 0 : [_]T { X } ** N + const val = if (mulinfo.len == 1) blk: { + const copied_val = try (try lhs_sub_val.elemValue(sema.arena, 0)).copy(anon_decl.arena()); + break :blk try Value.Tag.repeated.create(anon_decl.arena(), copied_val); + } else blk: { + // the actual loop + var i: u64 = 0; + while (i < tomulby) : (i += 1) { + var j: u64 = 0; + while (j < mulinfo.len) : (j += 1) { + const val = try lhs_sub_val.elemValue(sema.arena, j); + buf[mulinfo.len * i + j] = try val.copy(anon_decl.arena()); + } } - } - const val = try Value.Tag.array.create(anon_decl.arena(), buf); + break :blk try Value.Tag.array.create(anon_decl.arena(), buf); + }; if (lhs_ty.zigTypeTag() == .Pointer) { return sema.analyzeDeclRef(try anon_decl.finish(final_ty, val)); } else { diff --git a/test/behavior/array.zig b/test/behavior/array.zig index 8250cdea06..9c7282f0f2 100644 --- a/test/behavior/array.zig +++ b/test/behavior/array.zig @@ -32,4 +32,9 @@ test "array init with mult" { const a = 'a'; var i: [8]u8 = [2]u8{ a, 'b' } ** 4; try expect(std.mem.eql(u8, &i, "abababab")); + + // this should cause a Value.repeated to be emitted in AIR. + // TODO: find a way to test that this is actually getting emmited + var j: [4]u8 = [1]u8{'a'} ** 4; + try expect(std.mem.eql(u8, &j, "aaaa")); }