| author | |
| committer | |
| log | 278829fc2cc23e55b09915ce07ce1ec2dbf7e68b |
| tree | 8c9b8a920ece20514e5457e266ed8fd1ac7310ba |
| parent | 91636f1e8cc197a310205724458a4e1154530720 |
10 files changed, 346 insertions(+), 63 deletions(-)
src-self-hosted/codegen.zig created+61| ... | ... | @@ -0,0 +1,61 @@ |
| 1 | const std = @import("std"); | |
| 2 | // TODO codegen pretends that Module is renamed to Build because I plan to | |
| 3 | // do that refactor at some point | |
| 4 | const 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 | |
| 8 | const llvm = @import("llvm.zig"); | |
| 9 | const ir = @import("ir.zig"); | |
| 10 | const Value = @import("value.zig").Value; | |
| 11 | const Type = @import("type.zig").Type; | |
| 12 | const event = std.event; | |
| 13 | ||
| 14 | pub 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 | ||
| 45 | pub 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 | ||
| 57 | pub 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 | 375 | |
| 376 | 376 | pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Instruction { |
| 377 | 377 | const target = try self.params.target.getAsParam(); |
| 378 | ||
| 379 | 378 | 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); | |
| 387 | 380 | } |
| 388 | 381 | }; |
| 389 | 382 | }; |
src-self-hosted/llvm.zig+20-3| ... | ... | @@ -2,10 +2,27 @@ const builtin = @import("builtin"); |
| 2 | 2 | const c = @import("c.zig"); |
| 3 | 3 | const assert = @import("std").debug.assert; |
| 4 | 4 | |
| 5 | pub const ValueRef = removeNullability(c.LLVMValueRef); | |
| 6 | pub const ModuleRef = removeNullability(c.LLVMModuleRef); | |
| 7 | pub const ContextRef = removeNullability(c.LLVMContextRef); | |
| 8 | 5 | pub const BuilderRef = removeNullability(c.LLVMBuilderRef); |
| 6 | pub const ContextRef = removeNullability(c.LLVMContextRef); | |
| 7 | pub const ModuleRef = removeNullability(c.LLVMModuleRef); | |
| 8 | pub const ValueRef = removeNullability(c.LLVMValueRef); | |
| 9 | pub const TypeRef = removeNullability(c.LLVMTypeRef); | |
| 10 | ||
| 11 | pub const AddFunction = c.LLVMAddFunction; | |
| 12 | pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext; | |
| 13 | pub const DisposeBuilder = c.LLVMDisposeBuilder; | |
| 14 | pub const DisposeModule = c.LLVMDisposeModule; | |
| 15 | pub const DumpModule = c.LLVMDumpModule; | |
| 16 | pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext; | |
| 17 | pub const VoidTypeInContext = c.LLVMVoidTypeInContext; | |
| 18 | ||
| 19 | pub const FunctionType = LLVMFunctionType; | |
| 20 | extern fn LLVMFunctionType( | |
| 21 | ReturnType: TypeRef, | |
| 22 | ParamTypes: [*]TypeRef, | |
| 23 | ParamCount: c_uint, | |
| 24 | IsVarArg: c_int, | |
| 25 | ) ?TypeRef; | |
| 9 | 26 | |
| 10 | 27 | fn removeNullability(comptime T: type) type { |
| 11 | 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 | 14 | const introspect = @import("introspect.zig"); |
| 15 | 15 | const Args = arg.Args; |
| 16 | 16 | const Flag = arg.Flag; |
| 17 | const EventLoopLocal = @import("module.zig").EventLoopLocal; | |
| 17 | 18 | const Module = @import("module.zig").Module; |
| 18 | 19 | const Target = @import("target.zig").Target; |
| 19 | 20 | const errmsg = @import("errmsg.zig"); |
| ... | ... | @@ -386,9 +387,13 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Mo |
| 386 | 387 | |
| 387 | 388 | var loop: event.Loop = undefined; |
| 388 | 389 | try loop.initMultiThreaded(allocator); |
| 390 | defer loop.deinit(); | |
| 391 | ||
| 392 | var event_loop_local = EventLoopLocal.init(&loop); | |
| 393 | defer event_loop_local.deinit(); | |
| 389 | 394 | |
| 390 | 395 | var module = try Module.create( |
| 391 | &loop, | |
| 396 | &event_loop_local, | |
| 392 | 397 | root_name, |
| 393 | 398 | root_source_file, |
| 394 | 399 | Target.Native, |
src-self-hosted/module.zig+77-35| ... | ... | @@ -25,14 +25,58 @@ const ParsedFile = @import("parsed_file.zig").ParsedFile; |
| 25 | 25 | const Value = @import("value.zig").Value; |
| 26 | 26 | const Type = Value.Type; |
| 27 | 27 | const Span = errmsg.Span; |
| 28 | const codegen = @import("codegen.zig"); | |
| 29 | ||
| 30 | /// Data that is local to the event loop. | |
| 31 | pub 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 | ||
| 67 | pub 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 | }; | |
| 28 | 74 | |
| 29 | 75 | pub const Module = struct { |
| 76 | event_loop_local: *EventLoopLocal, | |
| 30 | 77 | loop: *event.Loop, |
| 31 | 78 | name: Buffer, |
| 32 | 79 | root_src_path: ?[]const u8, |
| 33 | llvm_module: llvm.ModuleRef, | |
| 34 | context: llvm.ContextRef, | |
| 35 | builder: llvm.BuilderRef, | |
| 36 | 80 | target: Target, |
| 37 | 81 | build_mode: builtin.Mode, |
| 38 | 82 | zig_lib_dir: []const u8, |
| ... | ... | @@ -187,7 +231,7 @@ pub const Module = struct { |
| 187 | 231 | }; |
| 188 | 232 | |
| 189 | 233 | pub fn create( |
| 190 | loop: *event.Loop, | |
| 234 | event_loop_local: *EventLoopLocal, | |
| 191 | 235 | name: []const u8, |
| 192 | 236 | root_src_path: ?[]const u8, |
| 193 | 237 | target: *const Target, |
| ... | ... | @@ -196,29 +240,20 @@ pub const Module = struct { |
| 196 | 240 | zig_lib_dir: []const u8, |
| 197 | 241 | cache_dir: []const u8, |
| 198 | 242 | ) !*Module { |
| 243 | const loop = event_loop_local.loop; | |
| 244 | ||
| 199 | 245 | var name_buffer = try Buffer.init(loop.allocator, name); |
| 200 | 246 | errdefer name_buffer.deinit(); |
| 201 | 247 | |
| 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 | 248 | const events = try event.Channel(Event).create(loop, 0); |
| 212 | 249 | errdefer events.destroy(); |
| 213 | 250 | |
| 214 | 251 | const module = try loop.allocator.create(Module{ |
| 215 | 252 | .loop = loop, |
| 253 | .event_loop_local = event_loop_local, | |
| 216 | 254 | .events = events, |
| 217 | 255 | .name = name_buffer, |
| 218 | 256 | .root_src_path = root_src_path, |
| 219 | .llvm_module = llvm_module, | |
| 220 | .context = context, | |
| 221 | .builder = builder, | |
| 222 | 257 | .target = target.*, |
| 223 | 258 | .kind = kind, |
| 224 | 259 | .build_mode = build_mode, |
| ... | ... | @@ -290,7 +325,7 @@ pub const Module = struct { |
| 290 | 325 | .base = Value{ |
| 291 | 326 | .id = Value.Id.Type, |
| 292 | 327 | .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 | |
| 294 | 329 | }, |
| 295 | 330 | .id = builtin.TypeId.Type, |
| 296 | 331 | }, |
| ... | ... | @@ -305,7 +340,7 @@ pub const Module = struct { |
| 305 | 340 | .base = Value{ |
| 306 | 341 | .id = Value.Id.Type, |
| 307 | 342 | .typeof = &Type.MetaType.get(module).base, |
| 308 | .ref_count = 1, | |
| 343 | .ref_count = std.atomic.Int(usize).init(1), | |
| 309 | 344 | }, |
| 310 | 345 | .id = builtin.TypeId.Void, |
| 311 | 346 | }, |
| ... | ... | @@ -317,7 +352,7 @@ pub const Module = struct { |
| 317 | 352 | .base = Value{ |
| 318 | 353 | .id = Value.Id.Type, |
| 319 | 354 | .typeof = &Type.MetaType.get(module).base, |
| 320 | .ref_count = 1, | |
| 355 | .ref_count = std.atomic.Int(usize).init(1), | |
| 321 | 356 | }, |
| 322 | 357 | .id = builtin.TypeId.NoReturn, |
| 323 | 358 | }, |
| ... | ... | @@ -329,7 +364,7 @@ pub const Module = struct { |
| 329 | 364 | .base = Value{ |
| 330 | 365 | .id = Value.Id.Type, |
| 331 | 366 | .typeof = &Type.MetaType.get(module).base, |
| 332 | .ref_count = 1, | |
| 367 | .ref_count = std.atomic.Int(usize).init(1), | |
| 333 | 368 | }, |
| 334 | 369 | .id = builtin.TypeId.Bool, |
| 335 | 370 | }, |
| ... | ... | @@ -340,7 +375,7 @@ pub const Module = struct { |
| 340 | 375 | .base = Value{ |
| 341 | 376 | .id = Value.Id.Void, |
| 342 | 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 | 381 | errdefer module.a().destroy(module.void_value); |
| ... | ... | @@ -349,7 +384,7 @@ pub const Module = struct { |
| 349 | 384 | .base = Value{ |
| 350 | 385 | .id = Value.Id.Bool, |
| 351 | 386 | .typeof = &Type.Bool.get(module).base, |
| 352 | .ref_count = 1, | |
| 387 | .ref_count = std.atomic.Int(usize).init(1), | |
| 353 | 388 | }, |
| 354 | 389 | .x = true, |
| 355 | 390 | }); |
| ... | ... | @@ -359,7 +394,7 @@ pub const Module = struct { |
| 359 | 394 | .base = Value{ |
| 360 | 395 | .id = Value.Id.Bool, |
| 361 | 396 | .typeof = &Type.Bool.get(module).base, |
| 362 | .ref_count = 1, | |
| 397 | .ref_count = std.atomic.Int(usize).init(1), | |
| 363 | 398 | }, |
| 364 | 399 | .x = false, |
| 365 | 400 | }); |
| ... | ... | @@ -369,16 +404,12 @@ pub const Module = struct { |
| 369 | 404 | .base = Value{ |
| 370 | 405 | .id = Value.Id.NoReturn, |
| 371 | 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 | 410 | errdefer module.a().destroy(module.noreturn_value); |
| 376 | 411 | } |
| 377 | 412 | |
| 378 | fn dump(self: *Module) void { | |
| 379 | c.LLVMDumpModule(self.module); | |
| 380 | } | |
| 381 | ||
| 382 | 413 | pub fn destroy(self: *Module) void { |
| 383 | 414 | self.noreturn_value.base.deref(self); |
| 384 | 415 | self.void_value.base.deref(self); |
| ... | ... | @@ -389,9 +420,6 @@ pub const Module = struct { |
| 389 | 420 | self.meta_type.base.base.deref(self); |
| 390 | 421 | |
| 391 | 422 | self.events.destroy(); |
| 392 | c.LLVMDisposeBuilder(self.builder); | |
| 393 | c.LLVMDisposeModule(self.llvm_module); | |
| 394 | c.LLVMContextDispose(self.context); | |
| 395 | 423 | self.name.deinit(); |
| 396 | 424 | |
| 397 | 425 | self.a().destroy(self); |
| ... | ... | @@ -657,10 +685,19 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void { |
| 657 | 685 | const fndef_scope = try Scope.FnDef.create(module, fn_decl.base.parent_scope); |
| 658 | 686 | defer fndef_scope.base.deref(module); |
| 659 | 687 | |
| 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 | 695 | defer fn_type.base.base.deref(module); |
| 662 | 696 | |
| 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 | 701 | defer fn_val.base.deref(module); |
| 665 | 702 | |
| 666 | 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 | 711 | ) catch unreachable)) catch |err| switch (err) { |
| 675 | 712 | // This poison value should not cause the errdefers to run. It simply means |
| 676 | 713 | // that self.compile_errors is populated. |
| 714 | // TODO https://github.com/ziglang/zig/issues/769 | |
| 677 | 715 | error.SemanticAnalysisFailed => return {}, |
| 678 | 716 | else => return err, |
| 679 | 717 | }; |
| ... | ... | @@ -692,14 +730,18 @@ async fn generateDeclFn(module: *Module, fn_decl: *Decl.Fn) !void { |
| 692 | 730 | ) catch unreachable)) catch |err| switch (err) { |
| 693 | 731 | // This poison value should not cause the errdefers to run. It simply means |
| 694 | 732 | // that self.compile_errors is populated. |
| 733 | // TODO https://github.com/ziglang/zig/issues/769 | |
| 695 | 734 | error.SemanticAnalysisFailed => return {}, |
| 696 | 735 | else => return err, |
| 697 | 736 | }; |
| 698 | defer analyzed_code.destroy(module.a()); | |
| 737 | errdefer analyzed_code.destroy(module.a()); | |
| 699 | 738 | |
| 700 | 739 | if (module.verbose_ir) { |
| 701 | 740 | std.debug.warn("analyzed:\n"); |
| 702 | 741 | analyzed_code.dump(); |
| 703 | 742 | } |
| 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); | |
| 705 | 747 | } |
src-self-hosted/test.zig+9-2| ... | ... | @@ -6,6 +6,7 @@ const Module = @import("module.zig").Module; |
| 6 | 6 | const introspect = @import("introspect.zig"); |
| 7 | 7 | const assertOrPanic = std.debug.assertOrPanic; |
| 8 | 8 | const errmsg = @import("errmsg.zig"); |
| 9 | const EventLoopLocal = @import("module.zig").EventLoopLocal; | |
| 9 | 10 | |
| 10 | 11 | test "compile errors" { |
| 11 | 12 | var ctx: TestContext = undefined; |
| ... | ... | @@ -22,6 +23,7 @@ const allocator = std.heap.c_allocator; |
| 22 | 23 | |
| 23 | 24 | pub const TestContext = struct { |
| 24 | 25 | loop: std.event.Loop, |
| 26 | event_loop_local: EventLoopLocal, | |
| 25 | 27 | zig_lib_dir: []u8, |
| 26 | 28 | zig_cache_dir: []u8, |
| 27 | 29 | file_index: std.atomic.Int(usize), |
| ... | ... | @@ -34,6 +36,7 @@ pub const TestContext = struct { |
| 34 | 36 | self.* = TestContext{ |
| 35 | 37 | .any_err = {}, |
| 36 | 38 | .loop = undefined, |
| 39 | .event_loop_local = undefined, | |
| 37 | 40 | .zig_lib_dir = undefined, |
| 38 | 41 | .zig_cache_dir = undefined, |
| 39 | 42 | .group = undefined, |
| ... | ... | @@ -43,6 +46,9 @@ pub const TestContext = struct { |
| 43 | 46 | try self.loop.initMultiThreaded(allocator); |
| 44 | 47 | errdefer self.loop.deinit(); |
| 45 | 48 | |
| 49 | self.event_loop_local = EventLoopLocal.init(&self.loop); | |
| 50 | errdefer self.event_loop_local.deinit(); | |
| 51 | ||
| 46 | 52 | self.group = std.event.Group(error!void).init(&self.loop); |
| 47 | 53 | errdefer self.group.cancelAll(); |
| 48 | 54 | |
| ... | ... | @@ -60,6 +66,7 @@ pub const TestContext = struct { |
| 60 | 66 | std.os.deleteTree(allocator, tmp_dir_name) catch {}; |
| 61 | 67 | allocator.free(self.zig_cache_dir); |
| 62 | 68 | allocator.free(self.zig_lib_dir); |
| 69 | self.event_loop_local.deinit(); | |
| 63 | 70 | self.loop.deinit(); |
| 64 | 71 | } |
| 65 | 72 | |
| ... | ... | @@ -83,7 +90,7 @@ pub const TestContext = struct { |
| 83 | 90 | msg: []const u8, |
| 84 | 91 | ) !void { |
| 85 | 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 | 94 | const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1); |
| 88 | 95 | |
| 89 | 96 | if (std.os.path.dirname(file1_path)) |dirname| { |
| ... | ... | @@ -94,7 +101,7 @@ pub const TestContext = struct { |
| 94 | 101 | try std.io.writeFile(allocator, file1_path, source); |
| 95 | 102 | |
| 96 | 103 | var module = try Module.create( |
| 97 | &self.loop, | |
| 104 | &self.event_loop_local, | |
| 98 | 105 | "test", |
| 99 | 106 | file1_path, |
| 100 | 107 | Target.Native, |
src-self-hosted/type.zig+144-3| ... | ... | @@ -1,7 +1,10 @@ |
| 1 | const std = @import("std"); | |
| 1 | 2 | const builtin = @import("builtin"); |
| 2 | 3 | const Scope = @import("scope.zig").Scope; |
| 3 | 4 | const Module = @import("module.zig").Module; |
| 4 | 5 | const Value = @import("value.zig").Value; |
| 6 | const llvm = @import("llvm.zig"); | |
| 7 | const CompilationUnit = @import("codegen.zig").CompilationUnit; | |
| 5 | 8 | |
| 6 | 9 | pub const Type = struct { |
| 7 | 10 | base: Value, |
| ... | ... | @@ -39,6 +42,36 @@ pub const Type = struct { |
| 39 | 42 | } |
| 40 | 43 | } |
| 41 | 44 | |
| 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 | 75 | pub fn dump(base: *const Type) void { |
| 43 | 76 | std.debug.warn("{}", @tagName(base.id)); |
| 44 | 77 | } |
| ... | ... | @@ -54,27 +87,72 @@ pub const Type = struct { |
| 54 | 87 | pub fn destroy(self: *Struct, module: *Module) void { |
| 55 | 88 | module.a().destroy(self); |
| 56 | 89 | } |
| 90 | ||
| 91 | pub fn getLlvmType(self: *Struct, cunit: *CompilationUnit) llvm.TypeRef { | |
| 92 | @panic("TODO"); | |
| 93 | } | |
| 57 | 94 | }; |
| 58 | 95 | |
| 59 | 96 | pub const Fn = struct { |
| 60 | 97 | base: Type, |
| 98 | return_type: *Type, | |
| 99 | params: []Param, | |
| 100 | is_var_args: bool, | |
| 61 | 101 | |
| 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{ | |
| 64 | 109 | .base = Type{ |
| 65 | 110 | .base = Value{ |
| 66 | 111 | .id = Value.Id.Type, |
| 67 | 112 | .typeof = &MetaType.get(module).base, |
| 68 | .ref_count = 1, | |
| 113 | .ref_count = std.atomic.Int(usize).init(1), | |
| 69 | 114 | }, |
| 70 | 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 | } |
| 74 | 129 | |
| 75 | 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 | 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 | }; |
| 79 | 157 | |
| 80 | 158 | pub const MetaType = struct { |
| ... | ... | @@ -118,6 +196,10 @@ pub const Type = struct { |
| 118 | 196 | pub fn destroy(self: *Bool, module: *Module) void { |
| 119 | 197 | module.a().destroy(self); |
| 120 | 198 | } |
| 199 | ||
| 200 | pub fn getLlvmType(self: *Bool, cunit: *CompilationUnit) llvm.TypeRef { | |
| 201 | @panic("TODO"); | |
| 202 | } | |
| 121 | 203 | }; |
| 122 | 204 | |
| 123 | 205 | pub const NoReturn = struct { |
| ... | ... | @@ -140,6 +222,10 @@ pub const Type = struct { |
| 140 | 222 | pub fn destroy(self: *Int, module: *Module) void { |
| 141 | 223 | module.a().destroy(self); |
| 142 | 224 | } |
| 225 | ||
| 226 | pub fn getLlvmType(self: *Int, cunit: *CompilationUnit) llvm.TypeRef { | |
| 227 | @panic("TODO"); | |
| 228 | } | |
| 143 | 229 | }; |
| 144 | 230 | |
| 145 | 231 | pub const Float = struct { |
| ... | ... | @@ -148,6 +234,10 @@ pub const Type = struct { |
| 148 | 234 | pub fn destroy(self: *Float, module: *Module) void { |
| 149 | 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 | 242 | pub const Pointer = struct { |
| 153 | 243 | base: Type, |
| ... | ... | @@ -180,14 +270,24 @@ pub const Type = struct { |
| 180 | 270 | ) *Pointer { |
| 181 | 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 | 279 | pub const Array = struct { |
| 185 | 280 | base: Type, |
| 186 | 281 | |
| 187 | 282 | pub fn destroy(self: *Array, module: *Module) void { |
| 188 | 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 | 291 | pub const ComptimeFloat = struct { |
| 192 | 292 | base: Type, |
| 193 | 293 | |
| ... | ... | @@ -195,6 +295,7 @@ pub const Type = struct { |
| 195 | 295 | module.a().destroy(self); |
| 196 | 296 | } |
| 197 | 297 | }; |
| 298 | ||
| 198 | 299 | pub const ComptimeInt = struct { |
| 199 | 300 | base: Type, |
| 200 | 301 | |
| ... | ... | @@ -202,6 +303,7 @@ pub const Type = struct { |
| 202 | 303 | module.a().destroy(self); |
| 203 | 304 | } |
| 204 | 305 | }; |
| 306 | ||
| 205 | 307 | pub const Undefined = struct { |
| 206 | 308 | base: Type, |
| 207 | 309 | |
| ... | ... | @@ -209,6 +311,7 @@ pub const Type = struct { |
| 209 | 311 | module.a().destroy(self); |
| 210 | 312 | } |
| 211 | 313 | }; |
| 314 | ||
| 212 | 315 | pub const Null = struct { |
| 213 | 316 | base: Type, |
| 214 | 317 | |
| ... | ... | @@ -216,41 +319,67 @@ pub const Type = struct { |
| 216 | 319 | module.a().destroy(self); |
| 217 | 320 | } |
| 218 | 321 | }; |
| 322 | ||
| 219 | 323 | pub const Optional = struct { |
| 220 | 324 | base: Type, |
| 221 | 325 | |
| 222 | 326 | pub fn destroy(self: *Optional, module: *Module) void { |
| 223 | 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 | 335 | pub const ErrorUnion = struct { |
| 227 | 336 | base: Type, |
| 228 | 337 | |
| 229 | 338 | pub fn destroy(self: *ErrorUnion, module: *Module) void { |
| 230 | 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 | 347 | pub const ErrorSet = struct { |
| 234 | 348 | base: Type, |
| 235 | 349 | |
| 236 | 350 | pub fn destroy(self: *ErrorSet, module: *Module) void { |
| 237 | 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 | 359 | pub const Enum = struct { |
| 241 | 360 | base: Type, |
| 242 | 361 | |
| 243 | 362 | pub fn destroy(self: *Enum, module: *Module) void { |
| 244 | 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 | 371 | pub const Union = struct { |
| 248 | 372 | base: Type, |
| 249 | 373 | |
| 250 | 374 | pub fn destroy(self: *Union, module: *Module) void { |
| 251 | 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 | 383 | pub const Namespace = struct { |
| 255 | 384 | base: Type, |
| 256 | 385 | |
| ... | ... | @@ -273,6 +402,10 @@ pub const Type = struct { |
| 273 | 402 | pub fn destroy(self: *BoundFn, module: *Module) void { |
| 274 | 403 | module.a().destroy(self); |
| 275 | 404 | } |
| 405 | ||
| 406 | pub fn getLlvmType(self: *BoundFn, cunit: *CompilationUnit) llvm.TypeRef { | |
| 407 | @panic("TODO"); | |
| 408 | } | |
| 276 | 409 | }; |
| 277 | 410 | |
| 278 | 411 | pub const ArgTuple = struct { |
| ... | ... | @@ -289,6 +422,10 @@ pub const Type = struct { |
| 289 | 422 | pub fn destroy(self: *Opaque, module: *Module) void { |
| 290 | 423 | module.a().destroy(self); |
| 291 | 424 | } |
| 425 | ||
| 426 | pub fn getLlvmType(self: *Opaque, cunit: *CompilationUnit) llvm.TypeRef { | |
| 427 | @panic("TODO"); | |
| 428 | } | |
| 292 | 429 | }; |
| 293 | 430 | |
| 294 | 431 | pub const Promise = struct { |
| ... | ... | @@ -297,5 +434,9 @@ pub const Type = struct { |
| 297 | 434 | pub fn destroy(self: *Promise, module: *Module) void { |
| 298 | 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 | 8 | pub const Value = struct { |
| 9 | 9 | id: Id, |
| 10 | 10 | typeof: *Type, |
| 11 | ref_count: usize, | |
| 11 | ref_count: std.atomic.Int(usize), | |
| 12 | 12 | |
| 13 | /// Thread-safe | |
| 13 | 14 | pub fn ref(base: *Value) void { |
| 14 | base.ref_count += 1; | |
| 15 | _ = base.ref_count.incr(); | |
| 15 | 16 | } |
| 16 | 17 | |
| 18 | /// Thread-safe | |
| 17 | 19 | 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) { | |
| 20 | 21 | base.typeof.base.deref(module); |
| 21 | 22 | switch (base.id) { |
| 22 | 23 | Id.Type => @fieldParentPtr(Type, "base", base).destroy(module), |
| ... | ... | @@ -52,6 +53,10 @@ pub const Value = struct { |
| 52 | 53 | pub const Fn = struct { |
| 53 | 54 | base: Value, |
| 54 | 55 | |
| 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 | 60 | /// parent should be the top level decls or container decls |
| 56 | 61 | fndef_scope: *Scope.FnDef, |
| 57 | 62 | |
| ... | ... | @@ -62,16 +67,18 @@ pub const Value = struct { |
| 62 | 67 | block_scope: *Scope.Block, |
| 63 | 68 | |
| 64 | 69 | /// 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 | 72 | const self = try module.a().create(Fn{ |
| 67 | 73 | .base = Value{ |
| 68 | 74 | .id = Value.Id.Fn, |
| 69 | 75 | .typeof = &fn_type.base, |
| 70 | .ref_count = 1, | |
| 76 | .ref_count = std.atomic.Int(usize).init(1), | |
| 71 | 77 | }, |
| 72 | 78 | .fndef_scope = fndef_scope, |
| 73 | 79 | .child_scope = &fndef_scope.base, |
| 74 | 80 | .block_scope = undefined, |
| 81 | .symbol_name = symbol_name, | |
| 75 | 82 | }); |
| 76 | 83 | fn_type.base.base.ref(); |
| 77 | 84 | fndef_scope.fn_val = self; |
| ... | ... | @@ -81,6 +88,7 @@ pub const Value = struct { |
| 81 | 88 | |
| 82 | 89 | pub fn destroy(self: *Fn, module: *Module) void { |
| 83 | 90 | self.fndef_scope.base.deref(module); |
| 91 | self.symbol_name.deinit(); | |
| 84 | 92 | module.a().destroy(self); |
| 85 | 93 | } |
| 86 | 94 | }; |
std/atomic/int.zig+14-4| ... | ... | @@ -4,16 +4,26 @@ const AtomicOrder = builtin.AtomicOrder; |
| 4 | 4 | /// Thread-safe, lock-free integer |
| 5 | 5 | pub fn Int(comptime T: type) type { |
| 6 | 6 | return struct { |
| 7 | value: T, | |
| 7 | unprotected_value: T, | |
| 8 | 8 | |
| 9 | 9 | pub const Self = this; |
| 10 | 10 | |
| 11 | 11 | pub fn init(init_val: T) Self { |
| 12 | return Self{ .value = init_val }; | |
| 12 | return Self{ .unprotected_value = init_val }; | |
| 13 | 13 | } |
| 14 | 14 | |
| 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); | |
| 17 | 27 | } |
| 18 | 28 | }; |
| 19 | 29 | } |
std/event/loop.zig-1| ... | ... | @@ -101,7 +101,6 @@ pub const Loop = struct { |
| 101 | 101 | errdefer self.deinitOsData(); |
| 102 | 102 | } |
| 103 | 103 | |
| 104 | /// must call stop before deinit | |
| 105 | 104 | pub fn deinit(self: *Loop) void { |
| 106 | 105 | self.deinitOsData(); |
| 107 | 106 | self.allocator.free(self.extra_threads); |