Commit 2c11acf807
src-self-hosted/ir.zig
@@ -382,7 +382,7 @@ const Analyze = struct {
return self.constIntBig(old_inst.src, Type.initTag(.comptime_int), big_int);
},
.ptrtoint => return self.analyzeInstPtrToInt(func, old_inst.cast(text.Inst.PtrToInt).?),
- .fieldptr => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
+ .fieldptr => return self.analyzeInstFieldPtr(func, old_inst.cast(text.Inst.FieldPtr).?),
.deref => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
.as => return self.analyzeInstAs(func, old_inst.cast(text.Inst.As).?),
.@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
@@ -470,6 +470,39 @@ const Analyze = struct {
return self.addNewInstArgs(f, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr });
}
+ fn analyzeInstFieldPtr(self: *Analyze, func: ?*Fn, fieldptr: *text.Inst.FieldPtr) InnerError!*Inst {
+ const object_ptr = try self.resolveInst(func, fieldptr.positionals.object_ptr);
+ const field_name = try self.resolveConstString(func, fieldptr.positionals.field_name);
+
+ const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
+ .Pointer => object_ptr.ty.elemType(),
+ else => return self.fail(fieldptr.base.src, "expected pointer, found '{}'", .{object_ptr.ty}),
+ };
+ switch (elem_ty.zigTypeTag()) {
+ .Array => {
+ if (mem.eql(u8, field_name, "len")) {
+ const len_payload = try self.arena.allocator.create(Value.Payload.Int_u64);
+ len_payload.* = .{ .int = elem_ty.arrayLen() };
+
+ const ref_payload = try self.arena.allocator.create(Value.Payload.RefVal);
+ ref_payload.* = .{ .val = Value.initPayload(&len_payload.base) };
+
+ return self.constInst(fieldptr.base.src, .{
+ .ty = Type.initTag(.single_const_pointer_to_comptime_int),
+ .val = Value.initPayload(&ref_payload.base),
+ });
+ } else {
+ return self.fail(
+ fieldptr.positionals.field_name.src,
+ "no member named '{}' in '{}'",
+ .{ field_name, elem_ty },
+ );
+ }
+ },
+ else => return self.fail(fieldptr.base.src, "type '{}' does not support field access", .{elem_ty}),
+ }
+ }
+
fn analyzeInstIntCast(self: *Analyze, func: ?*Fn, intcast: *text.Inst.IntCast) InnerError!*Inst {
const dest_type = try self.resolveType(func, intcast.positionals.dest_type);
const new_inst = try self.resolveInst(func, intcast.positionals.value);
src-self-hosted/type.zig
@@ -54,6 +54,7 @@ pub const Type = extern union {
.array, .array_u8_sentinel_0 => return .Array,
.single_const_pointer => return .Pointer,
+ .single_const_pointer_to_comptime_int => return .Pointer,
.const_slice_u8 => return .Pointer,
}
}
@@ -127,6 +128,7 @@ pub const Type = extern union {
.const_slice_u8 => return out_stream.writeAll("[]const u8"),
.fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
+ .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
.array_u8_sentinel_0 => {
const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
@@ -177,6 +179,7 @@ pub const Type = extern union {
.@"comptime_float" => return Value.initTag(.comptime_float_type),
.@"noreturn" => return Value.initTag(.noreturn_type),
.fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type),
+ .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
.const_slice_u8 => return Value.initTag(.const_slice_u8_type),
else => {
const ty_payload = try allocator.create(Value.Payload.Ty);
@@ -219,7 +222,9 @@ pub const Type = extern union {
.fn_naked_noreturn_no_args,
=> false,
- .single_const_pointer => true,
+ .single_const_pointer,
+ .single_const_pointer_to_comptime_int,
+ => true,
};
}
@@ -253,6 +258,7 @@ pub const Type = extern union {
.array,
.array_u8_sentinel_0,
.single_const_pointer,
+ .single_const_pointer_to_comptime_int,
.fn_naked_noreturn_no_args,
=> false,
@@ -293,7 +299,10 @@ pub const Type = extern union {
.fn_naked_noreturn_no_args,
=> unreachable,
- .single_const_pointer, .const_slice_u8 => true,
+ .single_const_pointer,
+ .single_const_pointer_to_comptime_int,
+ .const_slice_u8,
+ => true,
};
}
@@ -330,7 +339,47 @@ pub const Type = extern union {
.array => self.cast(Payload.Array).?.elem_type,
.single_const_pointer => self.cast(Payload.SingleConstPointer).?.pointee_type,
- .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.@"u8"),
+ .array_u8_sentinel_0, .const_slice_u8 => Type.initTag(.u8),
+ .single_const_pointer_to_comptime_int => Type.initTag(.comptime_int),
+ };
+ }
+
+ /// Asserts the type is an array.
+ pub fn arrayLen(self: Type) u64 {
+ return switch (self.tag()) {
+ .u8,
+ .i8,
+ .isize,
+ .usize,
+ .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,
+ .fn_naked_noreturn_no_args,
+ .single_const_pointer,
+ .single_const_pointer_to_comptime_int,
+ .const_slice_u8,
+ => unreachable,
+
+ .array => self.cast(Payload.Array).?.len,
+ .array_u8_sentinel_0 => self.cast(Payload.Array_u8_Sentinel0).?.len,
};
}
@@ -353,6 +402,7 @@ pub const Type = extern union {
.fn_naked_noreturn_no_args,
.array,
.single_const_pointer,
+ .single_const_pointer_to_comptime_int,
.array_u8_sentinel_0,
.const_slice_u8,
=> unreachable,
@@ -380,32 +430,33 @@ pub const Type = extern union {
/// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`.
pub const Tag = enum {
// The first section of this enum are tags that require no payload.
- @"u8",
- @"i8",
- @"isize",
- @"usize",
- @"c_short",
- @"c_ushort",
- @"c_int",
- @"c_uint",
- @"c_long",
- @"c_ulong",
- @"c_longlong",
- @"c_ulonglong",
- @"c_longdouble",
- @"c_void",
- @"f16",
- @"f32",
- @"f64",
- @"f128",
- @"bool",
- @"void",
- @"type",
- @"anyerror",
- @"comptime_int",
- @"comptime_float",
- @"noreturn",
+ u8,
+ i8,
+ isize,
+ usize,
+ c_short,
+ c_ushort,
+ c_int,
+ c_uint,
+ c_long,
+ c_ulong,
+ c_longlong,
+ c_ulonglong,
+ c_longdouble,
+ c_void,
+ f16,
+ f32,
+ f64,
+ f128,
+ bool,
+ void,
+ type,
+ anyerror,
+ comptime_int,
+ comptime_float,
+ noreturn,
fn_naked_noreturn_no_args,
+ single_const_pointer_to_comptime_int,
const_slice_u8, // See last_no_payload_tag below.
// After this, the tag requires a payload.
src-self-hosted/value.zig
@@ -44,6 +44,7 @@ pub const Value = extern union {
comptime_float_type,
noreturn_type,
fn_naked_noreturn_no_args_type,
+ single_const_pointer_to_comptime_int_type,
const_slice_u8_type,
void_value,
@@ -58,6 +59,7 @@ pub const Value = extern union {
int_big,
function,
ref,
+ ref_val,
bytes,
pub const last_no_payload_tag = Tag.bool_false;
@@ -100,7 +102,8 @@ pub const Value = extern union {
out_stream: var,
) !void {
comptime assert(fmt.len == 0);
- switch (self.tag()) {
+ var val = self;
+ while (true) switch (val.tag()) {
.u8_type => return out_stream.writeAll("u8"),
.i8_type => return out_stream.writeAll("i8"),
.isize_type => return out_stream.writeAll("isize"),
@@ -127,20 +130,26 @@ pub const Value = extern union {
.comptime_float_type => return out_stream.writeAll("comptime_float"),
.noreturn_type => return out_stream.writeAll("noreturn"),
.fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
+ .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
.const_slice_u8_type => return out_stream.writeAll("[]const u8"),
.void_value => return out_stream.writeAll("{}"),
.noreturn_value => return out_stream.writeAll("unreachable"),
.bool_true => return out_stream.writeAll("true"),
.bool_false => return out_stream.writeAll("false"),
- .ty => return self.cast(Payload.Ty).?.ty.format("", options, out_stream),
- .int_u64 => return std.fmt.formatIntValue(self.cast(Payload.Int_u64).?.int, "", options, out_stream),
- .int_i64 => return std.fmt.formatIntValue(self.cast(Payload.Int_i64).?.int, "", options, out_stream),
- .int_big => return out_stream.print("{}", .{self.cast(Payload.IntBig).?.big_int}),
+ .ty => return val.cast(Payload.Ty).?.ty.format("", options, out_stream),
+ .int_u64 => return std.fmt.formatIntValue(val.cast(Payload.Int_u64).?.int, "", options, out_stream),
+ .int_i64 => return std.fmt.formatIntValue(val.cast(Payload.Int_i64).?.int, "", options, out_stream),
+ .int_big => return out_stream.print("{}", .{val.cast(Payload.IntBig).?.big_int}),
.function => return out_stream.writeAll("(function)"),
.ref => return out_stream.writeAll("(ref)"),
+ .ref_val => {
+ try out_stream.writeAll("*const ");
+ val = val.cast(Payload.RefVal).?.val;
+ continue;
+ },
.bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream),
- }
+ };
}
/// Asserts that the value is representable as an array of bytes.
@@ -183,6 +192,7 @@ pub const Value = extern union {
.comptime_float_type => Type.initTag(.@"comptime_float"),
.noreturn_type => Type.initTag(.@"noreturn"),
.fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),
+ .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
.const_slice_u8_type => Type.initTag(.const_slice_u8),
.void_value,
@@ -194,6 +204,7 @@ pub const Value = extern union {
.int_big,
.function,
.ref,
+ .ref_val,
.bytes,
=> unreachable,
};
@@ -229,6 +240,7 @@ pub const Value = extern union {
.comptime_float_type,
.noreturn_type,
.fn_naked_noreturn_no_args_type,
+ .single_const_pointer_to_comptime_int_type,
.const_slice_u8_type,
.void_value,
.noreturn_value,
@@ -236,6 +248,7 @@ pub const Value = extern union {
.bool_false,
.function,
.ref,
+ .ref_val,
.bytes,
=> unreachable,
@@ -311,6 +324,11 @@ pub const Value = extern union {
pointee: *MemoryCell,
};
+ pub const RefVal = struct {
+ base: Payload = Payload{ .tag = .ref_val },
+ val: Value,
+ };
+
pub const Bytes = struct {
base: Payload = Payload{ .tag = .bytes },
data: []const u8,