| 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,15 +375,8 @@ pub const Instruction = struct { |
| 375 | 375 | ||
| 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); |
| 380 | 379 | 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"); |
| 2 | const c = @import("c.zig"); | 2 | const c = @import("c.zig"); |
| 3 | const assert = @import("std").debug.assert; | 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 | pub const BuilderRef = removeNullability(c.LLVMBuilderRef); | 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 | fn removeNullability(comptime T: type) type { | 27 | fn 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"); |
| 14 | const introspect = @import("introspect.zig"); | 14 | const introspect = @import("introspect.zig"); |
| 15 | const Args = arg.Args; | 15 | const Args = arg.Args; |
| 16 | const Flag = arg.Flag; | 16 | const Flag = arg.Flag; |
| 17 | const EventLoopLocal = @import("module.zig").EventLoopLocal; | ||
| 17 | const Module = @import("module.zig").Module; | 18 | const Module = @import("module.zig").Module; |
| 18 | const Target = @import("target.zig").Target; | 19 | const Target = @import("target.zig").Target; |
| 19 | const errmsg = @import("errmsg.zig"); | 20 | const 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 |
| 386 | 387 | ||
| 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(); | ||
| 389 | 394 | ||
| 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; |
| 25 | const Value = @import("value.zig").Value; | 25 | const Value = @import("value.zig").Value; |
| 26 | const Type = Value.Type; | 26 | const Type = Value.Type; |
| 27 | const Span = errmsg.Span; | 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 | pub const Module = struct { | 75 | pub 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 | }; |
| 188 | 232 | ||
| 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(); |
| 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 | 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(); |
| 213 | 250 | ||
| 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 twice | 328 | .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 | } |
| 377 | 412 | ||
| 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); |
| 390 | 421 | ||
| 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(); |
| 396 | 424 | ||
| 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); |
| 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 | defer fn_type.base.base.deref(module); | 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 | defer fn_val.base.deref(module); | 701 | defer fn_val.base.deref(module); |
| 665 | 702 | ||
| 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 means | 712 | // 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 means | 731 | // 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()); |
| 699 | 738 | ||
| 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 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 +6,7 @@ const Module = @import("module.zig").Module; |
| 6 | const introspect = @import("introspect.zig"); | 6 | const introspect = @import("introspect.zig"); |
| 7 | const assertOrPanic = std.debug.assertOrPanic; | 7 | const assertOrPanic = std.debug.assertOrPanic; |
| 8 | const errmsg = @import("errmsg.zig"); | 8 | const errmsg = @import("errmsg.zig"); |
| 9 | const EventLoopLocal = @import("module.zig").EventLoopLocal; | ||
| 9 | 10 | ||
| 10 | test "compile errors" { | 11 | test "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; |
| 22 | 23 | ||
| 23 | pub const TestContext = struct { | 24 | pub 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(); |
| 45 | 48 | ||
| 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(); |
| 48 | 54 | ||
| ... | @@ -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 | } |
| 65 | 72 | ||
| ... | @@ -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); |
| 88 | 95 | ||
| 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); |
| 95 | 102 | ||
| 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 @@ |
| 1 | const std = @import("std"); | ||
| 1 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 2 | const Scope = @import("scope.zig").Scope; | 3 | const Scope = @import("scope.zig").Scope; |
| 3 | const Module = @import("module.zig").Module; | 4 | const Module = @import("module.zig").Module; |
| 4 | const Value = @import("value.zig").Value; | 5 | const Value = @import("value.zig").Value; |
| 6 | const llvm = @import("llvm.zig"); | ||
| 7 | const CompilationUnit = @import("codegen.zig").CompilationUnit; | ||
| 5 | 8 | ||
| 6 | pub const Type = struct { | 9 | pub 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 | } |
| 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 | 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 | }; |
| 58 | 95 | ||
| 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, | ||
| 61 | 101 | ||
| 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 | } |
| 74 | 129 | ||
| 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 | }; |
| 79 | 157 | ||
| 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 | }; |
| 122 | 204 | ||
| 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 | }; |
| 144 | 230 | ||
| 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, |
| 186 | 281 | ||
| 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, |
| 193 | 293 | ||
| ... | @@ -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, |
| 200 | 301 | ||
| ... | @@ -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, |
| 207 | 309 | ||
| ... | @@ -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, |
| 214 | 317 | ||
| ... | @@ -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, |
| 221 | 325 | ||
| 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, |
| 228 | 337 | ||
| 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, |
| 235 | 349 | ||
| 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, |
| 242 | 361 | ||
| 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, |
| 249 | 373 | ||
| 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, |
| 256 | 385 | ||
| ... | @@ -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 | }; |
| 277 | 410 | ||
| 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 | }; |
| 293 | 430 | ||
| 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; |
| 8 | pub const Value = struct { | 8 | pub 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), |
| 12 | 12 | ||
| 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 | } |
| 16 | 17 | ||
| 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, |
| 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 | /// parent should be the top level decls or container decls | 60 | /// parent should be the top level decls or container decls |
| 56 | fndef_scope: *Scope.FnDef, | 61 | fndef_scope: *Scope.FnDef, |
| 57 | 62 | ||
| ... | @@ -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, |
| 63 | 68 | ||
| 64 | /// Creates a Fn value with 1 ref | 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 | 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 { |
| 81 | 88 | ||
| 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 integer | 4 | /// Thread-safe, lock-free integer |
| 5 | pub fn Int(comptime T: type) type { | 5 | pub fn Int(comptime T: type) type { |
| 6 | return struct { | 6 | return struct { |
| 7 | value: T, | 7 | unprotected_value: T, |
| 8 | 8 | ||
| 9 | pub const Self = this; | 9 | pub const Self = this; |
| 10 | 10 | ||
| 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 | } |
| 14 | 14 | ||
| 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 | } |
| 103 | 103 | ||
| 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); |