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 {...@@ -375,15 +375,8 @@ pub const Instruction = struct {
375375
376 pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Instruction {376 pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Instruction {
377 const target = try self.params.target.getAsParam();377 const target = try self.params.target.getAsParam();
378
379 try ira.src_implicit_return_type_list.append(target);378 try ira.src_implicit_return_type_list.append(target);
380379 return ira.irb.buildConstVoid(self.base.scope, self.base.span, true);
381 return ira.irb.build(
382 AddImplicitReturnType,
383 self.base.scope,
384 self.base.span,
385 Params{ .target = target },
386 );
387 }380 }
388 };381 };
389};382};
src-self-hosted/llvm.zig+20-3
...@@ -2,10 +2,27 @@ const builtin = @import("builtin");...@@ -2,10 +2,27 @@ const builtin = @import("builtin");
2const c = @import("c.zig");2const c = @import("c.zig");
3const assert = @import("std").debug.assert;3const assert = @import("std").debug.assert;
44
5pub const ValueRef = removeNullability(c.LLVMValueRef);
6pub const ModuleRef = removeNullability(c.LLVMModuleRef);
7pub const ContextRef = removeNullability(c.LLVMContextRef);
8pub const BuilderRef = removeNullability(c.LLVMBuilderRef);5pub 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
10fn removeNullability(comptime T: type) type {27fn removeNullability(comptime T: type) type {
11 comptime assert(@typeId(T) == builtin.TypeId.Optional);28 comptime assert(@typeId(T) == builtin.TypeId.Optional);
src-self-hosted/main.zig+6-1
...@@ -14,6 +14,7 @@ const c = @import("c.zig");...@@ -14,6 +14,7 @@ const c = @import("c.zig");
14const introspect = @import("introspect.zig");14const introspect = @import("introspect.zig");
15const Args = arg.Args;15const Args = arg.Args;
16const Flag = arg.Flag;16const Flag = arg.Flag;
17const EventLoopLocal = @import("module.zig").EventLoopLocal;
17const Module = @import("module.zig").Module;18const Module = @import("module.zig").Module;
18const Target = @import("target.zig").Target;19const Target = @import("target.zig").Target;
19const errmsg = @import("errmsg.zig");20const errmsg = @import("errmsg.zig");
...@@ -386,9 +387,13 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo...@@ -386,9 +387,13 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo
386387
387 var loop: event.Loop = undefined;388 var loop: event.Loop = undefined;
388 try loop.initMultiThreaded(allocator);389 try loop.initMultiThreaded(allocator);
390 defer loop.deinit();
391
392 var event_loop_local = EventLoopLocal.init(&loop);
393 defer event_loop_local.deinit();
389394
390 var module = try Module.create(395 var module = try Module.create(
391 &loop,396 &event_loop_local,
392 root_name,397 root_name,
393 root_source_file,398 root_source_file,
394 Target.Native,399 Target.Native,
src-self-hosted/module.zig+77-35
...@@ -25,14 +25,58 @@ const ParsedFile = @import("parsed_file.zig").ParsedFile;...@@ -25,14 +25,58 @@ const ParsedFile = @import("parsed_file.zig").ParsedFile;
25const Value = @import("value.zig").Value;25const Value = @import("value.zig").Value;
26const Type = Value.Type;26const Type = Value.Type;
27const Span = errmsg.Span;27const 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
29pub const Module = struct {75pub const Module = struct {
76 event_loop_local: *EventLoopLocal,
30 loop: *event.Loop,77 loop: *event.Loop,
31 name: Buffer,78 name: Buffer,
32 root_src_path: ?[]const u8,79 root_src_path: ?[]const u8,
33 llvm_module: llvm.ModuleRef,
34 context: llvm.ContextRef,
35 builder: llvm.BuilderRef,
36 target: Target,80 target: Target,
37 build_mode: builtin.Mode,81 build_mode: builtin.Mode,
38 zig_lib_dir: []const u8,82 zig_lib_dir: []const u8,
...@@ -187,7 +231,7 @@ pub const Module = struct {...@@ -187,7 +231,7 @@ pub const Module = struct {
187 };231 };
188232
189 pub fn create(233 pub fn create(
190 loop: *event.Loop,234 event_loop_local: *EventLoopLocal,
191 name: []const u8,235 name: []const u8,
192 root_src_path: ?[]const u8,236 root_src_path: ?[]const u8,
193 target: *const Target,237 target: *const Target,
...@@ -196,29 +240,20 @@ pub const Module = struct {...@@ -196,29 +240,20 @@ pub const Module = struct {
196 zig_lib_dir: []const u8,240 zig_lib_dir: []const u8,
197 cache_dir: []const u8,241 cache_dir: []const u8,
198 ) !*Module {242 ) !*Module {
243 const loop = event_loop_local.loop;
244
199 var name_buffer = try Buffer.init(loop.allocator, name);245 var name_buffer = try Buffer.init(loop.allocator, name);
200 errdefer name_buffer.deinit();246 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
211 const events = try event.Channel(Event).create(loop, 0);248 const events = try event.Channel(Event).create(loop, 0);
212 errdefer events.destroy();249 errdefer events.destroy();
213250
214 const module = try loop.allocator.create(Module{251 const module = try loop.allocator.create(Module{
215 .loop = loop,252 .loop = loop,
253 .event_loop_local = event_loop_local,
216 .events = events,254 .events = events,
217 .name = name_buffer,255 .name = name_buffer,
218 .root_src_path = root_src_path,256 .root_src_path = root_src_path,
219 .llvm_module = llvm_module,
220 .context = context,
221 .builder = builder,
222 .target = target.*,257 .target = target.*,
223 .kind = kind,258 .kind = kind,
224 .build_mode = build_mode,259 .build_mode = build_mode,
...@@ -290,7 +325,7 @@ pub const Module = struct {...@@ -290,7 +325,7 @@ pub const Module = struct {
290 .base = Value{325 .base = Value{
291 .id = Value.Id.Type,326 .id = Value.Id.Type,
292 .typeof = undefined,327 .typeof = undefined,
293 .ref_count = 3, // 3 because it references itself twice328 .ref_count = std.atomic.Int(usize).init(3), // 3 because it references itself twice
294 },329 },
295 .id = builtin.TypeId.Type,330 .id = builtin.TypeId.Type,
296 },331 },
...@@ -305,7 +340,7 @@ pub const Module = struct {...@@ -305,7 +340,7 @@ pub const Module = struct {
305 .base = Value{340 .base = Value{
306 .id = Value.Id.Type,341 .id = Value.Id.Type,
307 .typeof = &Type.MetaType.get(module).base,342 .typeof = &Type.MetaType.get(module).base,
308 .ref_count = 1,343 .ref_count = std.atomic.Int(usize).init(1),
309 },344 },
310 .id = builtin.TypeId.Void,345 .id = builtin.TypeId.Void,
311 },346 },
...@@ -317,7 +352,7 @@ pub const Module = struct {...@@ -317,7 +352,7 @@ pub const Module = struct {
317 .base = Value{352 .base = Value{
318 .id = Value.Id.Type,353 .id = Value.Id.Type,
319 .typeof = &Type.MetaType.get(module).base,354 .typeof = &Type.MetaType.get(module).base,
320 .ref_count = 1,355 .ref_count = std.atomic.Int(usize).init(1),
321 },356 },
322 .id = builtin.TypeId.NoReturn,357 .id = builtin.TypeId.NoReturn,
323 },358 },
...@@ -329,7 +364,7 @@ pub const Module = struct {...@@ -329,7 +364,7 @@ pub const Module = struct {
329 .base = Value{364 .base = Value{
330 .id = Value.Id.Type,365 .id = Value.Id.Type,
331 .typeof = &Type.MetaType.get(module).base,366 .typeof = &Type.MetaType.get(module).base,
332 .ref_count = 1,367 .ref_count = std.atomic.Int(usize).init(1),
333 },368 },
334 .id = builtin.TypeId.Bool,369 .id = builtin.TypeId.Bool,
335 },370 },
...@@ -340,7 +375,7 @@ pub const Module = struct {...@@ -340,7 +375,7 @@ pub const Module = struct {
340 .base = Value{375 .base = Value{
341 .id = Value.Id.Void,376 .id = Value.Id.Void,
342 .typeof = &Type.Void.get(module).base,377 .typeof = &Type.Void.get(module).base,
343 .ref_count = 1,378 .ref_count = std.atomic.Int(usize).init(1),
344 },379 },
345 });380 });
346 errdefer module.a().destroy(module.void_value);381 errdefer module.a().destroy(module.void_value);
...@@ -349,7 +384,7 @@ pub const Module = struct {...@@ -349,7 +384,7 @@ pub const Module = struct {
349 .base = Value{384 .base = Value{
350 .id = Value.Id.Bool,385 .id = Value.Id.Bool,
351 .typeof = &Type.Bool.get(module).base,386 .typeof = &Type.Bool.get(module).base,
352 .ref_count = 1,387 .ref_count = std.atomic.Int(usize).init(1),
353 },388 },
354 .x = true,389 .x = true,
355 });390 });
...@@ -359,7 +394,7 @@ pub const Module = struct {...@@ -359,7 +394,7 @@ pub const Module = struct {
359 .base = Value{394 .base = Value{
360 .id = Value.Id.Bool,395 .id = Value.Id.Bool,
361 .typeof = &Type.Bool.get(module).base,396 .typeof = &Type.Bool.get(module).base,
362 .ref_count = 1,397 .ref_count = std.atomic.Int(usize).init(1),
363 },398 },
364 .x = false,399 .x = false,
365 });400 });
...@@ -369,16 +404,12 @@ pub const Module = struct {...@@ -369,16 +404,12 @@ pub const Module = struct {
369 .base = Value{404 .base = Value{
370 .id = Value.Id.NoReturn,405 .id = Value.Id.NoReturn,
371 .typeof = &Type.NoReturn.get(module).base,406 .typeof = &Type.NoReturn.get(module).base,
372 .ref_count = 1,407 .ref_count = std.atomic.Int(usize).init(1),
373 },408 },
374 });409 });
375 errdefer module.a().destroy(module.noreturn_value);410 errdefer module.a().destroy(module.noreturn_value);
376 }411 }
377412
378 fn dump(self: *Module) void {
379 c.LLVMDumpModule(self.module);
380 }
381
382 pub fn destroy(self: *Module) void {413 pub fn destroy(self: *Module) void {
383 self.noreturn_value.base.deref(self);414 self.noreturn_value.base.deref(self);
384 self.void_value.base.deref(self);415 self.void_value.base.deref(self);
...@@ -389,9 +420,6 @@ pub const Module = struct {...@@ -389,9 +420,6 @@ pub const Module = struct {
389 self.meta_type.base.base.deref(self);420 self.meta_type.base.base.deref(self);
390421
391 self.events.destroy();422 self.events.destroy();
392 c.LLVMDisposeBuilder(self.builder);
393 c.LLVMDisposeModule(self.llvm_module);
394 c.LLVMContextDispose(self.context);
395 self.name.deinit();423 self.name.deinit();
396424
397 self.a().destroy(self);425 self.a().destroy(self);
...@@ -657,10 +685,19 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void {...@@ -657,10 +685,19 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void {
657 const fndef_scope = try Scope.FnDef.create(module, fn_decl.base.parent_scope);685 const fndef_scope = try Scope.FnDef.create(module, fn_decl.base.parent_scope);
658 defer fndef_scope.base.deref(module);686 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);
661 defer fn_type.base.base.deref(module);695 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);
664 defer fn_val.base.deref(module);701 defer fn_val.base.deref(module);
665702
666 fn_decl.value = Decl.Fn.Val{ .Ok = fn_val };703 fn_decl.value = Decl.Fn.Val{ .Ok = fn_val };
...@@ -674,6 +711,7 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void {...@@ -674,6 +711,7 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void {
674 ) catch unreachable)) catch |err| switch (err) {711 ) catch unreachable)) catch |err| switch (err) {
675 // This poison value should not cause the errdefers to run. It simply means712 // This poison value should not cause the errdefers to run. It simply means
676 // that self.compile_errors is populated.713 // that self.compile_errors is populated.
714 // TODO https://github.com/ziglang/zig/issues/769
677 error.SemanticAnalysisFailed => return {},715 error.SemanticAnalysisFailed => return {},
678 else => return err,716 else => return err,
679 };717 };
...@@ -692,14 +730,18 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void {...@@ -692,14 +730,18 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void {
692 ) catch unreachable)) catch |err| switch (err) {730 ) catch unreachable)) catch |err| switch (err) {
693 // This poison value should not cause the errdefers to run. It simply means731 // This poison value should not cause the errdefers to run. It simply means
694 // that self.compile_errors is populated.732 // that self.compile_errors is populated.
733 // TODO https://github.com/ziglang/zig/issues/769
695 error.SemanticAnalysisFailed => return {},734 error.SemanticAnalysisFailed => return {},
696 else => return err,735 else => return err,
697 };736 };
698 defer analyzed_code.destroy(module.a());737 errdefer analyzed_code.destroy(module.a());
699738
700 if (module.verbose_ir) {739 if (module.verbose_ir) {
701 std.debug.warn("analyzed:\n");740 std.debug.warn("analyzed:\n");
702 analyzed_code.dump();741 analyzed_code.dump();
703 }742 }
704 // TODO now render to LLVM module743
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);
705}747}
src-self-hosted/test.zig+9-2
...@@ -6,6 +6,7 @@ const Module = @import("module.zig").Module;...@@ -6,6 +6,7 @@ const Module = @import("module.zig").Module;
6const introspect = @import("introspect.zig");6const introspect = @import("introspect.zig");
7const assertOrPanic = std.debug.assertOrPanic;7const assertOrPanic = std.debug.assertOrPanic;
8const errmsg = @import("errmsg.zig");8const errmsg = @import("errmsg.zig");
9const EventLoopLocal = @import("module.zig").EventLoopLocal;
910
10test "compile errors" {11test "compile errors" {
11 var ctx: TestContext = undefined;12 var ctx: TestContext = undefined;
...@@ -22,6 +23,7 @@ const allocator = std.heap.c_allocator;...@@ -22,6 +23,7 @@ const allocator = std.heap.c_allocator;
2223
23pub const TestContext = struct {24pub const TestContext = struct {
24 loop: std.event.Loop,25 loop: std.event.Loop,
26 event_loop_local: EventLoopLocal,
25 zig_lib_dir: []u8,27 zig_lib_dir: []u8,
26 zig_cache_dir: []u8,28 zig_cache_dir: []u8,
27 file_index: std.atomic.Int(usize),29 file_index: std.atomic.Int(usize),
...@@ -34,6 +36,7 @@ pub const TestContext = struct {...@@ -34,6 +36,7 @@ pub const TestContext = struct {
34 self.* = TestContext{36 self.* = TestContext{
35 .any_err = {},37 .any_err = {},
36 .loop = undefined,38 .loop = undefined,
39 .event_loop_local = undefined,
37 .zig_lib_dir = undefined,40 .zig_lib_dir = undefined,
38 .zig_cache_dir = undefined,41 .zig_cache_dir = undefined,
39 .group = undefined,42 .group = undefined,
...@@ -43,6 +46,9 @@ pub const TestContext = struct {...@@ -43,6 +46,9 @@ pub const TestContext = struct {
43 try self.loop.initMultiThreaded(allocator);46 try self.loop.initMultiThreaded(allocator);
44 errdefer self.loop.deinit();47 errdefer self.loop.deinit();
4548
49 self.event_loop_local = EventLoopLocal.init(&self.loop);
50 errdefer self.event_loop_local.deinit();
51
46 self.group = std.event.Group(error!void).init(&self.loop);52 self.group = std.event.Group(error!void).init(&self.loop);
47 errdefer self.group.cancelAll();53 errdefer self.group.cancelAll();
4854
...@@ -60,6 +66,7 @@ pub const TestContext = struct {...@@ -60,6 +66,7 @@ pub const TestContext = struct {
60 std.os.deleteTree(allocator, tmp_dir_name) catch {};66 std.os.deleteTree(allocator, tmp_dir_name) catch {};
61 allocator.free(self.zig_cache_dir);67 allocator.free(self.zig_cache_dir);
62 allocator.free(self.zig_lib_dir);68 allocator.free(self.zig_lib_dir);
69 self.event_loop_local.deinit();
63 self.loop.deinit();70 self.loop.deinit();
64 }71 }
6572
...@@ -83,7 +90,7 @@ pub const TestContext = struct {...@@ -83,7 +90,7 @@ pub const TestContext = struct {
83 msg: []const u8,90 msg: []const u8,
84 ) !void {91 ) !void {
85 var file_index_buf: [20]u8 = undefined;92 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());
87 const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1);94 const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1);
8895
89 if (std.os.path.dirname(file1_path)) |dirname| {96 if (std.os.path.dirname(file1_path)) |dirname| {
...@@ -94,7 +101,7 @@ pub const TestContext = struct {...@@ -94,7 +101,7 @@ pub const TestContext = struct {
94 try std.io.writeFile(allocator, file1_path, source);101 try std.io.writeFile(allocator, file1_path, source);
95102
96 var module = try Module.create(103 var module = try Module.create(
97 &self.loop,104 &self.event_loop_local,
98 "test",105 "test",
99 file1_path,106 file1_path,
100 Target.Native,107 Target.Native,
src-self-hosted/type.zig+144-3
...@@ -1,7 +1,10 @@...@@ -1,7 +1,10 @@
1const std = @import("std");
1const builtin = @import("builtin");2const builtin = @import("builtin");
2const Scope = @import("scope.zig").Scope;3const Scope = @import("scope.zig").Scope;
3const Module = @import("module.zig").Module;4const Module = @import("module.zig").Module;
4const Value = @import("value.zig").Value;5const Value = @import("value.zig").Value;
6const llvm = @import("llvm.zig");
7const CompilationUnit = @import("codegen.zig").CompilationUnit;
58
6pub const Type = struct {9pub const Type = struct {
7 base: Value,10 base: Value,
...@@ -39,6 +42,36 @@ pub const Type = struct {...@@ -39,6 +42,36 @@ pub const Type = struct {
39 }42 }
40 }43 }
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
42 pub fn dump(base: *const Type) void {75 pub fn dump(base: *const Type) void {
43 std.debug.warn("{}", @tagName(base.id));76 std.debug.warn("{}", @tagName(base.id));
44 }77 }
...@@ -54,27 +87,72 @@ pub const Type = struct {...@@ -54,27 +87,72 @@ pub const Type = struct {
54 pub fn destroy(self: *Struct, module: *Module) void {87 pub fn destroy(self: *Struct, module: *Module) void {
55 module.a().destroy(self);88 module.a().destroy(self);
56 }89 }
90
91 pub fn getLlvmType(self: *Struct, cunit: *CompilationUnit) llvm.TypeRef {
92 @panic("TODO");
93 }
57 };94 };
5895
59 pub const Fn = struct {96 pub const Fn = struct {
60 base: Type,97 base: Type,
98 return_type: *Type,
99 params: []Param,
100 is_var_args: bool,
61101
62 pub fn create(module: *Module) !*Fn {102 pub const Param = struct {
63 return module.a().create(Fn{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{
64 .base = Type{109 .base = Type{
65 .base = Value{110 .base = Value{
66 .id = Value.Id.Type,111 .id = Value.Id.Type,
67 .typeof = &MetaType.get(module).base,112 .typeof = &MetaType.get(module).base,
68 .ref_count = 1,113 .ref_count = std.atomic.Int(usize).init(1),
69 },114 },
70 .id = builtin.TypeId.Fn,115 .id = builtin.TypeId.Fn,
71 },116 },
117 .return_type = return_type,
118 .params = params,
119 .is_var_args = is_var_args,
72 });120 });
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;
73 }128 }
74129
75 pub fn destroy(self: *Fn, module: *Module) void {130 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 }
76 module.a().destroy(self);135 module.a().destroy(self);
77 }136 }
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 }
78 };156 };
79157
80 pub const MetaType = struct {158 pub const MetaType = struct {
...@@ -118,6 +196,10 @@ pub const Type = struct {...@@ -118,6 +196,10 @@ pub const Type = struct {
118 pub fn destroy(self: *Bool, module: *Module) void {196 pub fn destroy(self: *Bool, module: *Module) void {
119 module.a().destroy(self);197 module.a().destroy(self);
120 }198 }
199
200 pub fn getLlvmType(self: *Bool, cunit: *CompilationUnit) llvm.TypeRef {
201 @panic("TODO");
202 }
121 };203 };
122204
123 pub const NoReturn = struct {205 pub const NoReturn = struct {
...@@ -140,6 +222,10 @@ pub const Type = struct {...@@ -140,6 +222,10 @@ pub const Type = struct {
140 pub fn destroy(self: *Int, module: *Module) void {222 pub fn destroy(self: *Int, module: *Module) void {
141 module.a().destroy(self);223 module.a().destroy(self);
142 }224 }
225
226 pub fn getLlvmType(self: *Int, cunit: *CompilationUnit) llvm.TypeRef {
227 @panic("TODO");
228 }
143 };229 };
144230
145 pub const Float = struct {231 pub const Float = struct {
...@@ -148,6 +234,10 @@ pub const Type = struct {...@@ -148,6 +234,10 @@ pub const Type = struct {
148 pub fn destroy(self: *Float, module: *Module) void {234 pub fn destroy(self: *Float, module: *Module) void {
149 module.a().destroy(self);235 module.a().destroy(self);
150 }236 }
237
238 pub fn getLlvmType(self: *Float, cunit: *CompilationUnit) llvm.TypeRef {
239 @panic("TODO");
240 }
151 };241 };
152 pub const Pointer = struct {242 pub const Pointer = struct {
153 base: Type,243 base: Type,
...@@ -180,14 +270,24 @@ pub const Type = struct {...@@ -180,14 +270,24 @@ pub const Type = struct {
180 ) *Pointer {270 ) *Pointer {
181 @panic("TODO get pointer");271 @panic("TODO get pointer");
182 }272 }
273
274 pub fn getLlvmType(self: *Pointer, cunit: *CompilationUnit) llvm.TypeRef {
275 @panic("TODO");
276 }
183 };277 };
278
184 pub const Array = struct {279 pub const Array = struct {
185 base: Type,280 base: Type,
186281
187 pub fn destroy(self: *Array, module: *Module) void {282 pub fn destroy(self: *Array, module: *Module) void {
188 module.a().destroy(self);283 module.a().destroy(self);
189 }284 }
285
286 pub fn getLlvmType(self: *Array, cunit: *CompilationUnit) llvm.TypeRef {
287 @panic("TODO");
288 }
190 };289 };
290
191 pub const ComptimeFloat = struct {291 pub const ComptimeFloat = struct {
192 base: Type,292 base: Type,
193293
...@@ -195,6 +295,7 @@ pub const Type = struct {...@@ -195,6 +295,7 @@ pub const Type = struct {
195 module.a().destroy(self);295 module.a().destroy(self);
196 }296 }
197 };297 };
298
198 pub const ComptimeInt = struct {299 pub const ComptimeInt = struct {
199 base: Type,300 base: Type,
200301
...@@ -202,6 +303,7 @@ pub const Type = struct {...@@ -202,6 +303,7 @@ pub const Type = struct {
202 module.a().destroy(self);303 module.a().destroy(self);
203 }304 }
204 };305 };
306
205 pub const Undefined = struct {307 pub const Undefined = struct {
206 base: Type,308 base: Type,
207309
...@@ -209,6 +311,7 @@ pub const Type = struct {...@@ -209,6 +311,7 @@ pub const Type = struct {
209 module.a().destroy(self);311 module.a().destroy(self);
210 }312 }
211 };313 };
314
212 pub const Null = struct {315 pub const Null = struct {
213 base: Type,316 base: Type,
214317
...@@ -216,41 +319,67 @@ pub const Type = struct {...@@ -216,41 +319,67 @@ pub const Type = struct {
216 module.a().destroy(self);319 module.a().destroy(self);
217 }320 }
218 };321 };
322
219 pub const Optional = struct {323 pub const Optional = struct {
220 base: Type,324 base: Type,
221325
222 pub fn destroy(self: *Optional, module: *Module) void {326 pub fn destroy(self: *Optional, module: *Module) void {
223 module.a().destroy(self);327 module.a().destroy(self);
224 }328 }
329
330 pub fn getLlvmType(self: *Optional, cunit: *CompilationUnit) llvm.TypeRef {
331 @panic("TODO");
332 }
225 };333 };
334
226 pub const ErrorUnion = struct {335 pub const ErrorUnion = struct {
227 base: Type,336 base: Type,
228337
229 pub fn destroy(self: *ErrorUnion, module: *Module) void {338 pub fn destroy(self: *ErrorUnion, module: *Module) void {
230 module.a().destroy(self);339 module.a().destroy(self);
231 }340 }
341
342 pub fn getLlvmType(self: *ErrorUnion, cunit: *CompilationUnit) llvm.TypeRef {
343 @panic("TODO");
344 }
232 };345 };
346
233 pub const ErrorSet = struct {347 pub const ErrorSet = struct {
234 base: Type,348 base: Type,
235349
236 pub fn destroy(self: *ErrorSet, module: *Module) void {350 pub fn destroy(self: *ErrorSet, module: *Module) void {
237 module.a().destroy(self);351 module.a().destroy(self);
238 }352 }
353
354 pub fn getLlvmType(self: *ErrorSet, cunit: *CompilationUnit) llvm.TypeRef {
355 @panic("TODO");
356 }
239 };357 };
358
240 pub const Enum = struct {359 pub const Enum = struct {
241 base: Type,360 base: Type,
242361
243 pub fn destroy(self: *Enum, module: *Module) void {362 pub fn destroy(self: *Enum, module: *Module) void {
244 module.a().destroy(self);363 module.a().destroy(self);
245 }364 }
365
366 pub fn getLlvmType(self: *Enum, cunit: *CompilationUnit) llvm.TypeRef {
367 @panic("TODO");
368 }
246 };369 };
370
247 pub const Union = struct {371 pub const Union = struct {
248 base: Type,372 base: Type,
249373
250 pub fn destroy(self: *Union, module: *Module) void {374 pub fn destroy(self: *Union, module: *Module) void {
251 module.a().destroy(self);375 module.a().destroy(self);
252 }376 }
377
378 pub fn getLlvmType(self: *Union, cunit: *CompilationUnit) llvm.TypeRef {
379 @panic("TODO");
380 }
253 };381 };
382
254 pub const Namespace = struct {383 pub const Namespace = struct {
255 base: Type,384 base: Type,
256385
...@@ -273,6 +402,10 @@ pub const Type = struct {...@@ -273,6 +402,10 @@ pub const Type = struct {
273 pub fn destroy(self: *BoundFn, module: *Module) void {402 pub fn destroy(self: *BoundFn, module: *Module) void {
274 module.a().destroy(self);403 module.a().destroy(self);
275 }404 }
405
406 pub fn getLlvmType(self: *BoundFn, cunit: *CompilationUnit) llvm.TypeRef {
407 @panic("TODO");
408 }
276 };409 };
277410
278 pub const ArgTuple = struct {411 pub const ArgTuple = struct {
...@@ -289,6 +422,10 @@ pub const Type = struct {...@@ -289,6 +422,10 @@ pub const Type = struct {
289 pub fn destroy(self: *Opaque, module: *Module) void {422 pub fn destroy(self: *Opaque, module: *Module) void {
290 module.a().destroy(self);423 module.a().destroy(self);
291 }424 }
425
426 pub fn getLlvmType(self: *Opaque, cunit: *CompilationUnit) llvm.TypeRef {
427 @panic("TODO");
428 }
292 };429 };
293430
294 pub const Promise = struct {431 pub const Promise = struct {
...@@ -297,5 +434,9 @@ pub const Type = struct {...@@ -297,5 +434,9 @@ pub const Type = struct {
297 pub fn destroy(self: *Promise, module: *Module) void {434 pub fn destroy(self: *Promise, module: *Module) void {
298 module.a().destroy(self);435 module.a().destroy(self);
299 }436 }
437
438 pub fn getLlvmType(self: *Promise, cunit: *CompilationUnit) llvm.TypeRef {
439 @panic("TODO");
440 }
300 };441 };
301};442};
src-self-hosted/value.zig+14-6
...@@ -8,15 +8,16 @@ const Module = @import("module.zig").Module;...@@ -8,15 +8,16 @@ const Module = @import("module.zig").Module;
8pub const Value = struct {8pub const Value = struct {
9 id: Id,9 id: Id,
10 typeof: *Type,10 typeof: *Type,
11 ref_count: usize,11 ref_count: std.atomic.Int(usize),
1212
13 /// Thread-safe
13 pub fn ref(base: *Value) void {14 pub fn ref(base: *Value) void {
14 base.ref_count += 1;15 _ = base.ref_count.incr();
15 }16 }
1617
18 /// Thread-safe
17 pub fn deref(base: *Value, module: *Module) void {19 pub fn deref(base: *Value, module: *Module) void {
18 base.ref_count -= 1;20 if (base.ref_count.decr() == 1) {
19 if (base.ref_count == 0) {
20 base.typeof.base.deref(module);21 base.typeof.base.deref(module);
21 switch (base.id) {22 switch (base.id) {
22 Id.Type => @fieldParentPtr(Type, "base", base).destroy(module),23 Id.Type => @fieldParentPtr(Type, "base", base).destroy(module),
...@@ -52,6 +53,10 @@ pub const Value = struct {...@@ -52,6 +53,10 @@ pub const Value = struct {
52 pub const Fn = struct {53 pub const Fn = struct {
53 base: Value,54 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
55 /// parent should be the top level decls or container decls60 /// parent should be the top level decls or container decls
56 fndef_scope: *Scope.FnDef,61 fndef_scope: *Scope.FnDef,
5762
...@@ -62,16 +67,18 @@ pub const Value = struct {...@@ -62,16 +67,18 @@ pub const Value = struct {
62 block_scope: *Scope.Block,67 block_scope: *Scope.Block,
6368
64 /// Creates a Fn value with 1 ref69 /// 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 {
66 const self = try module.a().create(Fn{72 const self = try module.a().create(Fn{
67 .base = Value{73 .base = Value{
68 .id = Value.Id.Fn,74 .id = Value.Id.Fn,
69 .typeof = &fn_type.base,75 .typeof = &fn_type.base,
70 .ref_count = 1,76 .ref_count = std.atomic.Int(usize).init(1),
71 },77 },
72 .fndef_scope = fndef_scope,78 .fndef_scope = fndef_scope,
73 .child_scope = &fndef_scope.base,79 .child_scope = &fndef_scope.base,
74 .block_scope = undefined,80 .block_scope = undefined,
81 .symbol_name = symbol_name,
75 });82 });
76 fn_type.base.base.ref();83 fn_type.base.base.ref();
77 fndef_scope.fn_val = self;84 fndef_scope.fn_val = self;
...@@ -81,6 +88,7 @@ pub const Value = struct {...@@ -81,6 +88,7 @@ pub const Value = struct {
8188
82 pub fn destroy(self: *Fn, module: *Module) void {89 pub fn destroy(self: *Fn, module: *Module) void {
83 self.fndef_scope.base.deref(module);90 self.fndef_scope.base.deref(module);
91 self.symbol_name.deinit();
84 module.a().destroy(self);92 module.a().destroy(self);
85 }93 }
86 };94 };
std/atomic/int.zig+14-4
...@@ -4,16 +4,26 @@ const AtomicOrder = builtin.AtomicOrder;...@@ -4,16 +4,26 @@ const AtomicOrder = builtin.AtomicOrder;
4/// Thread-safe, lock-free integer4/// Thread-safe, lock-free integer
5pub fn Int(comptime T: type) type {5pub fn Int(comptime T: type) type {
6 return struct {6 return struct {
7 value: T,7 unprotected_value: T,
88
9 pub const Self = this;9 pub const Self = this;
1010
11 pub fn init(init_val: T) Self {11 pub fn init(init_val: T) Self {
12 return Self{ .value = init_val };12 return Self{ .unprotected_value = init_val };
13 }13 }
1414
15 pub fn next(self: *Self) T {15 /// Returns previous value
16 return @atomicRmw(T, &self.value, builtin.AtomicRmwOp.Add, 1, AtomicOrder.SeqCst);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);
17 }27 }
18 };28 };
19}29}
std/event/loop.zig-1
...@@ -101,7 +101,6 @@ pub const Loop = struct {...@@ -101,7 +101,6 @@ pub const Loop = struct {
101 errdefer self.deinitOsData();101 errdefer self.deinitOsData();
102 }102 }
103103
104 /// must call stop before deinit
105 pub fn deinit(self: *Loop) void {104 pub fn deinit(self: *Loop) void {
106 self.deinitOsData();105 self.deinitOsData();
107 self.allocator.free(self.extra_threads);106 self.allocator.free(self.extra_threads);