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 {
168168 } else if (self.decl_table.get(old_inst)) |kv| {
169169 return kv.value.ptr orelse return error.AnalysisFail;
170170 } 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) {
172172 error.AnalysisFail => {
173173 try self.decl_table.putNoClobber(old_inst, .{ .ptr = null });
174174 return error.AnalysisFail;
......@@ -256,7 +256,14 @@ const Analyze = struct {
256256 });
257257 }
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 {
260267 switch (old_inst.tag) {
261268 .str => {
262269 // We can use this reference because Inst.Const's Value is arena-allocated.
......@@ -271,49 +278,63 @@ const Analyze = struct {
271278 .as => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
272279 .@"asm" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
273280 .@"unreachable" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
274 .@"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 },
281 .@"fn" => return self.analyzeInstFn(func, old_inst.cast(text.Inst.Fn).?),
313282 .@"export" => return self.fail(old_inst.src, "TODO implement analyzing {}", .{@tagName(old_inst.tag)}),
314283 .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));
316335 }
336
337 return self.fail(fntype.base.src, "TODO implement fntype instruction more", .{});
317338 }
318339
319340 fn coerce(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {
src-self-hosted/type.zig+49-3
......@@ -1,6 +1,7 @@
11const std = @import("std");
22const Value = @import("value.zig").Value;
33const assert = std.debug.assert;
4const Allocator = std.mem.Allocator;
45
56/// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication.
67/// It's important for this struct to be small.
......@@ -48,6 +49,8 @@ pub const Type = extern union {
4849 .@"comptime_float" => return .ComptimeFloat,
4950 .@"noreturn" => return .NoReturn,
5051
52 .fn_naked_noreturn_no_args => return .Fn,
53
5154 .array, .array_u8_sentinel_0 => return .Array,
5255 .single_const_pointer => return .Pointer,
5356 .const_slice_u8 => return .Pointer,
......@@ -122,6 +125,7 @@ pub const Type = extern union {
122125 => return out_stream.writeAll(@tagName(t)),
123126
124127 .const_slice_u8 => return out_stream.writeAll("[]const u8"),
128 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
125129
126130 .array_u8_sentinel_0 => {
127131 const payload = @fieldParentPtr(Payload.Array_u8_Sentinel0, "base", ty.ptr_otherwise);
......@@ -144,6 +148,43 @@ pub const Type = extern union {
144148 }
145149 }
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
147188 pub fn isSinglePointer(self: Type) bool {
148189 return switch (self.tag()) {
149190 .@"u8",
......@@ -174,6 +215,7 @@ pub const Type = extern union {
174215 .array,
175216 .array_u8_sentinel_0,
176217 .const_slice_u8,
218 .fn_naked_noreturn_no_args,
177219 => false,
178220
179221 .single_const_pointer => true,
......@@ -210,6 +252,7 @@ pub const Type = extern union {
210252 .array,
211253 .array_u8_sentinel_0,
212254 .single_const_pointer,
255 .fn_naked_noreturn_no_args,
213256 => false,
214257
215258 .const_slice_u8 => true,
......@@ -246,6 +289,7 @@ pub const Type = extern union {
246289 .@"noreturn",
247290 .array,
248291 .array_u8_sentinel_0,
292 .fn_naked_noreturn_no_args,
249293 => unreachable,
250294
251295 .single_const_pointer, .const_slice_u8 => true,
......@@ -280,6 +324,7 @@ pub const Type = extern union {
280324 .@"comptime_int",
281325 .@"comptime_float",
282326 .@"noreturn",
327 .fn_naked_noreturn_no_args,
283328 => unreachable,
284329
285330 .array => self.cast(Payload.Array).?.elem_type,
......@@ -296,7 +341,6 @@ pub const Type = extern union {
296341 /// See `zigTypeTag` for the function that corresponds to `std.builtin.TypeId`.
297342 pub const Tag = enum {
298343 // The first section of this enum are tags that require no payload.
299 const_slice_u8,
300344 @"u8",
301345 @"i8",
302346 @"isize",
......@@ -321,14 +365,16 @@ pub const Type = extern union {
321365 @"anyerror",
322366 @"comptime_int",
323367 @"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.
325371 // After this, the tag requires a payload.
326372
327373 array_u8_sentinel_0,
328374 array,
329375 single_const_pointer,
330376
331 pub const last_no_payload_tag = Tag.@"noreturn";
377 pub const last_no_payload_tag = Tag.const_slice_u8;
332378 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
333379 };
334380
src-self-hosted/value.zig+77-6
......@@ -16,10 +16,34 @@ pub const Value = extern union {
1616
1717 pub const Tag = enum {
1818 // 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,
1938 void_type,
39 type_type,
40 anyerror_type,
41 comptime_int_type,
42 comptime_float_type,
2043 noreturn_type,
21 bool_type,
22 usize_type,
44 fn_naked_noreturn_no_args_type,
45 const_slice_u8_type,
46
2347 void_value,
2448 noreturn_value,
2549 bool_true,
......@@ -74,10 +98,34 @@ pub const Value = extern union {
7498 ) !void {
7599 comptime assert(fmt.len == 0);
76100 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"),
77120 .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"),
78125 .noreturn_type => return out_stream.writeAll("noreturn"),
79 .bool_type => return out_stream.writeAll("bool"),
80 .usize_type => return out_stream.writeAll("usize"),
126 .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
127 .const_slice_u8_type => return out_stream.writeAll("[]const u8"),
128
81129 .void_value => return out_stream.writeAll("{}"),
82130 .noreturn_value => return out_stream.writeAll("unreachable"),
83131 .bool_true => return out_stream.writeAll("true"),
......@@ -105,10 +153,33 @@ pub const Value = extern union {
105153 return switch (self.tag()) {
106154 .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"),
108175 .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"),
109180 .noreturn_type => Type.initTag(.@"noreturn"),
110 .bool_type => Type.initTag(.@"bool"),
111 .usize_type => Type.initTag(.@"usize"),
181 .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),
182 .const_slice_u8_type => Type.initTag(.const_slice_u8),
112183
113184 .void_value,
114185 .noreturn_value,