ir: analyze fieldptr instruction
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user