Commit 8671e8d6d4
src-self-hosted/ir.zig
@@ -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,49 +278,63 @@ 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 {
src-self-hosted/type.zig
@@ -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;
};
src-self-hosted/value.zig
@@ -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.
+ 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,
- bool_type,
- usize_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()) {
+ .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"),
- .bool_type => return out_stream.writeAll("bool"),
- .usize_type => return out_stream.writeAll("usize"),
+ .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,
+ .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"),
- .bool_type => Type.initTag(.@"bool"),
- .usize_type => Type.initTag(.@"usize"),
+ .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,