From a3104a4a78089f3260c0dd3f4a96012c6d73a63b Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 12 Oct 2021 21:26:59 -0700 Subject: stage2: fix comptime stores and sentinel-terminated arrays * ZIR: the `array_type_sentinel` now has a source node attached to it for proper error reporting. * Refactor: move `Module.arrayType` to `Type.array` * Value: the `bytes` and `array` tags now include the sentinel, if the type has one. This simplifies comptime evaluation logic. * Sema: fix `zirStructInitEmpty` to properly handle when the type is void or a sentinel-terminated array. This handles the syntax `void{}` and `[0:X]T{}`. * Sema: fix the logic for reporting "cannot store runtime value in compile time variable" as well as for emitting a runtime store when a pointer value is comptime known but it is a global variable. * Sema: implement elemVal for double pointer to array. This can happen with this code for example: `var a: *[1]u8 = undefined; _ = a[0];` * Sema: Rework the `storePtrVal` function to properly handle nested structs and arrays. - Also it now handles comptime stores through a bitcasted pointer. When the pointer element type and the type according to the Decl don't match, the element value is bitcasted before storage. --- src/codegen/llvm.zig | 60 ++++++++++++++++++++++++------------------- src/codegen/llvm/bindings.zig | 2 +- 2 files changed, 34 insertions(+), 28 deletions(-) (limited to 'src/codegen') diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index 458ab093e4..5f461b1276 100644 --- a/src/codegen/llvm.zig +++ b/src/codegen/llvm.zig @@ -1031,54 +1031,60 @@ 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; - return self.todo("handle other sentinel values", .{}); - } else false; - + .Array => switch (tv.val.tag()) { + .bytes => { + const bytes = tv.val.castTag(.bytes).?.data; return self.context.constString( - payload.data.ptr, - @intCast(c_uint, payload.data.len), - llvm.Bool.fromBool(!zero_sentinel), + bytes.ptr, + @intCast(c_uint, bytes.len), + .True, // don't null terminate. bytes has the sentinel, if any. ); - } - if (tv.val.castTag(.array)) |payload| { + }, + .array => { + const elem_vals = tv.val.castTag(.array).?.data; const elem_ty = tv.ty.elemType(); - const elem_vals = payload.data; - const sento = tv.ty.sentinel(); - const llvm_elems = try gpa.alloc(*const llvm.Value, elem_vals.len + @boolToInt(sento != null)); + const gpa = self.gpa; + const llvm_elems = try gpa.alloc(*const llvm.Value, elem_vals.len); defer gpa.free(llvm_elems); for (elem_vals) |elem_val, i| { llvm_elems[i] = try self.genTypedValue(.{ .ty = elem_ty, .val = elem_val }); } - if (sento) |sent| llvm_elems[elem_vals.len] = try self.genTypedValue(.{ .ty = elem_ty, .val = sent }); const llvm_elem_ty = try self.llvmType(elem_ty); return llvm_elem_ty.constArray( llvm_elems.ptr, @intCast(c_uint, llvm_elems.len), ); - } - if (tv.val.castTag(.repeated)) |payload| { - const val = payload.data; + }, + .repeated => { + const val = tv.val.castTag(.repeated).?.data; const elem_ty = tv.ty.elemType(); + const sentinel = tv.ty.sentinel(); const len = tv.ty.arrayLen(); - - const llvm_elems = try gpa.alloc(*const llvm.Value, len); + const len_including_sent = len + @boolToInt(sentinel != null); + const gpa = self.gpa; + const llvm_elems = try gpa.alloc(*const llvm.Value, len_including_sent); 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 }); + for (llvm_elems[0..len]) |*elem| { + elem.* = try self.genTypedValue(.{ .ty = elem_ty, .val = val }); + } + if (sentinel) |sent| { + llvm_elems[len] = try self.genTypedValue(.{ .ty = elem_ty, .val = sent }); } 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", .{}); + }, + .empty_array_sentinel => { + const elem_ty = tv.ty.elemType(); + const sent_val = tv.ty.sentinel().?; + const sentinel = try self.genTypedValue(.{ .ty = elem_ty, .val = sent_val }); + const llvm_elems: [1]*const llvm.Value = .{sentinel}; + const llvm_elem_ty = try self.llvmType(elem_ty); + return llvm_elem_ty.constArray(&llvm_elems, llvm_elems.len); + }, + else => unreachable, }, .Optional => { var buf: Type.Payload.ElemType = undefined; diff --git a/src/codegen/llvm/bindings.zig b/src/codegen/llvm/bindings.zig index f4a6634efb..b019ac177c 100644 --- a/src/codegen/llvm/bindings.zig +++ b/src/codegen/llvm/bindings.zig @@ -194,7 +194,7 @@ pub const Type = opaque { extern fn LLVMConstReal(RealTy: *const Type, N: f64) *const Value; pub const constArray = LLVMConstArray; - extern fn LLVMConstArray(ElementTy: *const Type, ConstantVals: [*]*const Value, Length: c_uint) *const Value; + extern fn LLVMConstArray(ElementTy: *const Type, ConstantVals: [*]const *const Value, Length: c_uint) *const Value; pub const constNamedStruct = LLVMConstNamedStruct; extern fn LLVMConstNamedStruct( -- cgit v1.2.3