ir: analyze fntype instruction
This commit is contained in:
@@ -168,7 +168,7 @@ const Analyze = struct {
|
||||
} else if (self.decl_table.get(old_inst)) |kv| {
|
||||
return kv.value.ptr orelse return error.AnalysisFail;
|
||||
} else {
|
||||
const new_inst = self.analyzeInst(old_inst, null) catch |err| switch (err) {
|
||||
const new_inst = self.analyzeInst(null, old_inst) catch |err| switch (err) {
|
||||
error.AnalysisFail => {
|
||||
try self.decl_table.putNoClobber(old_inst, .{ .ptr = null });
|
||||
return error.AnalysisFail;
|
||||
@@ -256,7 +256,14 @@ const Analyze = struct {
|
||||
});
|
||||
}
|
||||
|
||||
fn analyzeInst(self: *Analyze, old_inst: *text.Inst, opt_func: ?*Fn) InnerError!*Inst {
|
||||
fn constType(self: *Analyze, src: usize, ty: Type) !*Inst {
|
||||
return self.constInst(src, .{
|
||||
.ty = Type.initTag(.@"type"),
|
||||
.val = try ty.toValue(&self.arena.allocator),
|
||||
});
|
||||
}
|
||||
|
||||
fn analyzeInst(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) InnerError!*Inst {
|
||||
switch (old_inst.tag) {
|
||||
.str => {
|
||||
// We can use this reference because Inst.Const's Value is arena-allocated.
|
||||
@@ -271,51 +278,65 @@ const Analyze = struct {
|
||||
.as => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
|
||||
.@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
|
||||
.@"unreachable" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
|
||||
.@"fn" => {
|
||||
const fn_inst = old_inst.cast(text.Inst.Fn).?;
|
||||
const fn_type = try self.resolveType(opt_func, fn_inst.positionals.fn_type);
|
||||
|
||||
var new_func: Fn = .{
|
||||
.body = std.ArrayList(*Inst).init(self.allocator),
|
||||
.inst_table = std.AutoHashMap(*text.Inst, NewInst).init(self.allocator),
|
||||
.fn_index = self.fns.items.len,
|
||||
};
|
||||
defer new_func.body.deinit();
|
||||
defer new_func.inst_table.deinit();
|
||||
// Don't hang on to a reference to this when analyzing body instructions, since the memory
|
||||
// could become invalid.
|
||||
(try self.fns.addOne()).* = .{
|
||||
.analysis_status = .in_progress,
|
||||
.body = undefined,
|
||||
};
|
||||
|
||||
for (fn_inst.positionals.body.instructions) |src_inst| {
|
||||
const new_inst = self.analyzeInst(src_inst, &new_func) catch |err| {
|
||||
self.fns.items[new_func.fn_index].analysis_status = .failure;
|
||||
return err;
|
||||
};
|
||||
try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst });
|
||||
}
|
||||
|
||||
self.fns.items[new_func.fn_index] = .{
|
||||
.analysis_status = .success,
|
||||
.body = new_func.body.toOwnedSlice(),
|
||||
};
|
||||
|
||||
const fn_payload = try self.arena.allocator.create(Value.Payload.Function);
|
||||
fn_payload.* = .{ .index = new_func.fn_index };
|
||||
|
||||
return self.constInst(old_inst.src, .{
|
||||
.ty = fn_type,
|
||||
.val = Value.initPayload(&fn_payload.base),
|
||||
});
|
||||
},
|
||||
.@"fn" => return self.analyzeInstFn(func, old_inst.cast(text.Inst.Fn).?),
|
||||
.@"export" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
|
||||
.primitive => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
|
||||
.fntype => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
|
||||
.fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?),
|
||||
}
|
||||
}
|
||||
|
||||
fn analyzeInstFn(self: *Analyze, opt_func: ?*Fn, fn_inst: *text.Inst.Fn) InnerError!*Inst {
|
||||
const fn_type = try self.resolveType(opt_func, fn_inst.positionals.fn_type);
|
||||
|
||||
var new_func: Fn = .{
|
||||
.body = std.ArrayList(*Inst).init(self.allocator),
|
||||
.inst_table = std.AutoHashMap(*text.Inst, NewInst).init(self.allocator),
|
||||
.fn_index = self.fns.items.len,
|
||||
};
|
||||
defer new_func.body.deinit();
|
||||
defer new_func.inst_table.deinit();
|
||||
// Don't hang on to a reference to this when analyzing body instructions, since the memory
|
||||
// could become invalid.
|
||||
(try self.fns.addOne()).* = .{
|
||||
.analysis_status = .in_progress,
|
||||
.body = undefined,
|
||||
};
|
||||
|
||||
for (fn_inst.positionals.body.instructions) |src_inst| {
|
||||
const new_inst = self.analyzeInst(&new_func, src_inst) catch |err| {
|
||||
self.fns.items[new_func.fn_index].analysis_status = .failure;
|
||||
return err;
|
||||
};
|
||||
try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst });
|
||||
}
|
||||
|
||||
self.fns.items[new_func.fn_index] = .{
|
||||
.analysis_status = .success,
|
||||
.body = new_func.body.toOwnedSlice(),
|
||||
};
|
||||
|
||||
const fn_payload = try self.arena.allocator.create(Value.Payload.Function);
|
||||
fn_payload.* = .{ .index = new_func.fn_index };
|
||||
|
||||
return self.constInst(fn_inst.base.src, .{
|
||||
.ty = fn_type,
|
||||
.val = Value.initPayload(&fn_payload.base),
|
||||
});
|
||||
}
|
||||
|
||||
fn analyzeInstFnType(self: *Analyze, opt_func: ?*Fn, fntype: *text.Inst.FnType) InnerError!*Inst {
|
||||
const return_type = try self.resolveType(opt_func, fntype.positionals.return_type);
|
||||
|
||||
if (return_type.zigTypeTag() == .NoReturn and
|
||||
fntype.positionals.param_types.len == 0 and
|
||||
fntype.kw_args.cc == .Naked)
|
||||
{
|
||||
return self.constType(fntype.base.src, Type.initTag(.fn_naked_noreturn_no_args));
|
||||
}
|
||||
|
||||
return self.fail(fntype.base.src, "TODO implement fntype instruction more", .{});
|
||||
}
|
||||
|
||||
fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
|
||||
const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);
|
||||
if (in_memory_result == .ok) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
const std = @import("std");
|
||||
const Value = @import("value.zig").Value;
|
||||
const assert = std.debug.assert;
|
||||
const Allocator = std.mem.Allocator;
|
||||
|
||||
/// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication.
|
||||
/// It's important for this struct to be small.
|
||||
@@ -48,6 +49,8 @@ pub const Type = extern union {
|
||||
.@"comptime_float" => return .ComptimeFloat,
|
||||
.@"noreturn" => return .NoReturn,
|
||||
|
||||
.fn_naked_noreturn_no_args => return .Fn,
|
||||
|
||||
.array, .array_u8_sentinel_0 => return .Array,
|
||||
.single_const_pointer => return .Pointer,
|
||||
.const_slice_u8 => return .Pointer,
|
||||
@@ -122,6 +125,7 @@ pub const Type = extern union {
|
||||
=> return out_stream.writeAll(@tagName(t)),
|
||||
|
||||
.const_slice_u8 => return out_stream.writeAll("[]const u8"),
|
||||
.fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
|
||||
|
||||
.array_u8_sentinel_0 => {
|
||||
const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
|
||||
@@ -144,6 +148,43 @@ pub const Type = extern union {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn toValue(self: Type, allocator: *Allocator) Allocator.Error!Value {
|
||||
switch (self.tag()) {
|
||||
.@"u8" => return Value.initTag(.u8_type),
|
||||
.@"i8" => return Value.initTag(.i8_type),
|
||||
.@"isize" => return Value.initTag(.isize_type),
|
||||
.@"usize" => return Value.initTag(.usize_type),
|
||||
.@"c_short" => return Value.initTag(.c_short_type),
|
||||
.@"c_ushort" => return Value.initTag(.c_ushort_type),
|
||||
.@"c_int" => return Value.initTag(.c_int_type),
|
||||
.@"c_uint" => return Value.initTag(.c_uint_type),
|
||||
.@"c_long" => return Value.initTag(.c_long_type),
|
||||
.@"c_ulong" => return Value.initTag(.c_ulong_type),
|
||||
.@"c_longlong" => return Value.initTag(.c_longlong_type),
|
||||
.@"c_ulonglong" => return Value.initTag(.c_ulonglong_type),
|
||||
.@"c_longdouble" => return Value.initTag(.c_longdouble_type),
|
||||
.@"c_void" => return Value.initTag(.c_void_type),
|
||||
.@"f16" => return Value.initTag(.f16_type),
|
||||
.@"f32" => return Value.initTag(.f32_type),
|
||||
.@"f64" => return Value.initTag(.f64_type),
|
||||
.@"f128" => return Value.initTag(.f128_type),
|
||||
.@"bool" => return Value.initTag(.bool_type),
|
||||
.@"void" => return Value.initTag(.void_type),
|
||||
.@"type" => return Value.initTag(.type_type),
|
||||
.@"anyerror" => return Value.initTag(.anyerror_type),
|
||||
.@"comptime_int" => return Value.initTag(.comptime_int_type),
|
||||
.@"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),
|
||||
.const_slice_u8 => return Value.initTag(.const_slice_u8_type),
|
||||
else => {
|
||||
const ty_payload = try allocator.create(Value.Payload.Ty);
|
||||
ty_payload.* = .{ .ty = self };
|
||||
return Value.initPayload(&ty_payload.base);
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn isSinglePointer(self: Type) bool {
|
||||
return switch (self.tag()) {
|
||||
.@"u8",
|
||||
@@ -174,6 +215,7 @@ pub const Type = extern union {
|
||||
.array,
|
||||
.array_u8_sentinel_0,
|
||||
.const_slice_u8,
|
||||
.fn_naked_noreturn_no_args,
|
||||
=> false,
|
||||
|
||||
.single_const_pointer => true,
|
||||
@@ -210,6 +252,7 @@ pub const Type = extern union {
|
||||
.array,
|
||||
.array_u8_sentinel_0,
|
||||
.single_const_pointer,
|
||||
.fn_naked_noreturn_no_args,
|
||||
=> false,
|
||||
|
||||
.const_slice_u8 => true,
|
||||
@@ -246,6 +289,7 @@ pub const Type = extern union {
|
||||
.@"noreturn",
|
||||
.array,
|
||||
.array_u8_sentinel_0,
|
||||
.fn_naked_noreturn_no_args,
|
||||
=> unreachable,
|
||||
|
||||
.single_const_pointer, .const_slice_u8 => true,
|
||||
@@ -280,6 +324,7 @@ pub const Type = extern union {
|
||||
.@"comptime_int",
|
||||
.@"comptime_float",
|
||||
.@"noreturn",
|
||||
.fn_naked_noreturn_no_args,
|
||||
=> unreachable,
|
||||
|
||||
.array => self.cast(Payload.Array).?.elem_type,
|
||||
@@ -296,7 +341,6 @@ 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.
|
||||
const_slice_u8,
|
||||
@"u8",
|
||||
@"i8",
|
||||
@"isize",
|
||||
@@ -321,14 +365,16 @@ pub const Type = extern union {
|
||||
@"anyerror",
|
||||
@"comptime_int",
|
||||
@"comptime_float",
|
||||
@"noreturn", // See last_no_payload_tag below.
|
||||
@"noreturn",
|
||||
fn_naked_noreturn_no_args,
|
||||
const_slice_u8, // See last_no_payload_tag below.
|
||||
// After this, the tag requires a payload.
|
||||
|
||||
array_u8_sentinel_0,
|
||||
array,
|
||||
single_const_pointer,
|
||||
|
||||
pub const last_no_payload_tag = Tag.@"noreturn";
|
||||
pub const last_no_payload_tag = Tag.const_slice_u8;
|
||||
pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
|
||||
};
|
||||
|
||||
|
||||
@@ -16,10 +16,34 @@ pub const Value = extern union {
|
||||
|
||||
pub const Tag = enum {
|
||||
// The first section of this enum are tags that require no payload.
|
||||
void_type,
|
||||
noreturn_type,
|
||||
bool_type,
|
||||
u8_type,
|
||||
i8_type,
|
||||
isize_type,
|
||||
usize_type,
|
||||
c_short_type,
|
||||
c_ushort_type,
|
||||
c_int_type,
|
||||
c_uint_type,
|
||||
c_long_type,
|
||||
c_ulong_type,
|
||||
c_longlong_type,
|
||||
c_ulonglong_type,
|
||||
c_longdouble_type,
|
||||
f16_type,
|
||||
f32_type,
|
||||
f64_type,
|
||||
f128_type,
|
||||
c_void_type,
|
||||
bool_type,
|
||||
void_type,
|
||||
type_type,
|
||||
anyerror_type,
|
||||
comptime_int_type,
|
||||
comptime_float_type,
|
||||
noreturn_type,
|
||||
fn_naked_noreturn_no_args_type,
|
||||
const_slice_u8_type,
|
||||
|
||||
void_value,
|
||||
noreturn_value,
|
||||
bool_true,
|
||||
@@ -74,10 +98,34 @@ pub const Value = extern union {
|
||||
) !void {
|
||||
comptime assert(fmt.len == 0);
|
||||
switch (self.tag()) {
|
||||
.void_type => return out_stream.writeAll("void"),
|
||||
.noreturn_type => return out_stream.writeAll("noreturn"),
|
||||
.bool_type => return out_stream.writeAll("bool"),
|
||||
.u8_type => return out_stream.writeAll("u8"),
|
||||
.i8_type => return out_stream.writeAll("i8"),
|
||||
.isize_type => return out_stream.writeAll("isize"),
|
||||
.usize_type => return out_stream.writeAll("usize"),
|
||||
.c_short_type => return out_stream.writeAll("c_short"),
|
||||
.c_ushort_type => return out_stream.writeAll("c_ushort"),
|
||||
.c_int_type => return out_stream.writeAll("c_int"),
|
||||
.c_uint_type => return out_stream.writeAll("c_uint"),
|
||||
.c_long_type => return out_stream.writeAll("c_long"),
|
||||
.c_ulong_type => return out_stream.writeAll("c_ulong"),
|
||||
.c_longlong_type => return out_stream.writeAll("c_longlong"),
|
||||
.c_ulonglong_type => return out_stream.writeAll("c_ulonglong"),
|
||||
.c_longdouble_type => return out_stream.writeAll("c_longdouble"),
|
||||
.f16_type => return out_stream.writeAll("f16"),
|
||||
.f32_type => return out_stream.writeAll("f32"),
|
||||
.f64_type => return out_stream.writeAll("f64"),
|
||||
.f128_type => return out_stream.writeAll("f128"),
|
||||
.c_void_type => return out_stream.writeAll("c_void"),
|
||||
.bool_type => return out_stream.writeAll("bool"),
|
||||
.void_type => return out_stream.writeAll("void"),
|
||||
.type_type => return out_stream.writeAll("type"),
|
||||
.anyerror_type => return out_stream.writeAll("anyerror"),
|
||||
.comptime_int_type => return out_stream.writeAll("comptime_int"),
|
||||
.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"),
|
||||
.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"),
|
||||
@@ -105,10 +153,33 @@ pub const Value = extern union {
|
||||
return switch (self.tag()) {
|
||||
.ty => self.cast(Payload.Ty).?.ty,
|
||||
|
||||
.void_type => Type.initTag(.@"void"),
|
||||
.noreturn_type => Type.initTag(.@"noreturn"),
|
||||
.bool_type => Type.initTag(.@"bool"),
|
||||
.u8_type => Type.initTag(.@"u8"),
|
||||
.i8_type => Type.initTag(.@"i8"),
|
||||
.isize_type => Type.initTag(.@"isize"),
|
||||
.usize_type => Type.initTag(.@"usize"),
|
||||
.c_short_type => Type.initTag(.@"c_short"),
|
||||
.c_ushort_type => Type.initTag(.@"c_ushort"),
|
||||
.c_int_type => Type.initTag(.@"c_int"),
|
||||
.c_uint_type => Type.initTag(.@"c_uint"),
|
||||
.c_long_type => Type.initTag(.@"c_long"),
|
||||
.c_ulong_type => Type.initTag(.@"c_ulong"),
|
||||
.c_longlong_type => Type.initTag(.@"c_longlong"),
|
||||
.c_ulonglong_type => Type.initTag(.@"c_ulonglong"),
|
||||
.c_longdouble_type => Type.initTag(.@"c_longdouble"),
|
||||
.f16_type => Type.initTag(.@"f16"),
|
||||
.f32_type => Type.initTag(.@"f32"),
|
||||
.f64_type => Type.initTag(.@"f64"),
|
||||
.f128_type => Type.initTag(.@"f128"),
|
||||
.c_void_type => Type.initTag(.@"c_void"),
|
||||
.bool_type => Type.initTag(.@"bool"),
|
||||
.void_type => Type.initTag(.@"void"),
|
||||
.type_type => Type.initTag(.@"type"),
|
||||
.anyerror_type => Type.initTag(.@"anyerror"),
|
||||
.comptime_int_type => Type.initTag(.@"comptime_int"),
|
||||
.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),
|
||||
.const_slice_u8_type => Type.initTag(.const_slice_u8),
|
||||
|
||||
.void_value,
|
||||
.noreturn_value,
|
||||
|
||||
Reference in New Issue
Block a user