From b1a86040dd530fd5632b22359eb7534dc2e3f4c9 Mon Sep 17 00:00:00 2001 From: Andrew Kelley Date: Wed, 22 Apr 2020 00:26:37 -0400 Subject: [PATCH] ir: emit zir for fntype --- src-self-hosted/ir/text.zig | 41 +++++++++- src-self-hosted/type.zig | 157 ++++++++++++++++++++++++++++++++++++ 2 files changed, 196 insertions(+), 2 deletions(-) diff --git a/src-self-hosted/ir/text.zig b/src-self-hosted/ir/text.zig index 3c9412f784..f7026d6af7 100644 --- a/src-self-hosted/ir/text.zig +++ b/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}), }, } diff --git a/src-self-hosted/type.zig b/src-self-hosted/type.zig index 2081f4ed5c..151b77791a 100644 --- a/src-self-hosted/type.zig +++ b/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