authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 17:06:09-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-04-21 17:06:09-04:00
log8671e8d6d4e570b104014859eaa66d70a0991217
treeded542cd7dda09801d207959136f3492c1f7ab1d
parent22e7ca5613c32b14043dee4531fe8b180bfc407a

ir: analyze fntype instruction


3 files changed, 189 insertions(+), 51 deletions(-)

src-self-hosted/ir.zig+63-42
...@@ -168,7 +168,7 @@ const Analyze = struct {...@@ -168,7 +168,7 @@ const Analyze = struct {
168 } else if (self.decl_table.get(old_inst)) |kv| {168 } else if (self.decl_table.get(old_inst)) |kv| {
169 return kv.value.ptr orelse return error.AnalysisFail;169 return kv.value.ptr orelse return error.AnalysisFail;
170 } else {170 } else {
171 const new_inst = self.analyzeInst(old_inst, null) catch |err| switch (err) {171 const new_inst = self.analyzeInst(null, old_inst) catch |err| switch (err) {
172 error.AnalysisFail => {172 error.AnalysisFail => {
173 try self.decl_table.putNoClobber(old_inst, .{ .ptr = null });173 try self.decl_table.putNoClobber(old_inst, .{ .ptr = null });
174 return error.AnalysisFail;174 return error.AnalysisFail;
...@@ -256,7 +256,14 @@ const Analyze = struct {...@@ -256,7 +256,14 @@ const Analyze = struct {
256 });256 });
257 }257 }
258258
259 fn analyzeInst(self: *Analyze, old_inst: *text.Inst, opt_func: ?*Fn) InnerError!*Inst {259 fn constType(self: *Analyze, src: usize, ty: Type) !*Inst {
260 return self.constInst(src, .{
261 .ty = Type.initTag(.@"type"),
262 .val = try ty.toValue(&self.arena.allocator),
263 });
264 }
265
266 fn analyzeInst(self: *Analyze, func: ?*Fn, old_inst: *text.Inst) InnerError!*Inst {
260 switch (old_inst.tag) {267 switch (old_inst.tag) {
261 .str => {268 .str => {
262 // We can use this reference because Inst.Const's Value is arena-allocated.269 // We can use this reference because Inst.Const's Value is arena-allocated.
...@@ -271,49 +278,63 @@ const Analyze = struct {...@@ -271,49 +278,63 @@ const Analyze = struct {
271 .as => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),278 .as => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
272 .@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),279 .@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
273 .@"unreachable" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),280 .@"unreachable" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
274 .@"fn" => {281 .@"fn" => return self.analyzeInstFn(func, old_inst.cast(text.Inst.Fn).?),
275 const fn_inst = old_inst.cast(text.Inst.Fn).?;
276 const fn_type = try self.resolveType(opt_func, fn_inst.positionals.fn_type);
277
278 var new_func: Fn = .{
279 .body = std.ArrayList(*Inst).init(self.allocator),
280 .inst_table = std.AutoHashMap(*text.Inst, NewInst).init(self.allocator),
281 .fn_index = self.fns.items.len,
282 };
283 defer new_func.body.deinit();
284 defer new_func.inst_table.deinit();
285 // Don't hang on to a reference to this when analyzing body instructions, since the memory
286 // could become invalid.
287 (try self.fns.addOne()).* = .{
288 .analysis_status = .in_progress,
289 .body = undefined,
290 };
291
292 for (fn_inst.positionals.body.instructions) |src_inst| {
293 const new_inst = self.analyzeInst(src_inst, &new_func) catch |err| {
294 self.fns.items[new_func.fn_index].analysis_status = .failure;
295 return err;
296 };
297 try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst });
298 }
299
300 self.fns.items[new_func.fn_index] = .{
301 .analysis_status = .success,
302 .body = new_func.body.toOwnedSlice(),
303 };
304
305 const fn_payload = try self.arena.allocator.create(Value.Payload.Function);
306 fn_payload.* = .{ .index = new_func.fn_index };
307
308 return self.constInst(old_inst.src, .{
309 .ty = fn_type,
310 .val = Value.initPayload(&fn_payload.base),
311 });
312 },
313 .@"export" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),282 .@"export" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
314 .primitive => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),283 .primitive => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
315 .fntype => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),284 .fntype => return self.analyzeInstFnType(func, old_inst.cast(text.Inst.FnType).?),
285 }
286 }
287
288 fn analyzeInstFn(self: *Analyze, opt_func: ?*Fn, fn_inst: *text.Inst.Fn) InnerError!*Inst {
289 const fn_type = try self.resolveType(opt_func, fn_inst.positionals.fn_type);
290
291 var new_func: Fn = .{
292 .body = std.ArrayList(*Inst).init(self.allocator),
293 .inst_table = std.AutoHashMap(*text.Inst, NewInst).init(self.allocator),
294 .fn_index = self.fns.items.len,
295 };
296 defer new_func.body.deinit();
297 defer new_func.inst_table.deinit();
298 // Don't hang on to a reference to this when analyzing body instructions, since the memory
299 // could become invalid.
300 (try self.fns.addOne()).* = .{
301 .analysis_status = .in_progress,
302 .body = undefined,
303 };
304
305 for (fn_inst.positionals.body.instructions) |src_inst| {
306 const new_inst = self.analyzeInst(&new_func, src_inst) catch |err| {
307 self.fns.items[new_func.fn_index].analysis_status = .failure;
308 return err;
309 };
310 try new_func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst });
311 }
312
313 self.fns.items[new_func.fn_index] = .{
314 .analysis_status = .success,
315 .body = new_func.body.toOwnedSlice(),
316 };
317
318 const fn_payload = try self.arena.allocator.create(Value.Payload.Function);
319 fn_payload.* = .{ .index = new_func.fn_index };
320
321 return self.constInst(fn_inst.base.src, .{
322 .ty = fn_type,
323 .val = Value.initPayload(&fn_payload.base),
324 });
325 }
326
327 fn analyzeInstFnType(self: *Analyze, opt_func: ?*Fn, fntype: *text.Inst.FnType) InnerError!*Inst {
328 const return_type = try self.resolveType(opt_func, fntype.positionals.return_type);
329
330 if (return_type.zigTypeTag() == .NoReturn and
331 fntype.positionals.param_types.len == 0 and
332 fntype.kw_args.cc == .Naked)
333 {
334 return self.constType(fntype.base.src, Type.initTag(.fn_naked_noreturn_no_args));
316 }335 }
336
337 return self.fail(fntype.base.src, "TODO implement fntype instruction more", .{});
317 }338 }
318339
319 fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {340 fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
src-self-hosted/type.zig+49-3
...@@ -1,6 +1,7 @@...@@ -1,6 +1,7 @@
1const std = @import("std");1const std = @import("std");
2const Value = @import("value.zig").Value;2const Value = @import("value.zig").Value;
3const assert = std.debug.assert;3const assert = std.debug.assert;
4const Allocator = std.mem.Allocator;
45
5/// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication.6/// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication.
6/// It's important for this struct to be small.7/// It's important for this struct to be small.
...@@ -48,6 +49,8 @@ pub const Type = extern union {...@@ -48,6 +49,8 @@ pub const Type = extern union {
48 .@"comptime_float" => return .ComptimeFloat,49 .@"comptime_float" => return .ComptimeFloat,
49 .@"noreturn" => return .NoReturn,50 .@"noreturn" => return .NoReturn,
5051
52 .fn_naked_noreturn_no_args => return .Fn,
53
51 .array, .array_u8_sentinel_0 => return .Array,54 .array, .array_u8_sentinel_0 => return .Array,
52 .single_const_pointer => return .Pointer,55 .single_const_pointer => return .Pointer,
53 .const_slice_u8 => return .Pointer,56 .const_slice_u8 => return .Pointer,
...@@ -122,6 +125,7 @@ pub const Type = extern union {...@@ -122,6 +125,7 @@ pub const Type = extern union {
122 => return out_stream.writeAll(@tagName(t)),125 => return out_stream.writeAll(@tagName(t)),
123126
124 .const_slice_u8 => return out_stream.writeAll("[]const u8"),127 .const_slice_u8 => return out_stream.writeAll("[]const u8"),
128 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
125129
126 .array_u8_sentinel_0 => {130 .array_u8_sentinel_0 => {
127 const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);131 const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
...@@ -144,6 +148,43 @@ pub const Type = extern union {...@@ -144,6 +148,43 @@ pub const Type = extern union {
144 }148 }
145 }149 }
146150
151 pub fn toValue(self: Type, allocator: *Allocator) Allocator.Error!Value {
152 switch (self.tag()) {
153 .@"u8" => return Value.initTag(.u8_type),
154 .@"i8" => return Value.initTag(.i8_type),
155 .@"isize" => return Value.initTag(.isize_type),
156 .@"usize" => return Value.initTag(.usize_type),
157 .@"c_short" => return Value.initTag(.c_short_type),
158 .@"c_ushort" => return Value.initTag(.c_ushort_type),
159 .@"c_int" => return Value.initTag(.c_int_type),
160 .@"c_uint" => return Value.initTag(.c_uint_type),
161 .@"c_long" => return Value.initTag(.c_long_type),
162 .@"c_ulong" => return Value.initTag(.c_ulong_type),
163 .@"c_longlong" => return Value.initTag(.c_longlong_type),
164 .@"c_ulonglong" => return Value.initTag(.c_ulonglong_type),
165 .@"c_longdouble" => return Value.initTag(.c_longdouble_type),
166 .@"c_void" => return Value.initTag(.c_void_type),
167 .@"f16" => return Value.initTag(.f16_type),
168 .@"f32" => return Value.initTag(.f32_type),
169 .@"f64" => return Value.initTag(.f64_type),
170 .@"f128" => return Value.initTag(.f128_type),
171 .@"bool" => return Value.initTag(.bool_type),
172 .@"void" => return Value.initTag(.void_type),
173 .@"type" => return Value.initTag(.type_type),
174 .@"anyerror" => return Value.initTag(.anyerror_type),
175 .@"comptime_int" => return Value.initTag(.comptime_int_type),
176 .@"comptime_float" => return Value.initTag(.comptime_float_type),
177 .@"noreturn" => return Value.initTag(.noreturn_type),
178 .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type),
179 .const_slice_u8 => return Value.initTag(.const_slice_u8_type),
180 else => {
181 const ty_payload = try allocator.create(Value.Payload.Ty);
182 ty_payload.* = .{ .ty = self };
183 return Value.initPayload(&ty_payload.base);
184 },
185 }
186 }
187
147 pub fn isSinglePointer(self: Type) bool {188 pub fn isSinglePointer(self: Type) bool {
148 return switch (self.tag()) {189 return switch (self.tag()) {
149 .@"u8",190 .@"u8",
...@@ -174,6 +215,7 @@ pub const Type = extern union {...@@ -174,6 +215,7 @@ pub const Type = extern union {
174 .array,215 .array,
175 .array_u8_sentinel_0,216 .array_u8_sentinel_0,
176 .const_slice_u8,217 .const_slice_u8,
218 .fn_naked_noreturn_no_args,
177 => false,219 => false,
178220
179 .single_const_pointer => true,221 .single_const_pointer => true,
...@@ -210,6 +252,7 @@ pub const Type = extern union {...@@ -210,6 +252,7 @@ pub const Type = extern union {
210 .array,252 .array,
211 .array_u8_sentinel_0,253 .array_u8_sentinel_0,
212 .single_const_pointer,254 .single_const_pointer,
255 .fn_naked_noreturn_no_args,
213 => false,256 => false,
214257
215 .const_slice_u8 => true,258 .const_slice_u8 => true,
...@@ -246,6 +289,7 @@ pub const Type = extern union {...@@ -246,6 +289,7 @@ pub const Type = extern union {
246 .@"noreturn",289 .@"noreturn",
247 .array,290 .array,
248 .array_u8_sentinel_0,291 .array_u8_sentinel_0,
292 .fn_naked_noreturn_no_args,
249 => unreachable,293 => unreachable,
250294
251 .single_const_pointer, .const_slice_u8 => true,295 .single_const_pointer, .const_slice_u8 => true,
...@@ -280,6 +324,7 @@ pub const Type = extern union {...@@ -280,6 +324,7 @@ pub const Type = extern union {
280 .@"comptime_int",324 .@"comptime_int",
281 .@"comptime_float",325 .@"comptime_float",
282 .@"noreturn",326 .@"noreturn",
327 .fn_naked_noreturn_no_args,
283 => unreachable,328 => unreachable,
284329
285 .array => self.cast(Payload.Array).?.elem_type,330 .array => self.cast(Payload.Array).?.elem_type,
...@@ -296,7 +341,6 @@ pub const Type = extern union {...@@ -296,7 +341,6 @@ pub const Type = extern union {
296 /// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`.341 /// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`.
297 pub const Tag = enum {342 pub const Tag = enum {
298 // The first section of this enum are tags that require no payload.343 // The first section of this enum are tags that require no payload.
299 const_slice_u8,
300 @"u8",344 @"u8",
301 @"i8",345 @"i8",
302 @"isize",346 @"isize",
...@@ -321,14 +365,16 @@ pub const Type = extern union {...@@ -321,14 +365,16 @@ pub const Type = extern union {
321 @"anyerror",365 @"anyerror",
322 @"comptime_int",366 @"comptime_int",
323 @"comptime_float",367 @"comptime_float",
324 @"noreturn", // See last_no_payload_tag below.368 @"noreturn",
369 fn_naked_noreturn_no_args,
370 const_slice_u8, // See last_no_payload_tag below.
325 // After this, the tag requires a payload.371 // After this, the tag requires a payload.
326372
327 array_u8_sentinel_0,373 array_u8_sentinel_0,
328 array,374 array,
329 single_const_pointer,375 single_const_pointer,
330376
331 pub const last_no_payload_tag = Tag.@"noreturn";377 pub const last_no_payload_tag = Tag.const_slice_u8;
332 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;378 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
333 };379 };
334380
src-self-hosted/value.zig+77-6
...@@ -16,10 +16,34 @@ pub const Value = extern union {...@@ -16,10 +16,34 @@ pub const Value = extern union {
1616
17 pub const Tag = enum {17 pub const Tag = enum {
18 // The first section of this enum are tags that require no payload.18 // The first section of this enum are tags that require no payload.
19 u8_type,
20 i8_type,
21 isize_type,
22 usize_type,
23 c_short_type,
24 c_ushort_type,
25 c_int_type,
26 c_uint_type,
27 c_long_type,
28 c_ulong_type,
29 c_longlong_type,
30 c_ulonglong_type,
31 c_longdouble_type,
32 f16_type,
33 f32_type,
34 f64_type,
35 f128_type,
36 c_void_type,
37 bool_type,
19 void_type,38 void_type,
39 type_type,
40 anyerror_type,
41 comptime_int_type,
42 comptime_float_type,
20 noreturn_type,43 noreturn_type,
21 bool_type,44 fn_naked_noreturn_no_args_type,
22 usize_type,45 const_slice_u8_type,
46
23 void_value,47 void_value,
24 noreturn_value,48 noreturn_value,
25 bool_true,49 bool_true,
...@@ -74,10 +98,34 @@ pub const Value = extern union {...@@ -74,10 +98,34 @@ pub const Value = extern union {
74 ) !void {98 ) !void {
75 comptime assert(fmt.len == 0);99 comptime assert(fmt.len == 0);
76 switch (self.tag()) {100 switch (self.tag()) {
101 .u8_type => return out_stream.writeAll("u8"),
102 .i8_type => return out_stream.writeAll("i8"),
103 .isize_type => return out_stream.writeAll("isize"),
104 .usize_type => return out_stream.writeAll("usize"),
105 .c_short_type => return out_stream.writeAll("c_short"),
106 .c_ushort_type => return out_stream.writeAll("c_ushort"),
107 .c_int_type => return out_stream.writeAll("c_int"),
108 .c_uint_type => return out_stream.writeAll("c_uint"),
109 .c_long_type => return out_stream.writeAll("c_long"),
110 .c_ulong_type => return out_stream.writeAll("c_ulong"),
111 .c_longlong_type => return out_stream.writeAll("c_longlong"),
112 .c_ulonglong_type => return out_stream.writeAll("c_ulonglong"),
113 .c_longdouble_type => return out_stream.writeAll("c_longdouble"),
114 .f16_type => return out_stream.writeAll("f16"),
115 .f32_type => return out_stream.writeAll("f32"),
116 .f64_type => return out_stream.writeAll("f64"),
117 .f128_type => return out_stream.writeAll("f128"),
118 .c_void_type => return out_stream.writeAll("c_void"),
119 .bool_type => return out_stream.writeAll("bool"),
77 .void_type => return out_stream.writeAll("void"),120 .void_type => return out_stream.writeAll("void"),
121 .type_type => return out_stream.writeAll("type"),
122 .anyerror_type => return out_stream.writeAll("anyerror"),
123 .comptime_int_type => return out_stream.writeAll("comptime_int"),
124 .comptime_float_type => return out_stream.writeAll("comptime_float"),
78 .noreturn_type => return out_stream.writeAll("noreturn"),125 .noreturn_type => return out_stream.writeAll("noreturn"),
79 .bool_type => return out_stream.writeAll("bool"),126 .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
80 .usize_type => return out_stream.writeAll("usize"),127 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
128
81 .void_value => return out_stream.writeAll("{}"),129 .void_value => return out_stream.writeAll("{}"),
82 .noreturn_value => return out_stream.writeAll("unreachable"),130 .noreturn_value => return out_stream.writeAll("unreachable"),
83 .bool_true => return out_stream.writeAll("true"),131 .bool_true => return out_stream.writeAll("true"),
...@@ -105,10 +153,33 @@ pub const Value = extern union {...@@ -105,10 +153,33 @@ pub const Value = extern union {
105 return switch (self.tag()) {153 return switch (self.tag()) {
106 .ty => self.cast(Payload.Ty).?.ty,154 .ty => self.cast(Payload.Ty).?.ty,
107155
156 .u8_type => Type.initTag(.@"u8"),
157 .i8_type => Type.initTag(.@"i8"),
158 .isize_type => Type.initTag(.@"isize"),
159 .usize_type => Type.initTag(.@"usize"),
160 .c_short_type => Type.initTag(.@"c_short"),
161 .c_ushort_type => Type.initTag(.@"c_ushort"),
162 .c_int_type => Type.initTag(.@"c_int"),
163 .c_uint_type => Type.initTag(.@"c_uint"),
164 .c_long_type => Type.initTag(.@"c_long"),
165 .c_ulong_type => Type.initTag(.@"c_ulong"),
166 .c_longlong_type => Type.initTag(.@"c_longlong"),
167 .c_ulonglong_type => Type.initTag(.@"c_ulonglong"),
168 .c_longdouble_type => Type.initTag(.@"c_longdouble"),
169 .f16_type => Type.initTag(.@"f16"),
170 .f32_type => Type.initTag(.@"f32"),
171 .f64_type => Type.initTag(.@"f64"),
172 .f128_type => Type.initTag(.@"f128"),
173 .c_void_type => Type.initTag(.@"c_void"),
174 .bool_type => Type.initTag(.@"bool"),
108 .void_type => Type.initTag(.@"void"),175 .void_type => Type.initTag(.@"void"),
176 .type_type => Type.initTag(.@"type"),
177 .anyerror_type => Type.initTag(.@"anyerror"),
178 .comptime_int_type => Type.initTag(.@"comptime_int"),
179 .comptime_float_type => Type.initTag(.@"comptime_float"),
109 .noreturn_type => Type.initTag(.@"noreturn"),180 .noreturn_type => Type.initTag(.@"noreturn"),
110 .bool_type => Type.initTag(.@"bool"),181 .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),
111 .usize_type => Type.initTag(.@"usize"),182 .const_slice_u8_type => Type.initTag(.const_slice_u8),
112183
113 .void_value,184 .void_value,
114 .noreturn_value,185 .noreturn_value,