From 28729efe2998579fc36a35e5bdab12727ece1e7a Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Tue, 28 Apr 2020 21:40:51 -0400 Subject: [PATCH] ZIR: implement return instruction --- lib/std/math/big/int.zig | 4 ++-- src-self-hosted/ir.zig | 22 ++++++++++++++++++++++ src-self-hosted/ir/text.zig | 27 ++++++++++++++++++++++++--- src-self-hosted/type.zig | 18 ++++++++++++++++++ src-self-hosted/value.zig | 12 ++++++++++++ 5 files changed, 78 insertions(+), 5 deletions(-) diff --git a/lib/std/math/big/int.zig b/lib/std/math/big/int.zig index 7e46e7e9b4..fb22f6621b 100644 --- a/lib/std/math/big/int.zig +++ b/lib/std/math/big/int.zig @@ -62,6 +62,7 @@ pub const Int = struct { /// Hint: use `calcLimbLen` to figure out how big an array to allocate for `limbs`. pub fn initSetFixed(limbs: []Limb, value: var) Int { + mem.set(Limb, limbs, 0); var s = Int.initFixed(limbs); s.set(value) catch unreachable; return s; @@ -126,11 +127,10 @@ pub const Int = struct { /// sufficient capacity, the exact amount will be allocated. This occurs even if the requested /// capacity is only greater than the current capacity by one limb. pub fn ensureCapacity(self: *Int, capacity: usize) !void { - self.assertWritable(); if (capacity <= self.limbs.len) { return; } - + self.assertWritable(); self.limbs = try self.allocator.?.realloc(self.limbs, capacity); } diff --git a/src-self-hosted/ir.zig b/src-self-hosted/ir.zig index b3ac9f7ba1..c4f3bdf579 100644 --- a/src-self-hosted/ir.zig +++ b/src-self-hosted/ir.zig @@ -22,6 +22,7 @@ pub const Inst = struct { pub const Tag = enum { unreach, + ret, constant, assembly, ptrtoint, @@ -58,6 +59,12 @@ pub const Inst = struct { args: void, }; + pub const Ret = struct { + pub const base_tag = Tag.ret; + base: Inst, + args: void, + }; + pub const Constant = struct { pub const base_tag = Tag.constant; base: Inst, @@ -491,6 +498,7 @@ const Analyze = struct { .as => return self.analyzeInstAs(block, old_inst.cast(text.Inst.As).?), .@"asm" => return self.analyzeInstAsm(block, old_inst.cast(text.Inst.Asm).?), .@"unreachable" => return self.analyzeInstUnreachable(block, old_inst.cast(text.Inst.Unreachable).?), + .@"return" => return self.analyzeInstRet(block, old_inst.cast(text.Inst.Return).?), .@"fn" => return self.analyzeInstFn(block, old_inst.cast(text.Inst.Fn).?), .@"export" => { try self.analyzeExport(block, old_inst.cast(text.Inst.Export).?); @@ -556,6 +564,13 @@ const Analyze = struct { return self.constType(fntype.base.src, Type.initTag(.fn_naked_noreturn_no_args)); } + if (return_type.zigTypeTag() == .Void and + fntype.positionals.param_types.len == 0 and + fntype.kw_args.cc == .C) + { + return self.constType(fntype.base.src, Type.initTag(.fn_ccc_void_no_args)); + } + return self.fail(fntype.base.src, "TODO implement fntype instruction more", .{}); } @@ -886,6 +901,11 @@ const Analyze = struct { return self.addNewInstArgs(b, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {}); } + fn analyzeInstRet(self: *Analyze, block: ?*Block, inst: *text.Inst.Return) InnerError!*Inst { + const b = try self.requireRuntimeBlock(block, inst.base.src); + return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.Ret, {}); + } + fn analyzeBody(self: *Analyze, block: ?*Block, body: text.Module.Body) !void { for (body.instructions) |src_inst| { const new_inst = self.analyzeInst(block, src_inst) catch |err| { @@ -1199,11 +1219,13 @@ pub fn main() anyerror!void { const allocator = if (std.builtin.link_libc) std.heap.c_allocator else &arena.allocator; const args = try std.process.argsAlloc(allocator); + defer std.process.argsFree(allocator, args); const src_path = args[1]; const debug_error_trace = true; const source = try std.fs.cwd().readFileAllocOptions(allocator, src_path, std.math.maxInt(u32), 1, 0); + defer allocator.free(source); var zir_module = try text.parse(allocator, source); defer zir_module.deinit(allocator); diff --git a/src-self-hosted/ir/text.zig b/src-self-hosted/ir/text.zig index 7d079f598b..7d444d9310 100644 --- a/src-self-hosted/ir/text.zig +++ b/src-self-hosted/ir/text.zig @@ -26,6 +26,7 @@ pub const Inst = struct { as, @"asm", @"unreachable", + @"return", @"fn", @"export", primitive, @@ -50,6 +51,7 @@ pub const Inst = struct { .as => As, .@"asm" => Asm, .@"unreachable" => Unreachable, + .@"return" => Return, .@"fn" => Fn, .@"export" => Export, .primitive => Primitive, @@ -159,6 +161,14 @@ pub const Inst = struct { kw_args: struct {}, }; + pub const Return = struct { + pub const base_tag = Tag.@"return"; + base: Inst, + + positionals: struct {}, + kw_args: struct {}, + }; + pub const Fn = struct { pub const base_tag = Tag.@"fn"; base: Inst, @@ -417,6 +427,7 @@ pub const Module = struct { .as => return self.writeInstToStreamGeneric(stream, .as, decl, inst_table), .@"asm" => return self.writeInstToStreamGeneric(stream, .@"asm", decl, inst_table), .@"unreachable" => return self.writeInstToStreamGeneric(stream, .@"unreachable", decl, inst_table), + .@"return" => return self.writeInstToStreamGeneric(stream, .@"return", decl, inst_table), .@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", decl, inst_table), .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", decl, inst_table), .primitive => return self.writeInstToStreamGeneric(stream, .primitive, decl, inst_table), @@ -1000,14 +1011,15 @@ const EmitZIR = struct { const fn_type = try self.emitType(src, module_fn.fn_type); + const arena_instrs = try self.arena.allocator.alloc(*Inst, instructions.items.len); + mem.copy(*Inst, arena_instrs, instructions.items); + const fn_inst = try self.arena.allocator.create(Inst.Fn); fn_inst.* = .{ .base = .{ .src = src, .tag = Inst.Fn.base_tag }, .positionals = .{ .fn_type = fn_type, - .body = .{ - .instructions = instructions.toOwnedSlice(), - }, + .body = .{ .instructions = arena_instrs }, }, .kw_args = .{}, }; @@ -1035,6 +1047,15 @@ const EmitZIR = struct { }; break :blk &unreach_inst.base; }, + .ret => blk: { + const ret_inst = try self.arena.allocator.create(Inst.Return); + ret_inst.* = .{ + .base = .{ .src = inst.src, .tag = Inst.Return.base_tag }, + .positionals = .{}, + .kw_args = .{}, + }; + break :blk &ret_inst.base; + }, .constant => unreachable, // excluded from function bodies .assembly => blk: { const old_inst = inst.cast(ir.Inst.Assembly).?; diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index c6551d5bb3..25f726a680 100644 --- a/src-self-hosted/type.zig +++ b/src-self-hosted/type.zig @@ -53,6 +53,7 @@ pub const Type = extern union { .noreturn => return .NoReturn, .fn_naked_noreturn_no_args => return .Fn, + .fn_ccc_void_no_args => return .Fn, .array, .array_u8_sentinel_0 => return .Array, .single_const_pointer => return .Pointer, @@ -184,6 +185,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"), + .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"), .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"), .array_u8_sentinel_0 => { @@ -243,6 +245,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), + .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_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 => { @@ -284,6 +287,7 @@ pub const Type = extern union { .array_u8_sentinel_0, .const_slice_u8, .fn_naked_noreturn_no_args, + .fn_ccc_void_no_args, .int_unsigned, .int_signed, => false, @@ -326,6 +330,7 @@ pub const Type = extern union { .single_const_pointer, .single_const_pointer_to_comptime_int, .fn_naked_noreturn_no_args, + .fn_ccc_void_no_args, .int_unsigned, .int_signed, => false, @@ -365,6 +370,7 @@ pub const Type = extern union { .array, .array_u8_sentinel_0, .fn_naked_noreturn_no_args, + .fn_ccc_void_no_args, .int_unsigned, .int_signed, => unreachable, @@ -405,6 +411,7 @@ pub const Type = extern union { .comptime_float, .noreturn, .fn_naked_noreturn_no_args, + .fn_ccc_void_no_args, .int_unsigned, .int_signed, => unreachable, @@ -445,6 +452,7 @@ pub const Type = extern union { .comptime_float, .noreturn, .fn_naked_noreturn_no_args, + .fn_ccc_void_no_args, .single_const_pointer, .single_const_pointer_to_comptime_int, .const_slice_u8, @@ -474,6 +482,7 @@ pub const Type = extern union { .comptime_float, .noreturn, .fn_naked_noreturn_no_args, + .fn_ccc_void_no_args, .array, .single_const_pointer, .single_const_pointer_to_comptime_int, @@ -516,6 +525,7 @@ pub const Type = extern union { .comptime_float, .noreturn, .fn_naked_noreturn_no_args, + .fn_ccc_void_no_args, .array, .single_const_pointer, .single_const_pointer_to_comptime_int, @@ -570,6 +580,7 @@ pub const Type = extern union { pub fn fnParamLen(self: Type) usize { return switch (self.tag()) { .fn_naked_noreturn_no_args => 0, + .fn_ccc_void_no_args => 0, .f16, .f32, @@ -612,6 +623,7 @@ pub const Type = extern union { pub fn fnParamTypes(self: Type, types: []Type) void { switch (self.tag()) { .fn_naked_noreturn_no_args => return, + .fn_ccc_void_no_args => return, .f16, .f32, @@ -653,6 +665,7 @@ pub const Type = extern union { pub fn fnReturnType(self: Type) Type { return switch (self.tag()) { .fn_naked_noreturn_no_args => Type.initTag(.noreturn), + .fn_ccc_void_no_args => Type.initTag(.void), .f16, .f32, @@ -694,6 +707,7 @@ pub const Type = extern union { pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention { return switch (self.tag()) { .fn_naked_noreturn_no_args => .Naked, + .fn_ccc_void_no_args => .C, .f16, .f32, @@ -763,6 +777,7 @@ pub const Type = extern union { .anyerror, .noreturn, .fn_naked_noreturn_no_args, + .fn_ccc_void_no_args, .array, .single_const_pointer, .single_const_pointer_to_comptime_int, @@ -798,6 +813,7 @@ pub const Type = extern union { .type, .anyerror, .fn_naked_noreturn_no_args, + .fn_ccc_void_no_args, .single_const_pointer_to_comptime_int, .array_u8_sentinel_0, .const_slice_u8, @@ -850,6 +866,7 @@ pub const Type = extern union { .type, .anyerror, .fn_naked_noreturn_no_args, + .fn_ccc_void_no_args, .single_const_pointer_to_comptime_int, .array_u8_sentinel_0, .const_slice_u8, @@ -898,6 +915,7 @@ pub const Type = extern union { comptime_float, noreturn, fn_naked_noreturn_no_args, + fn_ccc_void_no_args, single_const_pointer_to_comptime_int, const_slice_u8, // See last_no_payload_tag below. // After this, the tag requires a payload. diff --git a/src-self-hosted/value.zig b/src-self-hosted/value.zig index 8637fbde10..ea81463c99 100644 --- a/src-self-hosted/value.zig +++ b/src-self-hosted/value.zig @@ -45,6 +45,7 @@ pub const Value = extern union { comptime_float_type, noreturn_type, fn_naked_noreturn_no_args_type, + fn_ccc_void_no_args_type, single_const_pointer_to_comptime_int_type, const_slice_u8_type, @@ -134,6 +135,7 @@ 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"), + .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"), .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"), .const_slice_u8_type => return out_stream.writeAll("[]const u8"), @@ -202,6 +204,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), + .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_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), @@ -253,6 +256,7 @@ pub const Value = extern union { .comptime_float_type, .noreturn_type, .fn_naked_noreturn_no_args_type, + .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, .bool_true, @@ -306,6 +310,7 @@ pub const Value = extern union { .comptime_float_type, .noreturn_type, .fn_naked_noreturn_no_args_type, + .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, .bool_true, @@ -360,6 +365,7 @@ pub const Value = extern union { .comptime_float_type, .noreturn_type, .fn_naked_noreturn_no_args_type, + .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, .bool_true, @@ -419,6 +425,7 @@ pub const Value = extern union { .comptime_float_type, .noreturn_type, .fn_naked_noreturn_no_args_type, + .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, .bool_true, @@ -500,6 +507,7 @@ pub const Value = extern union { .comptime_float_type, .noreturn_type, .fn_naked_noreturn_no_args_type, + .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, .bool_true, @@ -550,6 +558,7 @@ pub const Value = extern union { .comptime_float_type, .noreturn_type, .fn_naked_noreturn_no_args_type, + .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, .bool_true, @@ -639,6 +648,7 @@ pub const Value = extern union { .comptime_float_type, .noreturn_type, .fn_naked_noreturn_no_args_type, + .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, .zero, @@ -691,6 +701,7 @@ pub const Value = extern union { .comptime_float_type, .noreturn_type, .fn_naked_noreturn_no_args_type, + .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, .zero, @@ -754,6 +765,7 @@ pub const Value = extern union { .comptime_float_type, .noreturn_type, .fn_naked_noreturn_no_args_type, + .fn_ccc_void_no_args_type, .single_const_pointer_to_comptime_int_type, .const_slice_u8_type, .zero,