Commit b1a86040dd

Andrew Kelley <andrew@ziglang.org>
2020-04-22 06:26:37
ir: emit zir for fntype
1 parent 993e654
Changed files (2)
src-self-hosted
src-self-hosted/ir/text.zig
@@ -880,7 +880,20 @@ const EmitZIR = struct {
                             break :blk &unreach_inst.base;
                         },
                         .constant => unreachable, // excluded from function bodies
-                        .assembly => @panic("TODO emit zir asm instruction"),
+                        .assembly => blk: {
+                            const old_inst = inst.cast(ir.Inst.Assembly).?;
+                            const new_inst = try self.arena.allocator.create(Inst.Asm);
+                            new_inst.* = .{
+                                .base = .{ .src = inst.src, .tag = Inst.Asm.base_tag },
+                                .positionals = .{
+                                    .asm_source = try self.emitStringLiteral(inst.src, old_inst.args.asm_source),
+                                    .return_type = try self.emitType(inst.src, inst.ty),
+                                },
+                                // TODO emit more kw_args
+                                .kw_args = .{},
+                            };
+                            break :blk &new_inst.base;
+                        },
                         .ptrtoint => blk: {
                             const old_inst = inst.cast(ir.Inst.PtrToInt).?;
                             const new_inst = try self.arena.allocator.create(Inst.PtrToInt);
@@ -918,7 +931,7 @@ const EmitZIR = struct {
         }
     }
 
-    pub fn emitType(self: *EmitZIR, src: usize, ty: Type) !*Inst {
+    pub fn emitType(self: *EmitZIR, src: usize, ty: Type) Allocator.Error!*Inst {
         switch (ty.tag()) {
             .isize => return self.emitPrimitiveType(src, .isize),
             .usize => return self.emitPrimitiveType(src, .usize),
@@ -944,6 +957,30 @@ const EmitZIR = struct {
                 .Type => return self.emitPrimitiveType(src, .type),
                 .ComptimeInt => return self.emitPrimitiveType(src, .comptime_int),
                 .ComptimeFloat => return self.emitPrimitiveType(src, .comptime_float),
+                .Fn => {
+                    const param_types = try self.allocator.alloc(Type, ty.fnParamLen());
+                    defer self.allocator.free(param_types);
+
+                    ty.fnParamTypes(param_types);
+                    const emitted_params = try self.arena.allocator.alloc(*Inst, param_types.len);
+                    for (param_types) |param_type, i| {
+                        emitted_params[i] = try self.emitType(src, param_type);
+                    }
+
+                    const fntype_inst = try self.arena.allocator.create(Inst.FnType);
+                    fntype_inst.* = .{
+                        .base = .{ .src = src, .tag = Inst.FnType.base_tag },
+                        .positionals = .{
+                            .param_types = emitted_params,
+                            .return_type = try self.emitType(src, ty.fnReturnType()),
+                        },
+                        .kw_args = .{
+                            .cc = ty.fnCallingConvention(),
+                        },
+                    };
+                    try self.decls.append(&fntype_inst.base);
+                    return &fntype_inst.base;
+                },
                 else => std.debug.panic("TODO implement emitType for {}", .{ty}),
             },
         }
src-self-hosted/type.zig
@@ -422,6 +422,163 @@ pub const Type = extern union {
         };
     }
 
+    /// Asserts the type is a function.
+    pub fn fnParamLen(self: Type) usize {
+        return switch (self.tag()) {
+            .fn_naked_noreturn_no_args => 0,
+
+            .f16,
+            .f32,
+            .f64,
+            .f128,
+            .c_longdouble,
+            .c_void,
+            .bool,
+            .void,
+            .type,
+            .anyerror,
+            .comptime_int,
+            .comptime_float,
+            .noreturn,
+            .array,
+            .single_const_pointer,
+            .single_const_pointer_to_comptime_int,
+            .array_u8_sentinel_0,
+            .const_slice_u8,
+            .u8,
+            .i8,
+            .usize,
+            .isize,
+            .c_short,
+            .c_ushort,
+            .c_int,
+            .c_uint,
+            .c_long,
+            .c_ulong,
+            .c_longlong,
+            .c_ulonglong,
+            => unreachable,
+        };
+    }
+
+    /// Asserts the type is a function. The length of the slice must be at least the length
+    /// given by `fnParamLen`.
+    pub fn fnParamTypes(self: Type, types: []Type) void {
+        switch (self.tag()) {
+            .fn_naked_noreturn_no_args => return,
+
+            .f16,
+            .f32,
+            .f64,
+            .f128,
+            .c_longdouble,
+            .c_void,
+            .bool,
+            .void,
+            .type,
+            .anyerror,
+            .comptime_int,
+            .comptime_float,
+            .noreturn,
+            .array,
+            .single_const_pointer,
+            .single_const_pointer_to_comptime_int,
+            .array_u8_sentinel_0,
+            .const_slice_u8,
+            .u8,
+            .i8,
+            .usize,
+            .isize,
+            .c_short,
+            .c_ushort,
+            .c_int,
+            .c_uint,
+            .c_long,
+            .c_ulong,
+            .c_longlong,
+            .c_ulonglong,
+            => unreachable,
+        }
+    }
+
+    /// Asserts the type is a function.
+    pub fn fnReturnType(self: Type) Type {
+        return switch (self.tag()) {
+            .fn_naked_noreturn_no_args => Type.initTag(.noreturn),
+
+            .f16,
+            .f32,
+            .f64,
+            .f128,
+            .c_longdouble,
+            .c_void,
+            .bool,
+            .void,
+            .type,
+            .anyerror,
+            .comptime_int,
+            .comptime_float,
+            .noreturn,
+            .array,
+            .single_const_pointer,
+            .single_const_pointer_to_comptime_int,
+            .array_u8_sentinel_0,
+            .const_slice_u8,
+            .u8,
+            .i8,
+            .usize,
+            .isize,
+            .c_short,
+            .c_ushort,
+            .c_int,
+            .c_uint,
+            .c_long,
+            .c_ulong,
+            .c_longlong,
+            .c_ulonglong,
+            => unreachable,
+        };
+    }
+
+    /// Asserts the type is a function.
+    pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {
+        return switch (self.tag()) {
+            .fn_naked_noreturn_no_args => .Naked,
+
+            .f16,
+            .f32,
+            .f64,
+            .f128,
+            .c_longdouble,
+            .c_void,
+            .bool,
+            .void,
+            .type,
+            .anyerror,
+            .comptime_int,
+            .comptime_float,
+            .noreturn,
+            .array,
+            .single_const_pointer,
+            .single_const_pointer_to_comptime_int,
+            .array_u8_sentinel_0,
+            .const_slice_u8,
+            .u8,
+            .i8,
+            .usize,
+            .isize,
+            .c_short,
+            .c_ushort,
+            .c_int,
+            .c_uint,
+            .c_long,
+            .c_ulong,
+            .c_longlong,
+            .c_ulonglong,
+            => unreachable,
+        };
+    }
+
     /// This enum does not directly correspond to `std.builtin.TypeId` because
     /// it has extra enum tags in it, as a way of using less memory. For example,
     /// even though Zig recognizes `*align(10) i32` and `*i32` both as Pointer types