Commit 6ab0ac161e
Changed files (6)
src-self-hosted
src-self-hosted/codegen/c.zig
@@ -85,7 +85,7 @@ fn genArray(file: *C, decl: *Decl) !void {
const name = try map(file.base.allocator, mem.span(decl.name));
defer file.base.allocator.free(name);
if (tv.val.cast(Value.Payload.Bytes)) |payload|
- if (tv.ty.arraySentinel()) |sentinel|
+ if (tv.ty.sentinel()) |sentinel|
if (sentinel.toUnsignedInt() == 0)
try file.constants.writer().print("const char *const {} = \"{}\";\n", .{ name, payload.data })
else
src-self-hosted/codegen.zig
@@ -132,7 +132,7 @@ pub fn generateSymbol(
.Array => {
// TODO populate .debug_info for the array
if (typed_value.val.cast(Value.Payload.Bytes)) |payload| {
- if (typed_value.ty.arraySentinel()) |sentinel| {
+ if (typed_value.ty.sentinel()) |sentinel| {
try code.ensureCapacity(code.items.len + payload.data.len + 1);
code.appendSliceAssumeCapacity(payload.data);
const prev_len = code.items.len;
src-self-hosted/Module.zig
@@ -2591,6 +2591,72 @@ pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) In
return self.fail(scope, src, "TODO implement analysis of iserr", .{});
}
+pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst, start: *Inst, end_opt: ?*Inst, sentinel_opt: ?*Inst) InnerError!*Inst {
+ const ptr_child = switch (array_ptr.ty.zigTypeTag()) {
+ .Pointer => array_ptr.ty.elemType(),
+ else => return self.fail(scope, src, "expected pointer, found '{}'", .{array_ptr.ty}),
+ };
+
+ var array_type = ptr_child;
+ const elem_type = switch (ptr_child.zigTypeTag()) {
+ .Array => ptr_child.elemType(),
+ .Pointer => blk: {
+ if (ptr_child.isSinglePointer()) {
+ if (ptr_child.elemType().zigTypeTag() == .Array) {
+ array_type = ptr_child.elemType();
+ break :blk ptr_child.elemType().elemType();
+ }
+
+ return self.fail(scope, src, "slice of single-item pointer", .{});
+ }
+ break :blk ptr_child.elemType();
+ },
+ else => return self.fail(scope, src, "slice of non-array type '{}'", .{ptr_child}),
+ };
+
+ const slice_sentinel = if (sentinel_opt) |sentinel| blk: {
+ const casted = try self.coerce(scope, elem_type, sentinel);
+ break :blk try self.resolveConstValue(scope, casted);
+ } else null;
+
+ var return_ptr_size: std.builtin.TypeInfo.Pointer.Size = .Slice;
+ var return_elem_type = elem_type;
+ if (end_opt) |end| {
+ if (end.value()) |end_val| {
+ if (start.value()) |start_val| {
+ const start_u64 = start_val.toUnsignedInt();
+ const end_u64 = end_val.toUnsignedInt();
+ if (start_u64 > end_u64) {
+ return self.fail(scope, src, "out of bounds slice", .{});
+ }
+
+ const len = end_u64 - start_u64;
+ const array_sentinel = if (array_type.zigTypeTag() == .Array and end_u64 == array_type.arrayLen())
+ array_type.sentinel()
+ else
+ slice_sentinel;
+ return_elem_type = try self.arrayType(scope, len, array_sentinel, elem_type);
+ return_ptr_size = .One;
+ }
+ }
+ }
+ const return_type = try self.ptrType(
+ scope,
+ src,
+ return_elem_type,
+ if (end_opt == null) slice_sentinel else null,
+ 0, // TODO alignment
+ 0,
+ 0,
+ !ptr_child.isConstPtr(),
+ ptr_child.isAllowzeroPtr(),
+ ptr_child.isVolatilePtr(),
+ return_ptr_size,
+ );
+
+ return self.fail(scope, src, "TODO implement analysis of slice", .{});
+}
+
/// Asserts that lhs and rhs types are both numeric.
pub fn cmpNumeric(
self: *Module,
src-self-hosted/type.zig
@@ -191,8 +191,8 @@ pub const Type = extern union {
return false;
if (!a.elemType().eql(b.elemType()))
return false;
- const sentinel_a = a.arraySentinel();
- const sentinel_b = b.arraySentinel();
+ const sentinel_a = a.sentinel();
+ const sentinel_b = b.sentinel();
if (sentinel_a) |sa| {
if (sentinel_b) |sb| {
return sa.eql(sb);
@@ -630,8 +630,8 @@ pub const Type = extern union {
const payload = @fieldParentPtr(Payload.Pointer, "base", ty.ptr_otherwise);
if (payload.sentinel) |some| switch (payload.size) {
.One, .C => unreachable,
- .Many => try out_stream.writeAll("[*:{}]"),
- .Slice => try out_stream.writeAll("[:{}]"),
+ .Many => try out_stream.print("[*:{}]", .{some}),
+ .Slice => try out_stream.print("[:{}]", .{some}),
} else switch (payload.size) {
.One => try out_stream.writeAll("*"),
.Many => try out_stream.writeAll("[*]"),
@@ -1341,6 +1341,81 @@ pub const Type = extern union {
};
}
+ pub fn isAllowzeroPtr(self: Type) bool {
+ return switch (self.tag()) {
+ .u8,
+ .i8,
+ .u16,
+ .i16,
+ .u32,
+ .i32,
+ .u64,
+ .i64,
+ .usize,
+ .isize,
+ .c_short,
+ .c_ushort,
+ .c_int,
+ .c_uint,
+ .c_long,
+ .c_ulong,
+ .c_longlong,
+ .c_ulonglong,
+ .c_longdouble,
+ .f16,
+ .f32,
+ .f64,
+ .f128,
+ .c_void,
+ .bool,
+ .void,
+ .type,
+ .anyerror,
+ .comptime_int,
+ .comptime_float,
+ .noreturn,
+ .@"null",
+ .@"undefined",
+ .array,
+ .array_sentinel,
+ .array_u8,
+ .array_u8_sentinel_0,
+ .fn_noreturn_no_args,
+ .fn_void_no_args,
+ .fn_naked_noreturn_no_args,
+ .fn_ccc_void_no_args,
+ .function,
+ .int_unsigned,
+ .int_signed,
+ .single_mut_pointer,
+ .single_const_pointer,
+ .many_const_pointer,
+ .many_mut_pointer,
+ .c_const_pointer,
+ .c_mut_pointer,
+ .const_slice,
+ .mut_slice,
+ .single_const_pointer_to_comptime_int,
+ .const_slice_u8,
+ .optional,
+ .optional_single_mut_pointer,
+ .optional_single_const_pointer,
+ .enum_literal,
+ .error_union,
+ .@"anyframe",
+ .anyframe_T,
+ .anyerror_void_error_union,
+ .error_set,
+ .error_set_single,
+ => false,
+
+ .pointer => {
+ const payload = @fieldParentPtr(Payload.Pointer, "base", self.ptr_otherwise);
+ return payload.@"allowzero";
+ },
+ };
+ }
+
/// Asserts that the type is an optional
pub fn isPtrLikeOptional(self: Type) bool {
switch (self.tag()) {
@@ -1585,8 +1660,8 @@ pub const Type = extern union {
};
}
- /// Asserts the type is an array or vector.
- pub fn arraySentinel(self: Type) ?Value {
+ /// Asserts the type is an array, pointer or vector.
+ pub fn sentinel(self: Type) ?Value {
return switch (self.tag()) {
.u8,
.i8,
@@ -1626,16 +1701,8 @@ pub const Type = extern union {
.fn_naked_noreturn_no_args,
.fn_ccc_void_no_args,
.function,
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
.const_slice,
.mut_slice,
- .single_const_pointer_to_comptime_int,
.const_slice_u8,
.int_unsigned,
.int_signed,
@@ -1651,7 +1718,18 @@ pub const Type = extern union {
.error_set_single,
=> unreachable,
- .array, .array_u8 => return null,
+ .single_const_pointer,
+ .single_mut_pointer,
+ .many_const_pointer,
+ .many_mut_pointer,
+ .c_const_pointer,
+ .c_mut_pointer,
+ .single_const_pointer_to_comptime_int,
+ .array,
+ .array_u8,
+ => return null,
+
+ .pointer => return self.cast(Payload.Pointer).?.sentinel,
.array_sentinel => return self.cast(Payload.ArraySentinel).?.sentinel,
.array_u8_sentinel_0 => return Value.initTag(.zero),
};
src-self-hosted/zir.zig
@@ -2596,7 +2596,7 @@ const EmitZIR = struct {
var len_pl = Value.Payload.Int_u64{ .int = ty.arrayLen() };
const len = Value.initPayload(&len_pl.base);
- const inst = if (ty.arraySentinel()) |sentinel| blk: {
+ const inst = if (ty.sentinel()) |sentinel| blk: {
const inst = try self.arena.allocator.create(Inst.ArrayTypeSentinel);
inst.* = .{
.base = .{
src-self-hosted/zir_sema.zig
@@ -1175,11 +1175,19 @@ fn analyzeInstElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.ElemPtr) Inne
}
fn analyzeInstSlice(mod: *Module, scope: *Scope, inst: *zir.Inst.Slice) InnerError!*Inst {
- return mod.fail(scope, inst.base.src, "TODO implement analyzeInstSlice", .{});
+ const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr);
+ const start = try resolveInst(mod, scope, inst.positionals.start);
+ const end = if (inst.kw_args.end) |end| try resolveInst(mod, scope, end) else null;
+ const sentinel = if (inst.kw_args.sentinel) |sentinel| try resolveInst(mod, scope, sentinel) else null;
+
+ return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, end, sentinel);
}
fn analyzeInstSliceStart(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
- return mod.fail(scope, inst.base.src, "TODO implement analyzeInstSliceStart", .{});
+ const array_ptr = try resolveInst(mod, scope, inst.positionals.lhs);
+ const start = try resolveInst(mod, scope, inst.positionals.rhs);
+
+ return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, null, null);
}
fn analyzeInstShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {