authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-14 15:45:15-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-14 16:03:22-04:00
log278829fc2cc23e55b09915ce07ce1ec2dbf7e68b
tree8c9b8a920ece20514e5457e266ed8fd1ac7310ba
parent91636f1e8cc197a310205724458a4e1154530720

self-hosted: adding a fn to an llvm module


10 files changed, 346 insertions(+), 63 deletions(-)

src-self-hosted/codegen.zig created+61
......@@ -0,0 +1,61 @@
1const std = @import("std");
2// TODO codegen pretends that Module is renamed to Build because I plan to
3// do that refactor at some point
4const Build = @import("module.zig").Module;
5// we go through llvm instead of c for 2 reasons:
6// 1. to avoid accidentally calling the non-thread-safe functions
7// 2. patch up some of the types to remove nullability
8const llvm = @import("llvm.zig");
9const ir = @import("ir.zig");
10const Value = @import("value.zig").Value;
11const Type = @import("type.zig").Type;
12const event = std.event;
13
14pub async fn renderToLlvm(build: *Build, fn_val: *Value.Fn, code: *ir.Code) !void {
15 fn_val.base.ref();
16 defer fn_val.base.deref(build);
17 defer code.destroy(build.a());
18
19 const llvm_handle = try build.event_loop_local.getAnyLlvmContext();
20 defer llvm_handle.release(build.event_loop_local);
21
22 const context = llvm_handle.node.data;
23
24 const module = llvm.ModuleCreateWithNameInContext(build.name.ptr(), context) orelse return error.OutOfMemory;
25 defer llvm.DisposeModule(module);
26
27 const builder = llvm.CreateBuilderInContext(context) orelse return error.OutOfMemory;
28 defer llvm.DisposeBuilder(builder);
29
30 var cunit = CompilationUnit{
31 .build = build,
32 .module = module,
33 .builder = builder,
34 .context = context,
35 .lock = event.Lock.init(build.loop),
36 };
37
38 try renderToLlvmModule(&cunit, fn_val, code);
39
40 if (build.verbose_llvm_ir) {
41 llvm.DumpModule(cunit.module);
42 }
43}
44
45pub const CompilationUnit = struct {
46 build: *Build,
47 module: llvm.ModuleRef,
48 builder: llvm.BuilderRef,
49 context: llvm.ContextRef,
50 lock: event.Lock,
51
52 fn a(self: *CompilationUnit) *std.mem.Allocator {
53 return self.build.a();
54 }
55};
56
57pub fn renderToLlvmModule(cunit: *CompilationUnit, fn_val: *Value.Fn, code: *ir.Code) !void {
58 // TODO audit more of codegen.cpp:fn_llvm_value and port more logic
59 const llvm_fn_type = try fn_val.base.typeof.getLlvmType(cunit);
60 const llvm_fn = llvm.AddFunction(cunit.module, fn_val.symbol_name.ptr(), llvm_fn_type);
61}
src-self-hosted/ir.zig+1-8
......@@ -375,15 +375,8 @@ pub const Instruction = struct {
375375
376376 pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Instruction {
377377 const target = try self.params.target.getAsParam();
378
379378 try ira.src_implicit_return_type_list.append(target);
380
381 return ira.irb.build(
382 AddImplicitReturnType,
383 self.base.scope,
384 self.base.span,
385 Params{ .target = target },
386 );
379 return ira.irb.buildConstVoid(self.base.scope, self.base.span, true);
387380 }
388381 };
389382};
src-self-hosted/llvm.zig+20-3
......@@ -2,10 +2,27 @@ const builtin = @import("builtin");
22const c = @import("c.zig");
33const assert = @import("std").debug.assert;
44
5pub const ValueRef = removeNullability(c.LLVMValueRef);
6pub const ModuleRef = removeNullability(c.LLVMModuleRef);
7pub const ContextRef = removeNullability(c.LLVMContextRef);
85pub const BuilderRef = removeNullability(c.LLVMBuilderRef);
6pub const ContextRef = removeNullability(c.LLVMContextRef);
7pub const ModuleRef = removeNullability(c.LLVMModuleRef);
8pub const ValueRef = removeNullability(c.LLVMValueRef);
9pub const TypeRef = removeNullability(c.LLVMTypeRef);
10
11pub const AddFunction = c.LLVMAddFunction;
12pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext;
13pub const DisposeBuilder = c.LLVMDisposeBuilder;
14pub const DisposeModule = c.LLVMDisposeModule;
15pub const DumpModule = c.LLVMDumpModule;
16pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
17pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
18
19pub const FunctionType = LLVMFunctionType;
20extern fn LLVMFunctionType(
21 ReturnType: TypeRef,
22 ParamTypes: [*]TypeRef,
23 ParamCount: c_uint,
24 IsVarArg: c_int,
25) ?TypeRef;
926
1027fn removeNullability(comptime T: type) type {
1128 comptime assert(@typeId(T) == builtin.TypeId.Optional);
src-self-hosted/main.zig+6-1
......@@ -14,6 +14,7 @@ const c = @import("c.zig");
1414const introspect = @import("introspect.zig");
1515const Args = arg.Args;
1616const Flag = arg.Flag;
17const EventLoopLocal = @import("module.zig").EventLoopLocal;
1718const Module = @import("module.zig").Module;
1819const Target = @import("target.zig").Target;
1920const errmsg = @import("errmsg.zig");
......@@ -386,9 +387,13 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
386387
387388 var loop: event.Loop = undefined;
388389 try loop.initMultiThreaded(allocator);
390 defer loop.deinit();
391
392 var event_loop_local = EventLoopLocal.init(&loop);
393 defer event_loop_local.deinit();
389394
390395 var module = try Module.create(
391 &loop,
396 &event_loop_local,
392397 root_name,
393398 root_source_file,
394399 Target.Native,
src-self-hosted/module.zig+77-35
......@@ -25,14 +25,58 @@ const ParsedFile = @import("parsed_file.zig").ParsedFile;
2525const Value = @import("value.zig").Value;
2626const Type = Value.Type;
2727const Span = errmsg.Span;
28const codegen = @import("codegen.zig");
29
30/// Data that is local to the event loop.
31pub const EventLoopLocal = struct {
32 loop: *event.Loop,
33 llvm_handle_pool: std.atomic.Stack(llvm.ContextRef),
34
35 fn init(loop: *event.Loop) EventLoopLocal {
36 return EventLoopLocal{
37 .loop = loop,
38 .llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(),
39 };
40 }
41
42 fn deinit(self: *EventLoopLocal) void {
43 while (self.llvm_handle_pool.pop()) |node| {
44 c.LLVMContextDispose(node.data);
45 self.loop.allocator.destroy(node);
46 }
47 }
48
49 /// Gets an exclusive handle on any LlvmContext.
50 /// Caller must release the handle when done.
51 pub fn getAnyLlvmContext(self: *EventLoopLocal) !LlvmHandle {
52 if (self.llvm_handle_pool.pop()) |node| return LlvmHandle{ .node = node };
53
54 const context_ref = c.LLVMContextCreate() orelse return error.OutOfMemory;
55 errdefer c.LLVMContextDispose(context_ref);
56
57 const node = try self.loop.allocator.create(std.atomic.Stack(llvm.ContextRef).Node{
58 .next = undefined,
59 .data = context_ref,
60 });
61 errdefer self.loop.allocator.destroy(node);
62
63 return LlvmHandle{ .node = node };
64 }
65};
66
67pub const LlvmHandle = struct {
68 node: *std.atomic.Stack(llvm.ContextRef).Node,
69
70 pub fn release(self: LlvmHandle, event_loop_local: *EventLoopLocal) void {
71 event_loop_local.llvm_handle_pool.push(self.node);
72 }
73};
2874
2975pub const Module = struct {
76 event_loop_local: *EventLoopLocal,
3077 loop: *event.Loop,
3178 name: Buffer,
3279 root_src_path: ?[]const u8,
33 llvm_module: llvm.ModuleRef,
34 context: llvm.ContextRef,
35 builder: llvm.BuilderRef,
3680 target: Target,
3781 build_mode: builtin.Mode,
3882 zig_lib_dir: []const u8,
......@@ -187,7 +231,7 @@ pub const Module = struct {
187231 };
188232
189233 pub fn create(
190 loop: *event.Loop,
234 event_loop_local: *EventLoopLocal,
191235 name: []const u8,
192236 root_src_path: ?[]const u8,
193237 target: *const Target,
......@@ -196,29 +240,20 @@ pub const Module = struct {
196240 zig_lib_dir: []const u8,
197241 cache_dir: []const u8,
198242 ) !*Module {
243 const loop = event_loop_local.loop;
244
199245 var name_buffer = try Buffer.init(loop.allocator, name);
200246 errdefer name_buffer.deinit();
201247
202 const context = c.LLVMContextCreate() orelse return error.OutOfMemory;
203 errdefer c.LLVMContextDispose(context);
204
205 const llvm_module = c.LLVMModuleCreateWithNameInContext(name_buffer.ptr(), context) orelse return error.OutOfMemory;
206 errdefer c.LLVMDisposeModule(llvm_module);
207
208 const builder = c.LLVMCreateBuilderInContext(context) orelse return error.OutOfMemory;
209 errdefer c.LLVMDisposeBuilder(builder);
210
211248 const events = try event.Channel(Event).create(loop, 0);
212249 errdefer events.destroy();
213250
214251 const module = try loop.allocator.create(Module{
215252 .loop = loop,
253 .event_loop_local = event_loop_local,
216254 .events = events,
217255 .name = name_buffer,
218256 .root_src_path = root_src_path,
219 .llvm_module = llvm_module,
220 .context = context,
221 .builder = builder,
222257 .target = target.*,
223258 .kind = kind,
224259 .build_mode = build_mode,
......@@ -290,7 +325,7 @@ pub const Module = struct {
290325 .base = Value{
291326 .id = Value.Id.Type,
292327 .typeof = undefined,
293 .ref_count = 3, // 3 because it references itself twice
328 .ref_count = std.atomic.Int(usize).init(3), // 3 because it references itself twice
294329 },
295330 .id = builtin.TypeId.Type,
296331 },
......@@ -305,7 +340,7 @@ pub const Module = struct {
305340 .base = Value{
306341 .id = Value.Id.Type,
307342 .typeof = &Type.MetaType.get(module).base,
308 .ref_count = 1,
343 .ref_count = std.atomic.Int(usize).init(1),
309344 },
310345 .id = builtin.TypeId.Void,
311346 },
......@@ -317,7 +352,7 @@ pub const Module = struct {
317352 .base = Value{
318353 .id = Value.Id.Type,
319354 .typeof = &Type.MetaType.get(module).base,
320 .ref_count = 1,
355 .ref_count = std.atomic.Int(usize).init(1),
321356 },
322357 .id = builtin.TypeId.NoReturn,
323358 },
......@@ -329,7 +364,7 @@ pub const Module = struct {
329364 .base = Value{
330365 .id = Value.Id.Type,
331366 .typeof = &Type.MetaType.get(module).base,
332 .ref_count = 1,
367 .ref_count = std.atomic.Int(usize).init(1),
333368 },
334369 .id = builtin.TypeId.Bool,
335370 },
......@@ -340,7 +375,7 @@ pub const Module = struct {
340375 .base = Value{
341376 .id = Value.Id.Void,
342377 .typeof = &Type.Void.get(module).base,
343 .ref_count = 1,
378 .ref_count = std.atomic.Int(usize).init(1),
344379 },
345380 });
346381 errdefer module.a().destroy(module.void_value);
......@@ -349,7 +384,7 @@ pub const Module = struct {
349384 .base = Value{
350385 .id = Value.Id.Bool,
351386 .typeof = &Type.Bool.get(module).base,
352 .ref_count = 1,
387 .ref_count = std.atomic.Int(usize).init(1),
353388 },
354389 .x = true,
355390 });
......@@ -359,7 +394,7 @@ pub const Module = struct {
359394 .base = Value{
360395 .id = Value.Id.Bool,
361396 .typeof = &Type.Bool.get(module).base,
362 .ref_count = 1,
397 .ref_count = std.atomic.Int(usize).init(1),
363398 },
364399 .x = false,
365400 });
......@@ -369,16 +404,12 @@ pub const Module = struct {
369404 .base = Value{
370405 .id = Value.Id.NoReturn,
371406 .typeof = &Type.NoReturn.get(module).base,
372 .ref_count = 1,
407 .ref_count = std.atomic.Int(usize).init(1),
373408 },
374409 });
375410 errdefer module.a().destroy(module.noreturn_value);
376411 }
377412
378 fn dump(self: *Module) void {
379 c.LLVMDumpModule(self.module);
380 }
381
382413 pub fn destroy(self: *Module) void {
383414 self.noreturn_value.base.deref(self);
384415 self.void_value.base.deref(self);
......@@ -389,9 +420,6 @@ pub const Module = struct {
389420 self.meta_type.base.base.deref(self);
390421
391422 self.events.destroy();
392 c.LLVMDisposeBuilder(self.builder);
393 c.LLVMDisposeModule(self.llvm_module);
394 c.LLVMContextDispose(self.context);
395423 self.name.deinit();
396424
397425 self.a().destroy(self);
......@@ -657,10 +685,19 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void {
657685 const fndef_scope = try Scope.FnDef.create(module, fn_decl.base.parent_scope);
658686 defer fndef_scope.base.deref(module);
659687
660 const fn_type = try Type.Fn.create(module);
688 // TODO actually look at the return type of the AST
689 const return_type = &Type.Void.get(module).base;
690 defer return_type.base.deref(module);
691
692 const is_var_args = false;
693 const params = ([*]Type.Fn.Param)(undefined)[0..0];
694 const fn_type = try Type.Fn.create(module, return_type, params, is_var_args);
661695 defer fn_type.base.base.deref(module);
662696
663 const fn_val = try Value.Fn.create(module, fn_type, fndef_scope);
697 var symbol_name = try std.Buffer.init(module.a(), fn_decl.base.name);
698 errdefer symbol_name.deinit();
699
700 const fn_val = try Value.Fn.create(module, fn_type, fndef_scope, symbol_name);
664701 defer fn_val.base.deref(module);
665702
666703 fn_decl.value = Decl.Fn.Val{ .Ok = fn_val };
......@@ -674,6 +711,7 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void {
674711 ) catch unreachable)) catch |err| switch (err) {
675712 // This poison value should not cause the errdefers to run. It simply means
676713 // that self.compile_errors is populated.
714 // TODO https://github.com/ziglang/zig/issues/769
677715 error.SemanticAnalysisFailed => return {},
678716 else => return err,
679717 };
......@@ -692,14 +730,18 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void {
692730 ) catch unreachable)) catch |err| switch (err) {
693731 // This poison value should not cause the errdefers to run. It simply means
694732 // that self.compile_errors is populated.
733 // TODO https://github.com/ziglang/zig/issues/769
695734 error.SemanticAnalysisFailed => return {},
696735 else => return err,
697736 };
698 defer analyzed_code.destroy(module.a());
737 errdefer analyzed_code.destroy(module.a());
699738
700739 if (module.verbose_ir) {
701740 std.debug.warn("analyzed:\n");
702741 analyzed_code.dump();
703742 }
704 // TODO now render to LLVM module
743
744 // Kick off rendering to LLVM module, but it doesn't block the fn decl
745 // analysis from being complete.
746 try module.build_group.call(codegen.renderToLlvm, module, fn_val, analyzed_code);
705747}
src-self-hosted/test.zig+9-2
......@@ -6,6 +6,7 @@ const Module = @import("module.zig").Module;
66const introspect = @import("introspect.zig");
77const assertOrPanic = std.debug.assertOrPanic;
88const errmsg = @import("errmsg.zig");
9const EventLoopLocal = @import("module.zig").EventLoopLocal;
910
1011test "compile errors" {
1112 var ctx: TestContext = undefined;
......@@ -22,6 +23,7 @@ const allocator = std.heap.c_allocator;
2223
2324pub const TestContext = struct {
2425 loop: std.event.Loop,
26 event_loop_local: EventLoopLocal,
2527 zig_lib_dir: []u8,
2628 zig_cache_dir: []u8,
2729 file_index: std.atomic.Int(usize),
......@@ -34,6 +36,7 @@ pub const TestContext = struct {
3436 self.* = TestContext{
3537 .any_err = {},
3638 .loop = undefined,
39 .event_loop_local = undefined,
3740 .zig_lib_dir = undefined,
3841 .zig_cache_dir = undefined,
3942 .group = undefined,
......@@ -43,6 +46,9 @@ pub const TestContext = struct {
4346 try self.loop.initMultiThreaded(allocator);
4447 errdefer self.loop.deinit();
4548
49 self.event_loop_local = EventLoopLocal.init(&self.loop);
50 errdefer self.event_loop_local.deinit();
51
4652 self.group = std.event.Group(error!void).init(&self.loop);
4753 errdefer self.group.cancelAll();
4854
......@@ -60,6 +66,7 @@ pub const TestContext = struct {
6066 std.os.deleteTree(allocator, tmp_dir_name) catch {};
6167 allocator.free(self.zig_cache_dir);
6268 allocator.free(self.zig_lib_dir);
69 self.event_loop_local.deinit();
6370 self.loop.deinit();
6471 }
6572
......@@ -83,7 +90,7 @@ pub const TestContext = struct {
8390 msg: []const u8,
8491 ) !void {
8592 var file_index_buf: [20]u8 = undefined;
86 const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.next());
93 const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());
8794 const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1);
8895
8996 if (std.os.path.dirname(file1_path)) |dirname| {
......@@ -94,7 +101,7 @@ pub const TestContext = struct {
94101 try std.io.writeFile(allocator, file1_path, source);
95102
96103 var module = try Module.create(
97 &self.loop,
104 &self.event_loop_local,
98105 "test",
99106 file1_path,
100107 Target.Native,
src-self-hosted/type.zig+144-3
......@@ -1,7 +1,10 @@
1const std = @import("std");
12const builtin = @import("builtin");
23const Scope = @import("scope.zig").Scope;
34const Module = @import("module.zig").Module;
45const Value = @import("value.zig").Value;
6const llvm = @import("llvm.zig");
7const CompilationUnit = @import("codegen.zig").CompilationUnit;
58
69pub const Type = struct {
710 base: Value,
......@@ -39,6 +42,36 @@ pub const Type = struct {
3942 }
4043 }
4144
45 pub fn getLlvmType(base: *Type, cunit: *CompilationUnit) (error{OutOfMemory}!llvm.TypeRef) {
46 switch (base.id) {
47 Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(cunit),
48 Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(cunit),
49 Id.Type => unreachable,
50 Id.Void => unreachable,
51 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmType(cunit),
52 Id.NoReturn => unreachable,
53 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmType(cunit),
54 Id.Float => return @fieldParentPtr(Float, "base", base).getLlvmType(cunit),
55 Id.Pointer => return @fieldParentPtr(Pointer, "base", base).getLlvmType(cunit),
56 Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmType(cunit),
57 Id.ComptimeFloat => unreachable,
58 Id.ComptimeInt => unreachable,
59 Id.Undefined => unreachable,
60 Id.Null => unreachable,
61 Id.Optional => return @fieldParentPtr(Optional, "base", base).getLlvmType(cunit),
62 Id.ErrorUnion => return @fieldParentPtr(ErrorUnion, "base", base).getLlvmType(cunit),
63 Id.ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(cunit),
64 Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(cunit),
65 Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(cunit),
66 Id.Namespace => unreachable,
67 Id.Block => unreachable,
68 Id.BoundFn => return @fieldParentPtr(BoundFn, "base", base).getLlvmType(cunit),
69 Id.ArgTuple => unreachable,
70 Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(cunit),
71 Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(cunit),
72 }
73 }
74
4275 pub fn dump(base: *const Type) void {
4376 std.debug.warn("{}", @tagName(base.id));
4477 }
......@@ -54,27 +87,72 @@ pub const Type = struct {
5487 pub fn destroy(self: *Struct, module: *Module) void {
5588 module.a().destroy(self);
5689 }
90
91 pub fn getLlvmType(self: *Struct, cunit: *CompilationUnit) llvm.TypeRef {
92 @panic("TODO");
93 }
5794 };
5895
5996 pub const Fn = struct {
6097 base: Type,
98 return_type: *Type,
99 params: []Param,
100 is_var_args: bool,
61101
62 pub fn create(module: *Module) !*Fn {
63 return module.a().create(Fn{
102 pub const Param = struct {
103 is_noalias: bool,
104 typeof: *Type,
105 };
106
107 pub fn create(module: *Module, return_type: *Type, params: []Param, is_var_args: bool) !*Fn {
108 const result = try module.a().create(Fn{
64109 .base = Type{
65110 .base = Value{
66111 .id = Value.Id.Type,
67112 .typeof = &MetaType.get(module).base,
68 .ref_count = 1,
113 .ref_count = std.atomic.Int(usize).init(1),
69114 },
70115 .id = builtin.TypeId.Fn,
71116 },
117 .return_type = return_type,
118 .params = params,
119 .is_var_args = is_var_args,
72120 });
121 errdefer module.a().destroy(result);
122
123 result.return_type.base.ref();
124 for (result.params) |param| {
125 param.typeof.base.ref();
126 }
127 return result;
73128 }
74129
75130 pub fn destroy(self: *Fn, module: *Module) void {
131 self.return_type.base.deref(module);
132 for (self.params) |param| {
133 param.typeof.base.deref(module);
134 }
76135 module.a().destroy(self);
77136 }
137
138 pub fn getLlvmType(self: *Fn, cunit: *CompilationUnit) !llvm.TypeRef {
139 const llvm_return_type = switch (self.return_type.id) {
140 Type.Id.Void => llvm.VoidTypeInContext(cunit.context) orelse return error.OutOfMemory,
141 else => try self.return_type.getLlvmType(cunit),
142 };
143 const llvm_param_types = try cunit.a().alloc(llvm.TypeRef, self.params.len);
144 defer cunit.a().free(llvm_param_types);
145 for (llvm_param_types) |*llvm_param_type, i| {
146 llvm_param_type.* = try self.params[i].typeof.getLlvmType(cunit);
147 }
148
149 return llvm.FunctionType(
150 llvm_return_type,
151 llvm_param_types.ptr,
152 @intCast(c_uint, llvm_param_types.len),
153 @boolToInt(self.is_var_args),
154 ) orelse error.OutOfMemory;
155 }
78156 };
79157
80158 pub const MetaType = struct {
......@@ -118,6 +196,10 @@ pub const Type = struct {
118196 pub fn destroy(self: *Bool, module: *Module) void {
119197 module.a().destroy(self);
120198 }
199
200 pub fn getLlvmType(self: *Bool, cunit: *CompilationUnit) llvm.TypeRef {
201 @panic("TODO");
202 }
121203 };
122204
123205 pub const NoReturn = struct {
......@@ -140,6 +222,10 @@ pub const Type = struct {
140222 pub fn destroy(self: *Int, module: *Module) void {
141223 module.a().destroy(self);
142224 }
225
226 pub fn getLlvmType(self: *Int, cunit: *CompilationUnit) llvm.TypeRef {
227 @panic("TODO");
228 }
143229 };
144230
145231 pub const Float = struct {
......@@ -148,6 +234,10 @@ pub const Type = struct {
148234 pub fn destroy(self: *Float, module: *Module) void {
149235 module.a().destroy(self);
150236 }
237
238 pub fn getLlvmType(self: *Float, cunit: *CompilationUnit) llvm.TypeRef {
239 @panic("TODO");
240 }
151241 };
152242 pub const Pointer = struct {
153243 base: Type,
......@@ -180,14 +270,24 @@ pub const Type = struct {
180270 ) *Pointer {
181271 @panic("TODO get pointer");
182272 }
273
274 pub fn getLlvmType(self: *Pointer, cunit: *CompilationUnit) llvm.TypeRef {
275 @panic("TODO");
276 }
183277 };
278
184279 pub const Array = struct {
185280 base: Type,
186281
187282 pub fn destroy(self: *Array, module: *Module) void {
188283 module.a().destroy(self);
189284 }
285
286 pub fn getLlvmType(self: *Array, cunit: *CompilationUnit) llvm.TypeRef {
287 @panic("TODO");
288 }
190289 };
290
191291 pub const ComptimeFloat = struct {
192292 base: Type,
193293
......@@ -195,6 +295,7 @@ pub const Type = struct {
195295 module.a().destroy(self);
196296 }
197297 };
298
198299 pub const ComptimeInt = struct {
199300 base: Type,
200301
......@@ -202,6 +303,7 @@ pub const Type = struct {
202303 module.a().destroy(self);
203304 }
204305 };
306
205307 pub const Undefined = struct {
206308 base: Type,
207309
......@@ -209,6 +311,7 @@ pub const Type = struct {
209311 module.a().destroy(self);
210312 }
211313 };
314
212315 pub const Null = struct {
213316 base: Type,
214317
......@@ -216,41 +319,67 @@ pub const Type = struct {
216319 module.a().destroy(self);
217320 }
218321 };
322
219323 pub const Optional = struct {
220324 base: Type,
221325
222326 pub fn destroy(self: *Optional, module: *Module) void {
223327 module.a().destroy(self);
224328 }
329
330 pub fn getLlvmType(self: *Optional, cunit: *CompilationUnit) llvm.TypeRef {
331 @panic("TODO");
332 }
225333 };
334
226335 pub const ErrorUnion = struct {
227336 base: Type,
228337
229338 pub fn destroy(self: *ErrorUnion, module: *Module) void {
230339 module.a().destroy(self);
231340 }
341
342 pub fn getLlvmType(self: *ErrorUnion, cunit: *CompilationUnit) llvm.TypeRef {
343 @panic("TODO");
344 }
232345 };
346
233347 pub const ErrorSet = struct {
234348 base: Type,
235349
236350 pub fn destroy(self: *ErrorSet, module: *Module) void {
237351 module.a().destroy(self);
238352 }
353
354 pub fn getLlvmType(self: *ErrorSet, cunit: *CompilationUnit) llvm.TypeRef {
355 @panic("TODO");
356 }
239357 };
358
240359 pub const Enum = struct {
241360 base: Type,
242361
243362 pub fn destroy(self: *Enum, module: *Module) void {
244363 module.a().destroy(self);
245364 }
365
366 pub fn getLlvmType(self: *Enum, cunit: *CompilationUnit) llvm.TypeRef {
367 @panic("TODO");
368 }
246369 };
370
247371 pub const Union = struct {
248372 base: Type,
249373
250374 pub fn destroy(self: *Union, module: *Module) void {
251375 module.a().destroy(self);
252376 }
377
378 pub fn getLlvmType(self: *Union, cunit: *CompilationUnit) llvm.TypeRef {
379 @panic("TODO");
380 }
253381 };
382
254383 pub const Namespace = struct {
255384 base: Type,
256385
......@@ -273,6 +402,10 @@ pub const Type = struct {
273402 pub fn destroy(self: *BoundFn, module: *Module) void {
274403 module.a().destroy(self);
275404 }
405
406 pub fn getLlvmType(self: *BoundFn, cunit: *CompilationUnit) llvm.TypeRef {
407 @panic("TODO");
408 }
276409 };
277410
278411 pub const ArgTuple = struct {
......@@ -289,6 +422,10 @@ pub const Type = struct {
289422 pub fn destroy(self: *Opaque, module: *Module) void {
290423 module.a().destroy(self);
291424 }
425
426 pub fn getLlvmType(self: *Opaque, cunit: *CompilationUnit) llvm.TypeRef {
427 @panic("TODO");
428 }
292429 };
293430
294431 pub const Promise = struct {
......@@ -297,5 +434,9 @@ pub const Type = struct {
297434 pub fn destroy(self: *Promise, module: *Module) void {
298435 module.a().destroy(self);
299436 }
437
438 pub fn getLlvmType(self: *Promise, cunit: *CompilationUnit) llvm.TypeRef {
439 @panic("TODO");
440 }
300441 };
301442};
src-self-hosted/value.zig+14-6
......@@ -8,15 +8,16 @@ const Module = @import("module.zig").Module;
88pub const Value = struct {
99 id: Id,
1010 typeof: *Type,
11 ref_count: usize,
11 ref_count: std.atomic.Int(usize),
1212
13 /// Thread-safe
1314 pub fn ref(base: *Value) void {
14 base.ref_count += 1;
15 _ = base.ref_count.incr();
1516 }
1617
18 /// Thread-safe
1719 pub fn deref(base: *Value, module: *Module) void {
18 base.ref_count -= 1;
19 if (base.ref_count == 0) {
20 if (base.ref_count.decr() == 1) {
2021 base.typeof.base.deref(module);
2122 switch (base.id) {
2223 Id.Type => @fieldParentPtr(Type, "base", base).destroy(module),
......@@ -52,6 +53,10 @@ pub const Value = struct {
5253 pub const Fn = struct {
5354 base: Value,
5455
56 /// The main external name that is used in the .o file.
57 /// TODO https://github.com/ziglang/zig/issues/265
58 symbol_name: std.Buffer,
59
5560 /// parent should be the top level decls or container decls
5661 fndef_scope: *Scope.FnDef,
5762
......@@ -62,16 +67,18 @@ pub const Value = struct {
6267 block_scope: *Scope.Block,
6368
6469 /// Creates a Fn value with 1 ref
65 pub fn create(module: *Module, fn_type: *Type.Fn, fndef_scope: *Scope.FnDef) !*Fn {
70 /// Takes ownership of symbol_name
71 pub fn create(module: *Module, fn_type: *Type.Fn, fndef_scope: *Scope.FnDef, symbol_name: std.Buffer) !*Fn {
6672 const self = try module.a().create(Fn{
6773 .base = Value{
6874 .id = Value.Id.Fn,
6975 .typeof = &fn_type.base,
70 .ref_count = 1,
76 .ref_count = std.atomic.Int(usize).init(1),
7177 },
7278 .fndef_scope = fndef_scope,
7379 .child_scope = &fndef_scope.base,
7480 .block_scope = undefined,
81 .symbol_name = symbol_name,
7582 });
7683 fn_type.base.base.ref();
7784 fndef_scope.fn_val = self;
......@@ -81,6 +88,7 @@ pub const Value = struct {
8188
8289 pub fn destroy(self: *Fn, module: *Module) void {
8390 self.fndef_scope.base.deref(module);
91 self.symbol_name.deinit();
8492 module.a().destroy(self);
8593 }
8694 };
std/atomic/int.zig+14-4
......@@ -4,16 +4,26 @@ const AtomicOrder = builtin.AtomicOrder;
44/// Thread-safe, lock-free integer
55pub fn Int(comptime T: type) type {
66 return struct {
7 value: T,
7 unprotected_value: T,
88
99 pub const Self = this;
1010
1111 pub fn init(init_val: T) Self {
12 return Self{ .value = init_val };
12 return Self{ .unprotected_value = init_val };
1313 }
1414
15 pub fn next(self: *Self) T {
16 return @atomicRmw(T, &self.value, builtin.AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
15 /// Returns previous value
16 pub fn incr(self: *Self) T {
17 return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);
18 }
19
20 /// Returns previous value
21 pub fn decr(self: *Self) T {
22 return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Sub, 1, AtomicOrder.SeqCst);
23 }
24
25 pub fn get(self: *Self) T {
26 return @atomicLoad(T, &self.unprotected_value, AtomicOrder.SeqCst);
1727 }
1828 };
1929}
std/event/loop.zig-1
......@@ -101,7 +101,6 @@ pub const Loop = struct {
101101 errdefer self.deinitOsData();
102102 }
103103
104 /// must call stop before deinit
105104 pub fn deinit(self: *Loop) void {
106105 self.deinitOsData();
107106 self.allocator.free(self.extra_threads);