Commit 28729efe29

Andrew Kelley <andrew@ziglang.org>
2020-04-29 03:40:51
ZIR: implement return instruction
1 parent 6b0f7de
Changed files (5)
lib
std
math
src-self-hosted
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);
     }
 
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).?;
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);
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.
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,