| author | |
| committer | |
| log | 97bfeac13f89e1b5a22fcd7d4705341b4c3e1950 |
| tree | 4a3e23a8b3908450b23f2dbba72e5f6c091d7114 |
| parent | 0fa24b6b7568557c29c9b3ee213ce2b06fcd6367 |
20 files changed, 808 insertions(+), 175 deletions(-)
CMakeLists.txt+1| ... | @@ -479,6 +479,7 @@ set(ZIG_STD_FILES | ... | @@ -479,6 +479,7 @@ set(ZIG_STD_FILES |
| 479 | "index.zig" | 479 | "index.zig" |
| 480 | "io.zig" | 480 | "io.zig" |
| 481 | "json.zig" | 481 | "json.zig" |
| 482 | "lazy_init.zig" | ||
| 482 | "linked_list.zig" | 483 | "linked_list.zig" |
| 483 | "macho.zig" | 484 | "macho.zig" |
| 484 | "math/acos.zig" | 485 | "math/acos.zig" |
src-self-hosted/codegen.zig+78-8| ... | @@ -1,19 +1,22 @@ | ... | @@ -1,19 +1,22 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = @import("builtin"); | ||
| 2 | const Compilation = @import("compilation.zig").Compilation; | 3 | const Compilation = @import("compilation.zig").Compilation; |
| 3 | // we go through llvm instead of c for 2 reasons: | ||
| 4 | // 1. to avoid accidentally calling the non-thread-safe functions | ||
| 5 | // 2. patch up some of the types to remove nullability | ||
| 6 | const llvm = @import("llvm.zig"); | 4 | const llvm = @import("llvm.zig"); |
| 5 | const c = @import("c.zig"); | ||
| 7 | const ir = @import("ir.zig"); | 6 | const ir = @import("ir.zig"); |
| 8 | const Value = @import("value.zig").Value; | 7 | const Value = @import("value.zig").Value; |
| 9 | const Type = @import("type.zig").Type; | 8 | const Type = @import("type.zig").Type; |
| 10 | const event = std.event; | 9 | const event = std.event; |
| 11 | const assert = std.debug.assert; | 10 | const assert = std.debug.assert; |
| 11 | const DW = std.dwarf; | ||
| 12 | 12 | ||
| 13 | pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) !void { | 13 | pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) !void { |
| 14 | fn_val.base.ref(); | 14 | fn_val.base.ref(); |
| 15 | defer fn_val.base.deref(comp); | 15 | defer fn_val.base.deref(comp); |
| 16 | defer code.destroy(comp.a()); | 16 | defer code.destroy(comp.gpa()); |
| 17 | |||
| 18 | var output_path = try await (async comp.createRandomOutputPath(comp.target.oFileExt()) catch unreachable); | ||
| 19 | errdefer output_path.deinit(); | ||
| 17 | 20 | ||
| 18 | const llvm_handle = try comp.event_loop_local.getAnyLlvmContext(); | 21 | const llvm_handle = try comp.event_loop_local.getAnyLlvmContext(); |
| 19 | defer llvm_handle.release(comp.event_loop_local); | 22 | defer llvm_handle.release(comp.event_loop_local); |
| ... | @@ -23,13 +26,56 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) | ... | @@ -23,13 +26,56 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) |
| 23 | const module = llvm.ModuleCreateWithNameInContext(comp.name.ptr(), context) orelse return error.OutOfMemory; | 26 | const module = llvm.ModuleCreateWithNameInContext(comp.name.ptr(), context) orelse return error.OutOfMemory; |
| 24 | defer llvm.DisposeModule(module); | 27 | defer llvm.DisposeModule(module); |
| 25 | 28 | ||
| 29 | llvm.SetTarget(module, comp.llvm_triple.ptr()); | ||
| 30 | llvm.SetDataLayout(module, comp.target_layout_str); | ||
| 31 | |||
| 32 | if (comp.target.getObjectFormat() == builtin.ObjectFormat.coff) { | ||
| 33 | llvm.AddModuleCodeViewFlag(module); | ||
| 34 | } else { | ||
| 35 | llvm.AddModuleDebugInfoFlag(module); | ||
| 36 | } | ||
| 37 | |||
| 26 | const builder = llvm.CreateBuilderInContext(context) orelse return error.OutOfMemory; | 38 | const builder = llvm.CreateBuilderInContext(context) orelse return error.OutOfMemory; |
| 27 | defer llvm.DisposeBuilder(builder); | 39 | defer llvm.DisposeBuilder(builder); |
| 28 | 40 | ||
| 41 | const dibuilder = llvm.CreateDIBuilder(module, true) orelse return error.OutOfMemory; | ||
| 42 | defer llvm.DisposeDIBuilder(dibuilder); | ||
| 43 | |||
| 44 | // Don't use ZIG_VERSION_STRING here. LLVM misparses it when it includes | ||
| 45 | // the git revision. | ||
| 46 | const producer = try std.Buffer.allocPrint( | ||
| 47 | &code.arena.allocator, | ||
| 48 | "zig {}.{}.{}", | ||
| 49 | u32(c.ZIG_VERSION_MAJOR), | ||
| 50 | u32(c.ZIG_VERSION_MINOR), | ||
| 51 | u32(c.ZIG_VERSION_PATCH), | ||
| 52 | ); | ||
| 53 | const flags = c""; | ||
| 54 | const runtime_version = 0; | ||
| 55 | const compile_unit_file = llvm.CreateFile( | ||
| 56 | dibuilder, | ||
| 57 | comp.name.ptr(), | ||
| 58 | comp.root_package.root_src_dir.ptr(), | ||
| 59 | ) orelse return error.OutOfMemory; | ||
| 60 | const is_optimized = comp.build_mode != builtin.Mode.Debug; | ||
| 61 | const compile_unit = llvm.CreateCompileUnit( | ||
| 62 | dibuilder, | ||
| 63 | DW.LANG_C99, | ||
| 64 | compile_unit_file, | ||
| 65 | producer.ptr(), | ||
| 66 | is_optimized, | ||
| 67 | flags, | ||
| 68 | runtime_version, | ||
| 69 | c"", | ||
| 70 | 0, | ||
| 71 | !comp.strip, | ||
| 72 | ) orelse return error.OutOfMemory; | ||
| 73 | |||
| 29 | var ofile = ObjectFile{ | 74 | var ofile = ObjectFile{ |
| 30 | .comp = comp, | 75 | .comp = comp, |
| 31 | .module = module, | 76 | .module = module, |
| 32 | .builder = builder, | 77 | .builder = builder, |
| 78 | .dibuilder = dibuilder, | ||
| 33 | .context = context, | 79 | .context = context, |
| 34 | .lock = event.Lock.init(comp.loop), | 80 | .lock = event.Lock.init(comp.loop), |
| 35 | }; | 81 | }; |
| ... | @@ -41,8 +87,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) | ... | @@ -41,8 +87,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) |
| 41 | // LLVMSetModuleInlineAsm(g->module, buf_ptr(&g->global_asm)); | 87 | // LLVMSetModuleInlineAsm(g->module, buf_ptr(&g->global_asm)); |
| 42 | //} | 88 | //} |
| 43 | 89 | ||
| 44 | // TODO | 90 | llvm.DIBuilderFinalize(dibuilder); |
| 45 | //ZigLLVMDIBuilderFinalize(g->dbuilder); | ||
| 46 | 91 | ||
| 47 | if (comp.verbose_llvm_ir) { | 92 | if (comp.verbose_llvm_ir) { |
| 48 | llvm.DumpModule(ofile.module); | 93 | llvm.DumpModule(ofile.module); |
| ... | @@ -53,17 +98,42 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) | ... | @@ -53,17 +98,42 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) |
| 53 | var error_ptr: ?[*]u8 = null; | 98 | var error_ptr: ?[*]u8 = null; |
| 54 | _ = llvm.VerifyModule(ofile.module, llvm.AbortProcessAction, &error_ptr); | 99 | _ = llvm.VerifyModule(ofile.module, llvm.AbortProcessAction, &error_ptr); |
| 55 | } | 100 | } |
| 101 | |||
| 102 | assert(comp.emit_file_type == Compilation.Emit.Binary); // TODO support other types | ||
| 103 | |||
| 104 | const is_small = comp.build_mode == builtin.Mode.ReleaseSmall; | ||
| 105 | const is_debug = comp.build_mode == builtin.Mode.Debug; | ||
| 106 | |||
| 107 | var err_msg: [*]u8 = undefined; | ||
| 108 | // TODO integrate this with evented I/O | ||
| 109 | if (llvm.TargetMachineEmitToFile( | ||
| 110 | comp.target_machine, | ||
| 111 | module, | ||
| 112 | output_path.ptr(), | ||
| 113 | llvm.EmitBinary, | ||
| 114 | &err_msg, | ||
| 115 | is_debug, | ||
| 116 | is_small, | ||
| 117 | )) { | ||
| 118 | if (std.debug.runtime_safety) { | ||
| 119 | std.debug.panic("unable to write object file {}: {s}\n", output_path.toSliceConst(), err_msg); | ||
| 120 | } | ||
| 121 | return error.WritingObjectFileFailed; | ||
| 122 | } | ||
| 123 | //validate_inline_fns(g); TODO | ||
| 124 | fn_val.containing_object = output_path; | ||
| 56 | } | 125 | } |
| 57 | 126 | ||
| 58 | pub const ObjectFile = struct { | 127 | pub const ObjectFile = struct { |
| 59 | comp: *Compilation, | 128 | comp: *Compilation, |
| 60 | module: llvm.ModuleRef, | 129 | module: llvm.ModuleRef, |
| 61 | builder: llvm.BuilderRef, | 130 | builder: llvm.BuilderRef, |
| 131 | dibuilder: *llvm.DIBuilder, | ||
| 62 | context: llvm.ContextRef, | 132 | context: llvm.ContextRef, |
| 63 | lock: event.Lock, | 133 | lock: event.Lock, |
| 64 | 134 | ||
| 65 | fn a(self: *ObjectFile) *std.mem.Allocator { | 135 | fn gpa(self: *ObjectFile) *std.mem.Allocator { |
| 66 | return self.comp.a(); | 136 | return self.comp.gpa(); |
| 67 | } | 137 | } |
| 68 | }; | 138 | }; |
| 69 | 139 |
src-self-hosted/compilation.zig+270-65| ... | @@ -26,16 +26,31 @@ const Value = @import("value.zig").Value; | ... | @@ -26,16 +26,31 @@ 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"); | 28 | const codegen = @import("codegen.zig"); |
| 29 | const Package = @import("package.zig").Package; | ||
| 29 | 30 | ||
| 30 | /// Data that is local to the event loop. | 31 | /// Data that is local to the event loop. |
| 31 | pub const EventLoopLocal = struct { | 32 | pub const EventLoopLocal = struct { |
| 32 | loop: *event.Loop, | 33 | loop: *event.Loop, |
| 33 | llvm_handle_pool: std.atomic.Stack(llvm.ContextRef), | 34 | llvm_handle_pool: std.atomic.Stack(llvm.ContextRef), |
| 34 | 35 | ||
| 35 | fn init(loop: *event.Loop) EventLoopLocal { | 36 | /// TODO pool these so that it doesn't have to lock |
| 37 | prng: event.Locked(std.rand.DefaultPrng), | ||
| 38 | |||
| 39 | var lazy_init_targets = std.lazyInit(void); | ||
| 40 | |||
| 41 | fn init(loop: *event.Loop) !EventLoopLocal { | ||
| 42 | lazy_init_targets.get() orelse { | ||
| 43 | Target.initializeAll(); | ||
| 44 | lazy_init_targets.resolve(); | ||
| 45 | }; | ||
| 46 | |||
| 47 | var seed_bytes: [@sizeOf(u64)]u8 = undefined; | ||
| 48 | try std.os.getRandomBytes(seed_bytes[0..]); | ||
| 49 | const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big); | ||
| 36 | return EventLoopLocal{ | 50 | return EventLoopLocal{ |
| 37 | .loop = loop, | 51 | .loop = loop, |
| 38 | .llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(), | 52 | .llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(), |
| 53 | .prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)), | ||
| 39 | }; | 54 | }; |
| 40 | } | 55 | } |
| 41 | 56 | ||
| ... | @@ -76,10 +91,16 @@ pub const Compilation = struct { | ... | @@ -76,10 +91,16 @@ pub const Compilation = struct { |
| 76 | event_loop_local: *EventLoopLocal, | 91 | event_loop_local: *EventLoopLocal, |
| 77 | loop: *event.Loop, | 92 | loop: *event.Loop, |
| 78 | name: Buffer, | 93 | name: Buffer, |
| 94 | llvm_triple: Buffer, | ||
| 79 | root_src_path: ?[]const u8, | 95 | root_src_path: ?[]const u8, |
| 80 | target: Target, | 96 | target: Target, |
| 97 | llvm_target: llvm.TargetRef, | ||
| 81 | build_mode: builtin.Mode, | 98 | build_mode: builtin.Mode, |
| 82 | zig_lib_dir: []const u8, | 99 | zig_lib_dir: []const u8, |
| 100 | zig_std_dir: []const u8, | ||
| 101 | |||
| 102 | /// lazily created when we need it | ||
| 103 | tmp_dir: event.Future(BuildError![]u8), | ||
| 83 | 104 | ||
| 84 | version_major: u32, | 105 | version_major: u32, |
| 85 | version_minor: u32, | 106 | version_minor: u32, |
| ... | @@ -106,8 +127,16 @@ pub const Compilation = struct { | ... | @@ -106,8 +127,16 @@ pub const Compilation = struct { |
| 106 | lib_dirs: []const []const u8, | 127 | lib_dirs: []const []const u8, |
| 107 | rpath_list: []const []const u8, | 128 | rpath_list: []const []const u8, |
| 108 | assembly_files: []const []const u8, | 129 | assembly_files: []const []const u8, |
| 130 | |||
| 131 | /// paths that are explicitly provided by the user to link against | ||
| 109 | link_objects: []const []const u8, | 132 | link_objects: []const []const u8, |
| 110 | 133 | ||
| 134 | /// functions that have their own objects that we need to link | ||
| 135 | /// it uses an optional pointer so that tombstone removals are possible | ||
| 136 | fn_link_set: event.Locked(FnLinkSet), | ||
| 137 | |||
| 138 | pub const FnLinkSet = std.LinkedList(?*Value.Fn); | ||
| 139 | |||
| 111 | windows_subsystem_windows: bool, | 140 | windows_subsystem_windows: bool, |
| 112 | windows_subsystem_console: bool, | 141 | windows_subsystem_console: bool, |
| 113 | 142 | ||
| ... | @@ -141,7 +170,7 @@ pub const Compilation = struct { | ... | @@ -141,7 +170,7 @@ pub const Compilation = struct { |
| 141 | 170 | ||
| 142 | /// Before code generation starts, must wait on this group to make sure | 171 | /// Before code generation starts, must wait on this group to make sure |
| 143 | /// the build is complete. | 172 | /// the build is complete. |
| 144 | build_group: event.Group(BuildError!void), | 173 | prelink_group: event.Group(BuildError!void), |
| 145 | 174 | ||
| 146 | compile_errors: event.Locked(CompileErrList), | 175 | compile_errors: event.Locked(CompileErrList), |
| 147 | 176 | ||
| ... | @@ -155,6 +184,16 @@ pub const Compilation = struct { | ... | @@ -155,6 +184,16 @@ pub const Compilation = struct { |
| 155 | false_value: *Value.Bool, | 184 | false_value: *Value.Bool, |
| 156 | noreturn_value: *Value.NoReturn, | 185 | noreturn_value: *Value.NoReturn, |
| 157 | 186 | ||
| 187 | target_machine: llvm.TargetMachineRef, | ||
| 188 | target_data_ref: llvm.TargetDataRef, | ||
| 189 | target_layout_str: [*]u8, | ||
| 190 | |||
| 191 | /// for allocating things which have the same lifetime as this Compilation | ||
| 192 | arena_allocator: std.heap.ArenaAllocator, | ||
| 193 | |||
| 194 | root_package: *Package, | ||
| 195 | std_package: *Package, | ||
| 196 | |||
| 158 | const CompileErrList = std.ArrayList(*errmsg.Msg); | 197 | const CompileErrList = std.ArrayList(*errmsg.Msg); |
| 159 | 198 | ||
| 160 | // TODO handle some of these earlier and report them in a way other than error codes | 199 | // TODO handle some of these earlier and report them in a way other than error codes |
| ... | @@ -195,6 +234,9 @@ pub const Compilation = struct { | ... | @@ -195,6 +234,9 @@ pub const Compilation = struct { |
| 195 | BufferTooSmall, | 234 | BufferTooSmall, |
| 196 | Unimplemented, // TODO remove this one | 235 | Unimplemented, // TODO remove this one |
| 197 | SemanticAnalysisFailed, // TODO remove this one | 236 | SemanticAnalysisFailed, // TODO remove this one |
| 237 | ReadOnlyFileSystem, | ||
| 238 | LinkQuotaExceeded, | ||
| 239 | EnvironmentVariableNotFound, | ||
| 198 | }; | 240 | }; |
| 199 | 241 | ||
| 200 | pub const Event = union(enum) { | 242 | pub const Event = union(enum) { |
| ... | @@ -234,31 +276,31 @@ pub const Compilation = struct { | ... | @@ -234,31 +276,31 @@ pub const Compilation = struct { |
| 234 | event_loop_local: *EventLoopLocal, | 276 | event_loop_local: *EventLoopLocal, |
| 235 | name: []const u8, | 277 | name: []const u8, |
| 236 | root_src_path: ?[]const u8, | 278 | root_src_path: ?[]const u8, |
| 237 | target: *const Target, | 279 | target: Target, |
| 238 | kind: Kind, | 280 | kind: Kind, |
| 239 | build_mode: builtin.Mode, | 281 | build_mode: builtin.Mode, |
| 282 | is_static: bool, | ||
| 240 | zig_lib_dir: []const u8, | 283 | zig_lib_dir: []const u8, |
| 241 | cache_dir: []const u8, | 284 | cache_dir: []const u8, |
| 242 | ) !*Compilation { | 285 | ) !*Compilation { |
| 243 | const loop = event_loop_local.loop; | 286 | const loop = event_loop_local.loop; |
| 244 | 287 | const comp = try event_loop_local.loop.allocator.create(Compilation{ | |
| 245 | var name_buffer = try Buffer.init(loop.allocator, name); | ||
| 246 | errdefer name_buffer.deinit(); | ||
| 247 | |||
| 248 | const events = try event.Channel(Event).create(loop, 0); | ||
| 249 | errdefer events.destroy(); | ||
| 250 | |||
| 251 | const comp = try loop.allocator.create(Compilation{ | ||
| 252 | .loop = loop, | 288 | .loop = loop, |
| 289 | .arena_allocator = std.heap.ArenaAllocator.init(loop.allocator), | ||
| 253 | .event_loop_local = event_loop_local, | 290 | .event_loop_local = event_loop_local, |
| 254 | .events = events, | 291 | .events = undefined, |
| 255 | .name = name_buffer, | ||
| 256 | .root_src_path = root_src_path, | 292 | .root_src_path = root_src_path, |
| 257 | .target = target.*, | 293 | .target = target, |
| 294 | .llvm_target = undefined, | ||
| 258 | .kind = kind, | 295 | .kind = kind, |
| 259 | .build_mode = build_mode, | 296 | .build_mode = build_mode, |
| 260 | .zig_lib_dir = zig_lib_dir, | 297 | .zig_lib_dir = zig_lib_dir, |
| 298 | .zig_std_dir = undefined, | ||
| 261 | .cache_dir = cache_dir, | 299 | .cache_dir = cache_dir, |
| 300 | .tmp_dir = event.Future(BuildError![]u8).init(loop), | ||
| 301 | |||
| 302 | .name = undefined, | ||
| 303 | .llvm_triple = undefined, | ||
| 262 | 304 | ||
| 263 | .version_major = 0, | 305 | .version_major = 0, |
| 264 | .version_minor = 0, | 306 | .version_minor = 0, |
| ... | @@ -283,7 +325,7 @@ pub const Compilation = struct { | ... | @@ -283,7 +325,7 @@ pub const Compilation = struct { |
| 283 | .is_test = false, | 325 | .is_test = false, |
| 284 | .each_lib_rpath = false, | 326 | .each_lib_rpath = false, |
| 285 | .strip = false, | 327 | .strip = false, |
| 286 | .is_static = false, | 328 | .is_static = is_static, |
| 287 | .linker_rdynamic = false, | 329 | .linker_rdynamic = false, |
| 288 | .clang_argv = [][]const u8{}, | 330 | .clang_argv = [][]const u8{}, |
| 289 | .llvm_argv = [][]const u8{}, | 331 | .llvm_argv = [][]const u8{}, |
| ... | @@ -291,9 +333,10 @@ pub const Compilation = struct { | ... | @@ -291,9 +333,10 @@ pub const Compilation = struct { |
| 291 | .rpath_list = [][]const u8{}, | 333 | .rpath_list = [][]const u8{}, |
| 292 | .assembly_files = [][]const u8{}, | 334 | .assembly_files = [][]const u8{}, |
| 293 | .link_objects = [][]const u8{}, | 335 | .link_objects = [][]const u8{}, |
| 336 | .fn_link_set = event.Locked(FnLinkSet).init(loop, FnLinkSet.init()), | ||
| 294 | .windows_subsystem_windows = false, | 337 | .windows_subsystem_windows = false, |
| 295 | .windows_subsystem_console = false, | 338 | .windows_subsystem_console = false, |
| 296 | .link_libs_list = ArrayList(*LinkLib).init(loop.allocator), | 339 | .link_libs_list = undefined, |
| 297 | .libc_link_lib = null, | 340 | .libc_link_lib = null, |
| 298 | .err_color = errmsg.Color.Auto, | 341 | .err_color = errmsg.Color.Auto, |
| 299 | .darwin_frameworks = [][]const u8{}, | 342 | .darwin_frameworks = [][]const u8{}, |
| ... | @@ -303,7 +346,7 @@ pub const Compilation = struct { | ... | @@ -303,7 +346,7 @@ pub const Compilation = struct { |
| 303 | .emit_file_type = Emit.Binary, | 346 | .emit_file_type = Emit.Binary, |
| 304 | .link_out_file = null, | 347 | .link_out_file = null, |
| 305 | .exported_symbol_names = event.Locked(Decl.Table).init(loop, Decl.Table.init(loop.allocator)), | 348 | .exported_symbol_names = event.Locked(Decl.Table).init(loop, Decl.Table.init(loop.allocator)), |
| 306 | .build_group = event.Group(BuildError!void).init(loop), | 349 | .prelink_group = event.Group(BuildError!void).init(loop), |
| 307 | .compile_errors = event.Locked(CompileErrList).init(loop, CompileErrList.init(loop.allocator)), | 350 | .compile_errors = event.Locked(CompileErrList).init(loop, CompileErrList.init(loop.allocator)), |
| 308 | 351 | ||
| 309 | .meta_type = undefined, | 352 | .meta_type = undefined, |
| ... | @@ -314,13 +357,82 @@ pub const Compilation = struct { | ... | @@ -314,13 +357,82 @@ pub const Compilation = struct { |
| 314 | .false_value = undefined, | 357 | .false_value = undefined, |
| 315 | .noreturn_type = undefined, | 358 | .noreturn_type = undefined, |
| 316 | .noreturn_value = undefined, | 359 | .noreturn_value = undefined, |
| 360 | |||
| 361 | .target_machine = undefined, | ||
| 362 | .target_data_ref = undefined, | ||
| 363 | .target_layout_str = undefined, | ||
| 364 | |||
| 365 | .root_package = undefined, | ||
| 366 | .std_package = undefined, | ||
| 317 | }); | 367 | }); |
| 368 | errdefer { | ||
| 369 | comp.arena_allocator.deinit(); | ||
| 370 | comp.loop.allocator.destroy(comp); | ||
| 371 | } | ||
| 372 | |||
| 373 | comp.name = try Buffer.init(comp.arena(), name); | ||
| 374 | comp.llvm_triple = try target.getTriple(comp.arena()); | ||
| 375 | comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple); | ||
| 376 | comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena()); | ||
| 377 | comp.zig_std_dir = try std.os.path.join(comp.arena(), zig_lib_dir, "std"); | ||
| 378 | |||
| 379 | const opt_level = switch (build_mode) { | ||
| 380 | builtin.Mode.Debug => llvm.CodeGenLevelNone, | ||
| 381 | else => llvm.CodeGenLevelAggressive, | ||
| 382 | }; | ||
| 383 | |||
| 384 | const reloc_mode = if (is_static) llvm.RelocStatic else llvm.RelocPIC; | ||
| 385 | |||
| 386 | // LLVM creates invalid binaries on Windows sometimes. | ||
| 387 | // See https://github.com/ziglang/zig/issues/508 | ||
| 388 | // As a workaround we do not use target native features on Windows. | ||
| 389 | var target_specific_cpu_args: ?[*]u8 = null; | ||
| 390 | var target_specific_cpu_features: ?[*]u8 = null; | ||
| 391 | errdefer llvm.DisposeMessage(target_specific_cpu_args); | ||
| 392 | errdefer llvm.DisposeMessage(target_specific_cpu_features); | ||
| 393 | if (target == Target.Native and !target.isWindows()) { | ||
| 394 | target_specific_cpu_args = llvm.GetHostCPUName() orelse return error.OutOfMemory; | ||
| 395 | target_specific_cpu_features = llvm.GetNativeFeatures() orelse return error.OutOfMemory; | ||
| 396 | } | ||
| 397 | |||
| 398 | comp.target_machine = llvm.CreateTargetMachine( | ||
| 399 | comp.llvm_target, | ||
| 400 | comp.llvm_triple.ptr(), | ||
| 401 | target_specific_cpu_args orelse c"", | ||
| 402 | target_specific_cpu_features orelse c"", | ||
| 403 | opt_level, | ||
| 404 | reloc_mode, | ||
| 405 | llvm.CodeModelDefault, | ||
| 406 | ) orelse return error.OutOfMemory; | ||
| 407 | errdefer llvm.DisposeTargetMachine(comp.target_machine); | ||
| 408 | |||
| 409 | comp.target_data_ref = llvm.CreateTargetDataLayout(comp.target_machine) orelse return error.OutOfMemory; | ||
| 410 | errdefer llvm.DisposeTargetData(comp.target_data_ref); | ||
| 411 | |||
| 412 | comp.target_layout_str = llvm.CopyStringRepOfTargetData(comp.target_data_ref) orelse return error.OutOfMemory; | ||
| 413 | errdefer llvm.DisposeMessage(comp.target_layout_str); | ||
| 414 | |||
| 415 | comp.events = try event.Channel(Event).create(comp.loop, 0); | ||
| 416 | errdefer comp.events.destroy(); | ||
| 417 | |||
| 418 | if (root_src_path) |root_src| { | ||
| 419 | const dirname = std.os.path.dirname(root_src) orelse "."; | ||
| 420 | const basename = std.os.path.basename(root_src); | ||
| 421 | |||
| 422 | comp.root_package = try Package.create(comp.arena(), dirname, basename); | ||
| 423 | comp.std_package = try Package.create(comp.arena(), comp.zig_std_dir, "index.zig"); | ||
| 424 | try comp.root_package.add("std", comp.std_package); | ||
| 425 | } else { | ||
| 426 | comp.root_package = try Package.create(comp.arena(), ".", ""); | ||
| 427 | } | ||
| 428 | |||
| 318 | try comp.initTypes(); | 429 | try comp.initTypes(); |
| 430 | |||
| 319 | return comp; | 431 | return comp; |
| 320 | } | 432 | } |
| 321 | 433 | ||
| 322 | fn initTypes(comp: *Compilation) !void { | 434 | fn initTypes(comp: *Compilation) !void { |
| 323 | comp.meta_type = try comp.a().create(Type.MetaType{ | 435 | comp.meta_type = try comp.gpa().create(Type.MetaType{ |
| 324 | .base = Type{ | 436 | .base = Type{ |
| 325 | .base = Value{ | 437 | .base = Value{ |
| 326 | .id = Value.Id.Type, | 438 | .id = Value.Id.Type, |
| ... | @@ -333,9 +445,9 @@ pub const Compilation = struct { | ... | @@ -333,9 +445,9 @@ pub const Compilation = struct { |
| 333 | }); | 445 | }); |
| 334 | comp.meta_type.value = &comp.meta_type.base; | 446 | comp.meta_type.value = &comp.meta_type.base; |
| 335 | comp.meta_type.base.base.typeof = &comp.meta_type.base; | 447 | comp.meta_type.base.base.typeof = &comp.meta_type.base; |
| 336 | errdefer comp.a().destroy(comp.meta_type); | 448 | errdefer comp.gpa().destroy(comp.meta_type); |
| 337 | 449 | ||
| 338 | comp.void_type = try comp.a().create(Type.Void{ | 450 | comp.void_type = try comp.gpa().create(Type.Void{ |
| 339 | .base = Type{ | 451 | .base = Type{ |
| 340 | .base = Value{ | 452 | .base = Value{ |
| 341 | .id = Value.Id.Type, | 453 | .id = Value.Id.Type, |
| ... | @@ -345,9 +457,9 @@ pub const Compilation = struct { | ... | @@ -345,9 +457,9 @@ pub const Compilation = struct { |
| 345 | .id = builtin.TypeId.Void, | 457 | .id = builtin.TypeId.Void, |
| 346 | }, | 458 | }, |
| 347 | }); | 459 | }); |
| 348 | errdefer comp.a().destroy(comp.void_type); | 460 | errdefer comp.gpa().destroy(comp.void_type); |
| 349 | 461 | ||
| 350 | comp.noreturn_type = try comp.a().create(Type.NoReturn{ | 462 | comp.noreturn_type = try comp.gpa().create(Type.NoReturn{ |
| 351 | .base = Type{ | 463 | .base = Type{ |
| 352 | .base = Value{ | 464 | .base = Value{ |
| 353 | .id = Value.Id.Type, | 465 | .id = Value.Id.Type, |
| ... | @@ -357,9 +469,9 @@ pub const Compilation = struct { | ... | @@ -357,9 +469,9 @@ pub const Compilation = struct { |
| 357 | .id = builtin.TypeId.NoReturn, | 469 | .id = builtin.TypeId.NoReturn, |
| 358 | }, | 470 | }, |
| 359 | }); | 471 | }); |
| 360 | errdefer comp.a().destroy(comp.noreturn_type); | 472 | errdefer comp.gpa().destroy(comp.noreturn_type); |
| 361 | 473 | ||
| 362 | comp.bool_type = try comp.a().create(Type.Bool{ | 474 | comp.bool_type = try comp.gpa().create(Type.Bool{ |
| 363 | .base = Type{ | 475 | .base = Type{ |
| 364 | .base = Value{ | 476 | .base = Value{ |
| 365 | .id = Value.Id.Type, | 477 | .id = Value.Id.Type, |
| ... | @@ -369,18 +481,18 @@ pub const Compilation = struct { | ... | @@ -369,18 +481,18 @@ pub const Compilation = struct { |
| 369 | .id = builtin.TypeId.Bool, | 481 | .id = builtin.TypeId.Bool, |
| 370 | }, | 482 | }, |
| 371 | }); | 483 | }); |
| 372 | errdefer comp.a().destroy(comp.bool_type); | 484 | errdefer comp.gpa().destroy(comp.bool_type); |
| 373 | 485 | ||
| 374 | comp.void_value = try comp.a().create(Value.Void{ | 486 | comp.void_value = try comp.gpa().create(Value.Void{ |
| 375 | .base = Value{ | 487 | .base = Value{ |
| 376 | .id = Value.Id.Void, | 488 | .id = Value.Id.Void, |
| 377 | .typeof = &Type.Void.get(comp).base, | 489 | .typeof = &Type.Void.get(comp).base, |
| 378 | .ref_count = std.atomic.Int(usize).init(1), | 490 | .ref_count = std.atomic.Int(usize).init(1), |
| 379 | }, | 491 | }, |
| 380 | }); | 492 | }); |
| 381 | errdefer comp.a().destroy(comp.void_value); | 493 | errdefer comp.gpa().destroy(comp.void_value); |
| 382 | 494 | ||
| 383 | comp.true_value = try comp.a().create(Value.Bool{ | 495 | comp.true_value = try comp.gpa().create(Value.Bool{ |
| 384 | .base = Value{ | 496 | .base = Value{ |
| 385 | .id = Value.Id.Bool, | 497 | .id = Value.Id.Bool, |
| 386 | .typeof = &Type.Bool.get(comp).base, | 498 | .typeof = &Type.Bool.get(comp).base, |
| ... | @@ -388,9 +500,9 @@ pub const Compilation = struct { | ... | @@ -388,9 +500,9 @@ pub const Compilation = struct { |
| 388 | }, | 500 | }, |
| 389 | .x = true, | 501 | .x = true, |
| 390 | }); | 502 | }); |
| 391 | errdefer comp.a().destroy(comp.true_value); | 503 | errdefer comp.gpa().destroy(comp.true_value); |
| 392 | 504 | ||
| 393 | comp.false_value = try comp.a().create(Value.Bool{ | 505 | comp.false_value = try comp.gpa().create(Value.Bool{ |
| 394 | .base = Value{ | 506 | .base = Value{ |
| 395 | .id = Value.Id.Bool, | 507 | .id = Value.Id.Bool, |
| 396 | .typeof = &Type.Bool.get(comp).base, | 508 | .typeof = &Type.Bool.get(comp).base, |
| ... | @@ -398,19 +510,23 @@ pub const Compilation = struct { | ... | @@ -398,19 +510,23 @@ pub const Compilation = struct { |
| 398 | }, | 510 | }, |
| 399 | .x = false, | 511 | .x = false, |
| 400 | }); | 512 | }); |
| 401 | errdefer comp.a().destroy(comp.false_value); | 513 | errdefer comp.gpa().destroy(comp.false_value); |
| 402 | 514 | ||
| 403 | comp.noreturn_value = try comp.a().create(Value.NoReturn{ | 515 | comp.noreturn_value = try comp.gpa().create(Value.NoReturn{ |
| 404 | .base = Value{ | 516 | .base = Value{ |
| 405 | .id = Value.Id.NoReturn, | 517 | .id = Value.Id.NoReturn, |
| 406 | .typeof = &Type.NoReturn.get(comp).base, | 518 | .typeof = &Type.NoReturn.get(comp).base, |
| 407 | .ref_count = std.atomic.Int(usize).init(1), | 519 | .ref_count = std.atomic.Int(usize).init(1), |
| 408 | }, | 520 | }, |
| 409 | }); | 521 | }); |
| 410 | errdefer comp.a().destroy(comp.noreturn_value); | 522 | errdefer comp.gpa().destroy(comp.noreturn_value); |
| 411 | } | 523 | } |
| 412 | 524 | ||
| 413 | pub fn destroy(self: *Compilation) void { | 525 | pub fn destroy(self: *Compilation) void { |
| 526 | if (self.tmp_dir.getOrNull()) |tmp_dir_result| if (tmp_dir_result.*) |tmp_dir| { | ||
| 527 | os.deleteTree(self.arena(), tmp_dir) catch {}; | ||
| 528 | } else |_| {}; | ||
| 529 | |||
| 414 | self.noreturn_value.base.deref(self); | 530 | self.noreturn_value.base.deref(self); |
| 415 | self.void_value.base.deref(self); | 531 | self.void_value.base.deref(self); |
| 416 | self.false_value.base.deref(self); | 532 | self.false_value.base.deref(self); |
| ... | @@ -420,14 +536,18 @@ pub const Compilation = struct { | ... | @@ -420,14 +536,18 @@ pub const Compilation = struct { |
| 420 | self.meta_type.base.base.deref(self); | 536 | self.meta_type.base.base.deref(self); |
| 421 | 537 | ||
| 422 | self.events.destroy(); | 538 | self.events.destroy(); |
| 423 | self.name.deinit(); | ||
| 424 | 539 | ||
| 425 | self.a().destroy(self); | 540 | llvm.DisposeMessage(self.target_layout_str); |
| 541 | llvm.DisposeTargetData(self.target_data_ref); | ||
| 542 | llvm.DisposeTargetMachine(self.target_machine); | ||
| 543 | |||
| 544 | self.arena_allocator.deinit(); | ||
| 545 | self.gpa().destroy(self); | ||
| 426 | } | 546 | } |
| 427 | 547 | ||
| 428 | pub fn build(self: *Compilation) !void { | 548 | pub fn build(self: *Compilation) !void { |
| 429 | if (self.llvm_argv.len != 0) { | 549 | if (self.llvm_argv.len != 0) { |
| 430 | var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.a(), [][]const []const u8{ | 550 | var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.arena(), [][]const []const u8{ |
| 431 | [][]const u8{"zig (LLVM option parsing)"}, | 551 | [][]const u8{"zig (LLVM option parsing)"}, |
| 432 | self.llvm_argv, | 552 | self.llvm_argv, |
| 433 | }); | 553 | }); |
| ... | @@ -436,7 +556,7 @@ pub const Compilation = struct { | ... | @@ -436,7 +556,7 @@ pub const Compilation = struct { |
| 436 | c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr); | 556 | c.ZigLLVMParseCommandLineOptions(self.llvm_argv.len + 1, c_compatible_args.ptr); |
| 437 | } | 557 | } |
| 438 | 558 | ||
| 439 | _ = try async<self.a()> self.buildAsync(); | 559 | _ = try async<self.gpa()> self.buildAsync(); |
| 440 | } | 560 | } |
| 441 | 561 | ||
| 442 | async fn buildAsync(self: *Compilation) void { | 562 | async fn buildAsync(self: *Compilation) void { |
| ... | @@ -464,7 +584,7 @@ pub const Compilation = struct { | ... | @@ -464,7 +584,7 @@ pub const Compilation = struct { |
| 464 | } | 584 | } |
| 465 | } else |err| { | 585 | } else |err| { |
| 466 | // if there's an error then the compile errors have dangling references | 586 | // if there's an error then the compile errors have dangling references |
| 467 | self.a().free(compile_errors); | 587 | self.gpa().free(compile_errors); |
| 468 | 588 | ||
| 469 | await (async self.events.put(Event{ .Error = err }) catch unreachable); | 589 | await (async self.events.put(Event{ .Error = err }) catch unreachable); |
| 470 | } | 590 | } |
| ... | @@ -477,26 +597,26 @@ pub const Compilation = struct { | ... | @@ -477,26 +597,26 @@ pub const Compilation = struct { |
| 477 | async fn addRootSrc(self: *Compilation) !void { | 597 | async fn addRootSrc(self: *Compilation) !void { |
| 478 | const root_src_path = self.root_src_path orelse @panic("TODO handle null root src path"); | 598 | const root_src_path = self.root_src_path orelse @panic("TODO handle null root src path"); |
| 479 | // TODO async/await os.path.real | 599 | // TODO async/await os.path.real |
| 480 | const root_src_real_path = os.path.real(self.a(), root_src_path) catch |err| { | 600 | const root_src_real_path = os.path.real(self.gpa(), root_src_path) catch |err| { |
| 481 | try printError("unable to get real path '{}': {}", root_src_path, err); | 601 | try printError("unable to get real path '{}': {}", root_src_path, err); |
| 482 | return err; | 602 | return err; |
| 483 | }; | 603 | }; |
| 484 | errdefer self.a().free(root_src_real_path); | 604 | errdefer self.gpa().free(root_src_real_path); |
| 485 | 605 | ||
| 486 | // TODO async/await readFileAlloc() | 606 | // TODO async/await readFileAlloc() |
| 487 | const source_code = io.readFileAlloc(self.a(), root_src_real_path) catch |err| { | 607 | const source_code = io.readFileAlloc(self.gpa(), root_src_real_path) catch |err| { |
| 488 | try printError("unable to open '{}': {}", root_src_real_path, err); | 608 | try printError("unable to open '{}': {}", root_src_real_path, err); |
| 489 | return err; | 609 | return err; |
| 490 | }; | 610 | }; |
| 491 | errdefer self.a().free(source_code); | 611 | errdefer self.gpa().free(source_code); |
| 492 | 612 | ||
| 493 | const parsed_file = try self.a().create(ParsedFile{ | 613 | const parsed_file = try self.gpa().create(ParsedFile{ |
| 494 | .tree = undefined, | 614 | .tree = undefined, |
| 495 | .realpath = root_src_real_path, | 615 | .realpath = root_src_real_path, |
| 496 | }); | 616 | }); |
| 497 | errdefer self.a().destroy(parsed_file); | 617 | errdefer self.gpa().destroy(parsed_file); |
| 498 | 618 | ||
| 499 | parsed_file.tree = try std.zig.parse(self.a(), source_code); | 619 | parsed_file.tree = try std.zig.parse(self.gpa(), source_code); |
| 500 | errdefer parsed_file.tree.deinit(); | 620 | errdefer parsed_file.tree.deinit(); |
| 501 | 621 | ||
| 502 | const tree = &parsed_file.tree; | 622 | const tree = &parsed_file.tree; |
| ... | @@ -525,7 +645,7 @@ pub const Compilation = struct { | ... | @@ -525,7 +645,7 @@ pub const Compilation = struct { |
| 525 | continue; | 645 | continue; |
| 526 | }; | 646 | }; |
| 527 | 647 | ||
| 528 | const fn_decl = try self.a().create(Decl.Fn{ | 648 | const fn_decl = try self.gpa().create(Decl.Fn{ |
| 529 | .base = Decl{ | 649 | .base = Decl{ |
| 530 | .id = Decl.Id.Fn, | 650 | .id = Decl.Id.Fn, |
| 531 | .name = name, | 651 | .name = name, |
| ... | @@ -538,7 +658,7 @@ pub const Compilation = struct { | ... | @@ -538,7 +658,7 @@ pub const Compilation = struct { |
| 538 | .value = Decl.Fn.Val{ .Unresolved = {} }, | 658 | .value = Decl.Fn.Val{ .Unresolved = {} }, |
| 539 | .fn_proto = fn_proto, | 659 | .fn_proto = fn_proto, |
| 540 | }); | 660 | }); |
| 541 | errdefer self.a().destroy(fn_decl); | 661 | errdefer self.gpa().destroy(fn_decl); |
| 542 | 662 | ||
| 543 | try decl_group.call(addTopLevelDecl, self, &fn_decl.base); | 663 | try decl_group.call(addTopLevelDecl, self, &fn_decl.base); |
| 544 | }, | 664 | }, |
| ... | @@ -547,15 +667,15 @@ pub const Compilation = struct { | ... | @@ -547,15 +667,15 @@ pub const Compilation = struct { |
| 547 | } | 667 | } |
| 548 | } | 668 | } |
| 549 | try await (async decl_group.wait() catch unreachable); | 669 | try await (async decl_group.wait() catch unreachable); |
| 550 | try await (async self.build_group.wait() catch unreachable); | 670 | try await (async self.prelink_group.wait() catch unreachable); |
| 551 | } | 671 | } |
| 552 | 672 | ||
| 553 | async fn addTopLevelDecl(self: *Compilation, decl: *Decl) !void { | 673 | async fn addTopLevelDecl(self: *Compilation, decl: *Decl) !void { |
| 554 | const is_export = decl.isExported(&decl.parsed_file.tree); | 674 | const is_export = decl.isExported(&decl.parsed_file.tree); |
| 555 | 675 | ||
| 556 | if (is_export) { | 676 | if (is_export) { |
| 557 | try self.build_group.call(verifyUniqueSymbol, self, decl); | 677 | try self.prelink_group.call(verifyUniqueSymbol, self, decl); |
| 558 | try self.build_group.call(resolveDecl, self, decl); | 678 | try self.prelink_group.call(resolveDecl, self, decl); |
| 559 | } | 679 | } |
| 560 | } | 680 | } |
| 561 | 681 | ||
| ... | @@ -563,7 +683,7 @@ pub const Compilation = struct { | ... | @@ -563,7 +683,7 @@ pub const Compilation = struct { |
| 563 | const text = try std.fmt.allocPrint(self.loop.allocator, fmt, args); | 683 | const text = try std.fmt.allocPrint(self.loop.allocator, fmt, args); |
| 564 | errdefer self.loop.allocator.free(text); | 684 | errdefer self.loop.allocator.free(text); |
| 565 | 685 | ||
| 566 | try self.build_group.call(addCompileErrorAsync, self, parsed_file, span, text); | 686 | try self.prelink_group.call(addCompileErrorAsync, self, parsed_file, span, text); |
| 567 | } | 687 | } |
| 568 | 688 | ||
| 569 | async fn addCompileErrorAsync( | 689 | async fn addCompileErrorAsync( |
| ... | @@ -625,11 +745,11 @@ pub const Compilation = struct { | ... | @@ -625,11 +745,11 @@ pub const Compilation = struct { |
| 625 | } | 745 | } |
| 626 | } | 746 | } |
| 627 | 747 | ||
| 628 | const link_lib = try self.a().create(LinkLib{ | 748 | const link_lib = try self.gpa().create(LinkLib{ |
| 629 | .name = name, | 749 | .name = name, |
| 630 | .path = null, | 750 | .path = null, |
| 631 | .provided_explicitly = provided_explicitly, | 751 | .provided_explicitly = provided_explicitly, |
| 632 | .symbols = ArrayList([]u8).init(self.a()), | 752 | .symbols = ArrayList([]u8).init(self.gpa()), |
| 633 | }); | 753 | }); |
| 634 | try self.link_libs_list.append(link_lib); | 754 | try self.link_libs_list.append(link_lib); |
| 635 | if (is_libc) { | 755 | if (is_libc) { |
| ... | @@ -638,9 +758,71 @@ pub const Compilation = struct { | ... | @@ -638,9 +758,71 @@ pub const Compilation = struct { |
| 638 | return link_lib; | 758 | return link_lib; |
| 639 | } | 759 | } |
| 640 | 760 | ||
| 641 | fn a(self: Compilation) *mem.Allocator { | 761 | /// General Purpose Allocator. Must free when done. |
| 762 | fn gpa(self: Compilation) *mem.Allocator { | ||
| 642 | return self.loop.allocator; | 763 | return self.loop.allocator; |
| 643 | } | 764 | } |
| 765 | |||
| 766 | /// Arena Allocator. Automatically freed when the Compilation is destroyed. | ||
| 767 | fn arena(self: *Compilation) *mem.Allocator { | ||
| 768 | return &self.arena_allocator.allocator; | ||
| 769 | } | ||
| 770 | |||
| 771 | /// If the temporary directory for this compilation has not been created, it creates it. | ||
| 772 | /// Then it creates a random file name in that dir and returns it. | ||
| 773 | pub async fn createRandomOutputPath(self: *Compilation, suffix: []const u8) !Buffer { | ||
| 774 | const tmp_dir = try await (async self.getTmpDir() catch unreachable); | ||
| 775 | const file_prefix = await (async self.getRandomFileName() catch unreachable); | ||
| 776 | |||
| 777 | const file_name = try std.fmt.allocPrint(self.gpa(), "{}{}", file_prefix[0..], suffix); | ||
| 778 | defer self.gpa().free(file_name); | ||
| 779 | |||
| 780 | const full_path = try os.path.join(self.gpa(), tmp_dir, file_name[0..]); | ||
| 781 | errdefer self.gpa().free(full_path); | ||
| 782 | |||
| 783 | return Buffer.fromOwnedSlice(self.gpa(), full_path); | ||
| 784 | } | ||
| 785 | |||
| 786 | /// If the temporary directory for this Compilation has not been created, creates it. | ||
| 787 | /// Then returns it. The directory is unique to this Compilation and cleaned up when | ||
| 788 | /// the Compilation deinitializes. | ||
| 789 | async fn getTmpDir(self: *Compilation) ![]const u8 { | ||
| 790 | if (await (async self.tmp_dir.start() catch unreachable)) |ptr| return ptr.*; | ||
| 791 | self.tmp_dir.data = await (async self.getTmpDirImpl() catch unreachable); | ||
| 792 | self.tmp_dir.resolve(); | ||
| 793 | return self.tmp_dir.data; | ||
| 794 | } | ||
| 795 | |||
| 796 | async fn getTmpDirImpl(self: *Compilation) ![]u8 { | ||
| 797 | const comp_dir_name = await (async self.getRandomFileName() catch unreachable); | ||
| 798 | const zig_dir_path = try getZigDir(self.gpa()); | ||
| 799 | defer self.gpa().free(zig_dir_path); | ||
| 800 | |||
| 801 | const tmp_dir = try os.path.join(self.arena(), zig_dir_path, comp_dir_name[0..]); | ||
| 802 | try os.makePath(self.gpa(), tmp_dir); | ||
| 803 | return tmp_dir; | ||
| 804 | } | ||
| 805 | |||
| 806 | async fn getRandomFileName(self: *Compilation) [12]u8 { | ||
| 807 | // here we replace the standard +/ with -_ so that it can be used in a file name | ||
| 808 | const b64_fs_encoder = std.base64.Base64Encoder.init( | ||
| 809 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_", | ||
| 810 | std.base64.standard_pad_char, | ||
| 811 | ); | ||
| 812 | |||
| 813 | var rand_bytes: [9]u8 = undefined; | ||
| 814 | |||
| 815 | { | ||
| 816 | const held = await (async self.event_loop_local.prng.acquire() catch unreachable); | ||
| 817 | defer held.release(); | ||
| 818 | |||
| 819 | held.value.random.bytes(rand_bytes[0..]); | ||
| 820 | } | ||
| 821 | |||
| 822 | var result: [12]u8 = undefined; | ||
| 823 | b64_fs_encoder.encode(result[0..], rand_bytes); | ||
| 824 | return result; | ||
| 825 | } | ||
| 644 | }; | 826 | }; |
| 645 | 827 | ||
| 646 | fn printError(comptime format: []const u8, args: ...) !void { | 828 | fn printError(comptime format: []const u8, args: ...) !void { |
| ... | @@ -662,13 +844,11 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib | ... | @@ -662,13 +844,11 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib |
| 662 | 844 | ||
| 663 | /// This declaration has been blessed as going into the final code generation. | 845 | /// This declaration has been blessed as going into the final code generation. |
| 664 | pub async fn resolveDecl(comp: *Compilation, decl: *Decl) !void { | 846 | pub async fn resolveDecl(comp: *Compilation, decl: *Decl) !void { |
| 665 | if (@atomicRmw(u8, &decl.resolution_in_progress, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst) == 0) { | 847 | if (await (async decl.resolution.start() catch unreachable)) |ptr| return ptr.*; |
| 666 | decl.resolution.data = await (async generateDecl(comp, decl) catch unreachable); | 848 | |
| 667 | decl.resolution.resolve(); | 849 | decl.resolution.data = await (async generateDecl(comp, decl) catch unreachable); |
| 668 | return decl.resolution.data; | 850 | decl.resolution.resolve(); |
| 669 | } else { | 851 | return decl.resolution.data; |
| 670 | return (await (async decl.resolution.get() catch unreachable)).*; | ||
| 671 | } | ||
| 672 | } | 852 | } |
| 673 | 853 | ||
| 674 | /// The function that actually does the generation. | 854 | /// The function that actually does the generation. |
| ... | @@ -698,7 +878,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { | ... | @@ -698,7 +878,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 698 | const fn_type = try Type.Fn.create(comp, return_type, params, is_var_args); | 878 | const fn_type = try Type.Fn.create(comp, return_type, params, is_var_args); |
| 699 | defer fn_type.base.base.deref(comp); | 879 | defer fn_type.base.base.deref(comp); |
| 700 | 880 | ||
| 701 | var symbol_name = try std.Buffer.init(comp.a(), fn_decl.base.name); | 881 | var symbol_name = try std.Buffer.init(comp.gpa(), fn_decl.base.name); |
| 702 | errdefer symbol_name.deinit(); | 882 | errdefer symbol_name.deinit(); |
| 703 | 883 | ||
| 704 | const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name); | 884 | const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name); |
| ... | @@ -719,7 +899,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { | ... | @@ -719,7 +899,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 719 | error.SemanticAnalysisFailed => return {}, | 899 | error.SemanticAnalysisFailed => return {}, |
| 720 | else => return err, | 900 | else => return err, |
| 721 | }; | 901 | }; |
| 722 | defer unanalyzed_code.destroy(comp.a()); | 902 | defer unanalyzed_code.destroy(comp.gpa()); |
| 723 | 903 | ||
| 724 | if (comp.verbose_ir) { | 904 | if (comp.verbose_ir) { |
| 725 | std.debug.warn("unanalyzed:\n"); | 905 | std.debug.warn("unanalyzed:\n"); |
| ... | @@ -738,7 +918,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { | ... | @@ -738,7 +918,7 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 738 | error.SemanticAnalysisFailed => return {}, | 918 | error.SemanticAnalysisFailed => return {}, |
| 739 | else => return err, | 919 | else => return err, |
| 740 | }; | 920 | }; |
| 741 | errdefer analyzed_code.destroy(comp.a()); | 921 | errdefer analyzed_code.destroy(comp.gpa()); |
| 742 | 922 | ||
| 743 | if (comp.verbose_ir) { | 923 | if (comp.verbose_ir) { |
| 744 | std.debug.warn("analyzed:\n"); | 924 | std.debug.warn("analyzed:\n"); |
| ... | @@ -747,5 +927,30 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { | ... | @@ -747,5 +927,30 @@ async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void { |
| 747 | 927 | ||
| 748 | // Kick off rendering to LLVM module, but it doesn't block the fn decl | 928 | // Kick off rendering to LLVM module, but it doesn't block the fn decl |
| 749 | // analysis from being complete. | 929 | // analysis from being complete. |
| 750 | try comp.build_group.call(codegen.renderToLlvm, comp, fn_val, analyzed_code); | 930 | try comp.prelink_group.call(codegen.renderToLlvm, comp, fn_val, analyzed_code); |
| 931 | try comp.prelink_group.call(addFnToLinkSet, comp, fn_val); | ||
| 932 | } | ||
| 933 | |||
| 934 | async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void { | ||
| 935 | fn_val.base.ref(); | ||
| 936 | defer fn_val.base.deref(comp); | ||
| 937 | |||
| 938 | fn_val.link_set_node.data = fn_val; | ||
| 939 | |||
| 940 | const held = await (async comp.fn_link_set.acquire() catch unreachable); | ||
| 941 | defer held.release(); | ||
| 942 | |||
| 943 | held.value.append(fn_val.link_set_node); | ||
| 944 | } | ||
| 945 | |||
| 946 | fn getZigDir(allocator: *mem.Allocator) ![]u8 { | ||
| 947 | const home_dir = try getHomeDir(allocator); | ||
| 948 | defer allocator.free(home_dir); | ||
| 949 | |||
| 950 | return os.path.join(allocator, home_dir, ".zig"); | ||
| 951 | } | ||
| 952 | |||
| 953 | /// TODO move to zig std lib, and make it work for other OSes | ||
| 954 | fn getHomeDir(allocator: *mem.Allocator) ![]u8 { | ||
| 955 | return os.getEnvVarOwned(allocator, "HOME"); | ||
| 751 | } | 956 | } |
src-self-hosted/ir.zig+5-5| ... | @@ -453,7 +453,7 @@ pub const Code = struct { | ... | @@ -453,7 +453,7 @@ pub const Code = struct { |
| 453 | arena: std.heap.ArenaAllocator, | 453 | arena: std.heap.ArenaAllocator, |
| 454 | return_type: ?*Type, | 454 | return_type: ?*Type, |
| 455 | 455 | ||
| 456 | /// allocator is comp.a() | 456 | /// allocator is comp.gpa() |
| 457 | pub fn destroy(self: *Code, allocator: *Allocator) void { | 457 | pub fn destroy(self: *Code, allocator: *Allocator) void { |
| 458 | self.arena.deinit(); | 458 | self.arena.deinit(); |
| 459 | allocator.destroy(self); | 459 | allocator.destroy(self); |
| ... | @@ -483,13 +483,13 @@ pub const Builder = struct { | ... | @@ -483,13 +483,13 @@ pub const Builder = struct { |
| 483 | pub const Error = Analyze.Error; | 483 | pub const Error = Analyze.Error; |
| 484 | 484 | ||
| 485 | pub fn init(comp: *Compilation, parsed_file: *ParsedFile) !Builder { | 485 | pub fn init(comp: *Compilation, parsed_file: *ParsedFile) !Builder { |
| 486 | const code = try comp.a().create(Code{ | 486 | const code = try comp.gpa().create(Code{ |
| 487 | .basic_block_list = undefined, | 487 | .basic_block_list = undefined, |
| 488 | .arena = std.heap.ArenaAllocator.init(comp.a()), | 488 | .arena = std.heap.ArenaAllocator.init(comp.gpa()), |
| 489 | .return_type = null, | 489 | .return_type = null, |
| 490 | }); | 490 | }); |
| 491 | code.basic_block_list = std.ArrayList(*BasicBlock).init(&code.arena.allocator); | 491 | code.basic_block_list = std.ArrayList(*BasicBlock).init(&code.arena.allocator); |
| 492 | errdefer code.destroy(comp.a()); | 492 | errdefer code.destroy(comp.gpa()); |
| 493 | 493 | ||
| 494 | return Builder{ | 494 | return Builder{ |
| 495 | .comp = comp, | 495 | .comp = comp, |
| ... | @@ -502,7 +502,7 @@ pub const Builder = struct { | ... | @@ -502,7 +502,7 @@ pub const Builder = struct { |
| 502 | } | 502 | } |
| 503 | 503 | ||
| 504 | pub fn abort(self: *Builder) void { | 504 | pub fn abort(self: *Builder) void { |
| 505 | self.code.destroy(self.comp.a()); | 505 | self.code.destroy(self.comp.gpa()); |
| 506 | } | 506 | } |
| 507 | 507 | ||
| 508 | /// Call code.destroy() when done | 508 | /// Call code.destroy() when done |
src-self-hosted/llvm.zig+73-2| ... | @@ -2,6 +2,12 @@ const builtin = @import("builtin"); | ... | @@ -2,6 +2,12 @@ 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 | // we wrap the c module for 3 reasons: | ||
| 6 | // 1. to avoid accidentally calling the non-thread-safe functions | ||
| 7 | // 2. patch up some of the types to remove nullability | ||
| 8 | // 3. some functions have been augmented by zig_llvm.cpp to be more powerful, | ||
| 9 | // such as ZigLLVMTargetMachineEmitToFile | ||
| 10 | |||
| 5 | pub const AttributeIndex = c_uint; | 11 | pub const AttributeIndex = c_uint; |
| 6 | pub const Bool = c_int; | 12 | pub const Bool = c_int; |
| 7 | 13 | ||
| ... | @@ -12,25 +18,51 @@ pub const ValueRef = removeNullability(c.LLVMValueRef); | ... | @@ -12,25 +18,51 @@ pub const ValueRef = removeNullability(c.LLVMValueRef); |
| 12 | pub const TypeRef = removeNullability(c.LLVMTypeRef); | 18 | pub const TypeRef = removeNullability(c.LLVMTypeRef); |
| 13 | pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef); | 19 | pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef); |
| 14 | pub const AttributeRef = removeNullability(c.LLVMAttributeRef); | 20 | pub const AttributeRef = removeNullability(c.LLVMAttributeRef); |
| 21 | pub const TargetRef = removeNullability(c.LLVMTargetRef); | ||
| 22 | pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef); | ||
| 23 | pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef); | ||
| 24 | pub const DIBuilder = c.ZigLLVMDIBuilder; | ||
| 15 | 25 | ||
| 16 | pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex; | 26 | pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex; |
| 17 | pub const AddFunction = c.LLVMAddFunction; | 27 | pub const AddFunction = c.LLVMAddFunction; |
| 28 | pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag; | ||
| 29 | pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag; | ||
| 18 | pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation; | 30 | pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation; |
| 31 | pub const ConstAllOnes = c.LLVMConstAllOnes; | ||
| 19 | pub const ConstInt = c.LLVMConstInt; | 32 | pub const ConstInt = c.LLVMConstInt; |
| 33 | pub const ConstNull = c.LLVMConstNull; | ||
| 20 | pub const ConstStringInContext = c.LLVMConstStringInContext; | 34 | pub const ConstStringInContext = c.LLVMConstStringInContext; |
| 21 | pub const ConstStructInContext = c.LLVMConstStructInContext; | 35 | pub const ConstStructInContext = c.LLVMConstStructInContext; |
| 36 | pub const CopyStringRepOfTargetData = c.LLVMCopyStringRepOfTargetData; | ||
| 22 | pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext; | 37 | pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext; |
| 38 | pub const CreateCompileUnit = c.ZigLLVMCreateCompileUnit; | ||
| 39 | pub const CreateDIBuilder = c.ZigLLVMCreateDIBuilder; | ||
| 23 | pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute; | 40 | pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute; |
| 41 | pub const CreateFile = c.ZigLLVMCreateFile; | ||
| 24 | pub const CreateStringAttribute = c.LLVMCreateStringAttribute; | 42 | pub const CreateStringAttribute = c.LLVMCreateStringAttribute; |
| 43 | pub const CreateTargetDataLayout = c.LLVMCreateTargetDataLayout; | ||
| 44 | pub const CreateTargetMachine = c.LLVMCreateTargetMachine; | ||
| 45 | pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize; | ||
| 25 | pub const DisposeBuilder = c.LLVMDisposeBuilder; | 46 | pub const DisposeBuilder = c.LLVMDisposeBuilder; |
| 47 | pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder; | ||
| 48 | pub const DisposeMessage = c.LLVMDisposeMessage; | ||
| 26 | pub const DisposeModule = c.LLVMDisposeModule; | 49 | pub const DisposeModule = c.LLVMDisposeModule; |
| 50 | pub const DisposeTargetData = c.LLVMDisposeTargetData; | ||
| 51 | pub const DisposeTargetMachine = c.LLVMDisposeTargetMachine; | ||
| 27 | pub const DoubleTypeInContext = c.LLVMDoubleTypeInContext; | 52 | pub const DoubleTypeInContext = c.LLVMDoubleTypeInContext; |
| 28 | pub const DumpModule = c.LLVMDumpModule; | 53 | pub const DumpModule = c.LLVMDumpModule; |
| 29 | pub const FP128TypeInContext = c.LLVMFP128TypeInContext; | 54 | pub const FP128TypeInContext = c.LLVMFP128TypeInContext; |
| 30 | pub const FloatTypeInContext = c.LLVMFloatTypeInContext; | 55 | pub const FloatTypeInContext = c.LLVMFloatTypeInContext; |
| 31 | pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName; | 56 | pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName; |
| 57 | pub const GetHostCPUName = c.ZigLLVMGetHostCPUName; | ||
| 32 | pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext; | 58 | pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext; |
| 59 | pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures; | ||
| 33 | pub const HalfTypeInContext = c.LLVMHalfTypeInContext; | 60 | pub const HalfTypeInContext = c.LLVMHalfTypeInContext; |
| 61 | pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers; | ||
| 62 | pub const InitializeAllAsmPrinters = c.LLVMInitializeAllAsmPrinters; | ||
| 63 | pub const InitializeAllTargetInfos = c.LLVMInitializeAllTargetInfos; | ||
| 64 | pub const InitializeAllTargetMCs = c.LLVMInitializeAllTargetMCs; | ||
| 65 | pub const InitializeAllTargets = c.LLVMInitializeAllTargets; | ||
| 34 | pub const InsertBasicBlockInContext = c.LLVMInsertBasicBlockInContext; | 66 | pub const InsertBasicBlockInContext = c.LLVMInsertBasicBlockInContext; |
| 35 | pub const Int128TypeInContext = c.LLVMInt128TypeInContext; | 67 | pub const Int128TypeInContext = c.LLVMInt128TypeInContext; |
| 36 | pub const Int16TypeInContext = c.LLVMInt16TypeInContext; | 68 | pub const Int16TypeInContext = c.LLVMInt16TypeInContext; |
| ... | @@ -47,13 +79,16 @@ pub const MDStringInContext = c.LLVMMDStringInContext; | ... | @@ -47,13 +79,16 @@ pub const MDStringInContext = c.LLVMMDStringInContext; |
| 47 | pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext; | 79 | pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext; |
| 48 | pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext; | 80 | pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext; |
| 49 | pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext; | 81 | pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext; |
| 82 | pub const SetDataLayout = c.LLVMSetDataLayout; | ||
| 83 | pub const SetTarget = c.LLVMSetTarget; | ||
| 50 | pub const StructTypeInContext = c.LLVMStructTypeInContext; | 84 | pub const StructTypeInContext = c.LLVMStructTypeInContext; |
| 51 | pub const TokenTypeInContext = c.LLVMTokenTypeInContext; | 85 | pub const TokenTypeInContext = c.LLVMTokenTypeInContext; |
| 52 | pub const VoidTypeInContext = c.LLVMVoidTypeInContext; | 86 | pub const VoidTypeInContext = c.LLVMVoidTypeInContext; |
| 53 | pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext; | 87 | pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext; |
| 54 | pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext; | 88 | pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext; |
| 55 | pub const ConstAllOnes = c.LLVMConstAllOnes; | 89 | |
| 56 | pub const ConstNull = c.LLVMConstNull; | 90 | pub const GetTargetFromTriple = LLVMGetTargetFromTriple; |
| 91 | extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool; | ||
| 57 | 92 | ||
| 58 | pub const VerifyModule = LLVMVerifyModule; | 93 | pub const VerifyModule = LLVMVerifyModule; |
| 59 | extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool; | 94 | extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool; |
| ... | @@ -83,6 +118,31 @@ pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction; | ... | @@ -83,6 +118,31 @@ pub const PrintMessageAction = VerifierFailureAction.LLVMPrintMessageAction; |
| 83 | pub const ReturnStatusAction = VerifierFailureAction.LLVMReturnStatusAction; | 118 | pub const ReturnStatusAction = VerifierFailureAction.LLVMReturnStatusAction; |
| 84 | pub const VerifierFailureAction = c.LLVMVerifierFailureAction; | 119 | pub const VerifierFailureAction = c.LLVMVerifierFailureAction; |
| 85 | 120 | ||
| 121 | pub const CodeGenLevelNone = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelNone; | ||
| 122 | pub const CodeGenLevelLess = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelLess; | ||
| 123 | pub const CodeGenLevelDefault = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelDefault; | ||
| 124 | pub const CodeGenLevelAggressive = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelAggressive; | ||
| 125 | pub const CodeGenOptLevel = c.LLVMCodeGenOptLevel; | ||
| 126 | |||
| 127 | pub const RelocDefault = c.LLVMRelocMode.LLVMRelocDefault; | ||
| 128 | pub const RelocStatic = c.LLVMRelocMode.LLVMRelocStatic; | ||
| 129 | pub const RelocPIC = c.LLVMRelocMode.LLVMRelocPIC; | ||
| 130 | pub const RelocDynamicNoPic = c.LLVMRelocMode.LLVMRelocDynamicNoPic; | ||
| 131 | pub const RelocMode = c.LLVMRelocMode; | ||
| 132 | |||
| 133 | pub const CodeModelDefault = c.LLVMCodeModel.LLVMCodeModelDefault; | ||
| 134 | pub const CodeModelJITDefault = c.LLVMCodeModel.LLVMCodeModelJITDefault; | ||
| 135 | pub const CodeModelSmall = c.LLVMCodeModel.LLVMCodeModelSmall; | ||
| 136 | pub const CodeModelKernel = c.LLVMCodeModel.LLVMCodeModelKernel; | ||
| 137 | pub const CodeModelMedium = c.LLVMCodeModel.LLVMCodeModelMedium; | ||
| 138 | pub const CodeModelLarge = c.LLVMCodeModel.LLVMCodeModelLarge; | ||
| 139 | pub const CodeModel = c.LLVMCodeModel; | ||
| 140 | |||
| 141 | pub const EmitAssembly = EmitOutputType.ZigLLVM_EmitAssembly; | ||
| 142 | pub const EmitBinary = EmitOutputType.ZigLLVM_EmitBinary; | ||
| 143 | pub const EmitLLVMIr = EmitOutputType.ZigLLVM_EmitLLVMIr; | ||
| 144 | pub const EmitOutputType = c.ZigLLVM_EmitOutputType; | ||
| 145 | |||
| 86 | fn removeNullability(comptime T: type) type { | 146 | fn removeNullability(comptime T: type) type { |
| 87 | comptime assert(@typeId(T) == builtin.TypeId.Optional); | 147 | comptime assert(@typeId(T) == builtin.TypeId.Optional); |
| 88 | return T.Child; | 148 | return T.Child; |
| ... | @@ -90,3 +150,14 @@ fn removeNullability(comptime T: type) type { | ... | @@ -90,3 +150,14 @@ fn removeNullability(comptime T: type) type { |
| 90 | 150 | ||
| 91 | pub const BuildRet = LLVMBuildRet; | 151 | pub const BuildRet = LLVMBuildRet; |
| 92 | extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ValueRef; | 152 | extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ValueRef; |
| 153 | |||
| 154 | pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile; | ||
| 155 | extern fn ZigLLVMTargetMachineEmitToFile( | ||
| 156 | targ_machine_ref: TargetMachineRef, | ||
| 157 | module_ref: ModuleRef, | ||
| 158 | filename: [*]const u8, | ||
| 159 | output_type: EmitOutputType, | ||
| 160 | error_message: *[*]u8, | ||
| 161 | is_debug: bool, | ||
| 162 | is_small: bool, | ||
| 163 | ) bool; |
src-self-hosted/main.zig+5-3| ... | @@ -363,6 +363,8 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -363,6 +363,8 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 363 | } | 363 | } |
| 364 | }; | 364 | }; |
| 365 | 365 | ||
| 366 | const is_static = flags.present("static"); | ||
| 367 | |||
| 366 | const assembly_files = flags.many("assembly"); | 368 | const assembly_files = flags.many("assembly"); |
| 367 | const link_objects = flags.many("object"); | 369 | const link_objects = flags.many("object"); |
| 368 | if (root_source_file == null and link_objects.len == 0 and assembly_files.len == 0) { | 370 | if (root_source_file == null and link_objects.len == 0 and assembly_files.len == 0) { |
| ... | @@ -389,7 +391,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -389,7 +391,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 389 | try loop.initMultiThreaded(allocator); | 391 | try loop.initMultiThreaded(allocator); |
| 390 | defer loop.deinit(); | 392 | defer loop.deinit(); |
| 391 | 393 | ||
| 392 | var event_loop_local = EventLoopLocal.init(&loop); | 394 | var event_loop_local = try EventLoopLocal.init(&loop); |
| 393 | defer event_loop_local.deinit(); | 395 | defer event_loop_local.deinit(); |
| 394 | 396 | ||
| 395 | var comp = try Compilation.create( | 397 | var comp = try Compilation.create( |
| ... | @@ -399,6 +401,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -399,6 +401,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 399 | Target.Native, | 401 | Target.Native, |
| 400 | out_type, | 402 | out_type, |
| 401 | build_mode, | 403 | build_mode, |
| 404 | is_static, | ||
| 402 | zig_lib_dir, | 405 | zig_lib_dir, |
| 403 | full_cache_dir, | 406 | full_cache_dir, |
| 404 | ); | 407 | ); |
| ... | @@ -426,7 +429,6 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -426,7 +429,6 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 426 | comp.clang_argv = clang_argv_buf.toSliceConst(); | 429 | comp.clang_argv = clang_argv_buf.toSliceConst(); |
| 427 | 430 | ||
| 428 | comp.strip = flags.present("strip"); | 431 | comp.strip = flags.present("strip"); |
| 429 | comp.is_static = flags.present("static"); | ||
| 430 | 432 | ||
| 431 | if (flags.single("libc-lib-dir")) |libc_lib_dir| { | 433 | if (flags.single("libc-lib-dir")) |libc_lib_dir| { |
| 432 | comp.libc_lib_dir = libc_lib_dir; | 434 | comp.libc_lib_dir = libc_lib_dir; |
| ... | @@ -481,9 +483,9 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co | ... | @@ -481,9 +483,9 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co |
| 481 | } | 483 | } |
| 482 | 484 | ||
| 483 | comp.emit_file_type = emit_type; | 485 | comp.emit_file_type = emit_type; |
| 484 | comp.link_objects = link_objects; | ||
| 485 | comp.assembly_files = assembly_files; | 486 | comp.assembly_files = assembly_files; |
| 486 | comp.link_out_file = flags.single("out-file"); | 487 | comp.link_out_file = flags.single("out-file"); |
| 488 | comp.link_objects = link_objects; | ||
| 487 | 489 | ||
| 488 | try comp.build(); | 490 | try comp.build(); |
| 489 | const process_build_events_handle = try async<loop.allocator> processBuildEvents(comp, color); | 491 | const process_build_events_handle = try async<loop.allocator> processBuildEvents(comp, color); |
src-self-hosted/package.zig created+29| ... | @@ -0,0 +1,29 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | const Buffer = std.Buffer; | ||
| 5 | |||
| 6 | pub const Package = struct { | ||
| 7 | root_src_dir: Buffer, | ||
| 8 | root_src_path: Buffer, | ||
| 9 | |||
| 10 | /// relative to root_src_dir | ||
| 11 | table: Table, | ||
| 12 | |||
| 13 | pub const Table = std.HashMap([]const u8, *Package, mem.hash_slice_u8, mem.eql_slice_u8); | ||
| 14 | |||
| 15 | /// makes internal copies of root_src_dir and root_src_path | ||
| 16 | /// allocator should be an arena allocator because Package never frees anything | ||
| 17 | pub fn create(allocator: *mem.Allocator, root_src_dir: []const u8, root_src_path: []const u8) !*Package { | ||
| 18 | return allocator.create(Package{ | ||
| 19 | .root_src_dir = try Buffer.init(allocator, root_src_dir), | ||
| 20 | .root_src_path = try Buffer.init(allocator, root_src_path), | ||
| 21 | .table = Table.init(allocator), | ||
| 22 | }); | ||
| 23 | } | ||
| 24 | |||
| 25 | pub fn add(self: *Package, name: []const u8, package: *Package) !void { | ||
| 26 | const entry = try self.table.put(try mem.dupe(self.table.allocator, u8, name), package); | ||
| 27 | assert(entry == null); | ||
| 28 | } | ||
| 29 | }; | ||
src-self-hosted/scope.zig+16-16| ... | @@ -64,7 +64,7 @@ pub const Scope = struct { | ... | @@ -64,7 +64,7 @@ pub const Scope = struct { |
| 64 | 64 | ||
| 65 | /// Creates a Decls scope with 1 reference | 65 | /// Creates a Decls scope with 1 reference |
| 66 | pub fn create(comp: *Compilation, parent: ?*Scope) !*Decls { | 66 | pub fn create(comp: *Compilation, parent: ?*Scope) !*Decls { |
| 67 | const self = try comp.a().create(Decls{ | 67 | const self = try comp.gpa().create(Decls{ |
| 68 | .base = Scope{ | 68 | .base = Scope{ |
| 69 | .id = Id.Decls, | 69 | .id = Id.Decls, |
| 70 | .parent = parent, | 70 | .parent = parent, |
| ... | @@ -72,9 +72,9 @@ pub const Scope = struct { | ... | @@ -72,9 +72,9 @@ pub const Scope = struct { |
| 72 | }, | 72 | }, |
| 73 | .table = undefined, | 73 | .table = undefined, |
| 74 | }); | 74 | }); |
| 75 | errdefer comp.a().destroy(self); | 75 | errdefer comp.gpa().destroy(self); |
| 76 | 76 | ||
| 77 | self.table = Decl.Table.init(comp.a()); | 77 | self.table = Decl.Table.init(comp.gpa()); |
| 78 | errdefer self.table.deinit(); | 78 | errdefer self.table.deinit(); |
| 79 | 79 | ||
| 80 | if (parent) |p| p.ref(); | 80 | if (parent) |p| p.ref(); |
| ... | @@ -126,7 +126,7 @@ pub const Scope = struct { | ... | @@ -126,7 +126,7 @@ pub const Scope = struct { |
| 126 | 126 | ||
| 127 | /// Creates a Block scope with 1 reference | 127 | /// Creates a Block scope with 1 reference |
| 128 | pub fn create(comp: *Compilation, parent: ?*Scope) !*Block { | 128 | pub fn create(comp: *Compilation, parent: ?*Scope) !*Block { |
| 129 | const self = try comp.a().create(Block{ | 129 | const self = try comp.gpa().create(Block{ |
| 130 | .base = Scope{ | 130 | .base = Scope{ |
| 131 | .id = Id.Block, | 131 | .id = Id.Block, |
| 132 | .parent = parent, | 132 | .parent = parent, |
| ... | @@ -138,14 +138,14 @@ pub const Scope = struct { | ... | @@ -138,14 +138,14 @@ pub const Scope = struct { |
| 138 | .is_comptime = undefined, | 138 | .is_comptime = undefined, |
| 139 | .safety = Safety.Auto, | 139 | .safety = Safety.Auto, |
| 140 | }); | 140 | }); |
| 141 | errdefer comp.a().destroy(self); | 141 | errdefer comp.gpa().destroy(self); |
| 142 | 142 | ||
| 143 | if (parent) |p| p.ref(); | 143 | if (parent) |p| p.ref(); |
| 144 | return self; | 144 | return self; |
| 145 | } | 145 | } |
| 146 | 146 | ||
| 147 | pub fn destroy(self: *Block, comp: *Compilation) void { | 147 | pub fn destroy(self: *Block, comp: *Compilation) void { |
| 148 | comp.a().destroy(self); | 148 | comp.gpa().destroy(self); |
| 149 | } | 149 | } |
| 150 | }; | 150 | }; |
| 151 | 151 | ||
| ... | @@ -158,7 +158,7 @@ pub const Scope = struct { | ... | @@ -158,7 +158,7 @@ pub const Scope = struct { |
| 158 | /// Creates a FnDef scope with 1 reference | 158 | /// Creates a FnDef scope with 1 reference |
| 159 | /// Must set the fn_val later | 159 | /// Must set the fn_val later |
| 160 | pub fn create(comp: *Compilation, parent: ?*Scope) !*FnDef { | 160 | pub fn create(comp: *Compilation, parent: ?*Scope) !*FnDef { |
| 161 | const self = try comp.a().create(FnDef{ | 161 | const self = try comp.gpa().create(FnDef{ |
| 162 | .base = Scope{ | 162 | .base = Scope{ |
| 163 | .id = Id.FnDef, | 163 | .id = Id.FnDef, |
| 164 | .parent = parent, | 164 | .parent = parent, |
| ... | @@ -173,7 +173,7 @@ pub const Scope = struct { | ... | @@ -173,7 +173,7 @@ pub const Scope = struct { |
| 173 | } | 173 | } |
| 174 | 174 | ||
| 175 | pub fn destroy(self: *FnDef, comp: *Compilation) void { | 175 | pub fn destroy(self: *FnDef, comp: *Compilation) void { |
| 176 | comp.a().destroy(self); | 176 | comp.gpa().destroy(self); |
| 177 | } | 177 | } |
| 178 | }; | 178 | }; |
| 179 | 179 | ||
| ... | @@ -182,7 +182,7 @@ pub const Scope = struct { | ... | @@ -182,7 +182,7 @@ pub const Scope = struct { |
| 182 | 182 | ||
| 183 | /// Creates a CompTime scope with 1 reference | 183 | /// Creates a CompTime scope with 1 reference |
| 184 | pub fn create(comp: *Compilation, parent: ?*Scope) !*CompTime { | 184 | pub fn create(comp: *Compilation, parent: ?*Scope) !*CompTime { |
| 185 | const self = try comp.a().create(CompTime{ | 185 | const self = try comp.gpa().create(CompTime{ |
| 186 | .base = Scope{ | 186 | .base = Scope{ |
| 187 | .id = Id.CompTime, | 187 | .id = Id.CompTime, |
| 188 | .parent = parent, | 188 | .parent = parent, |
| ... | @@ -195,7 +195,7 @@ pub const Scope = struct { | ... | @@ -195,7 +195,7 @@ pub const Scope = struct { |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | pub fn destroy(self: *CompTime, comp: *Compilation) void { | 197 | pub fn destroy(self: *CompTime, comp: *Compilation) void { |
| 198 | comp.a().destroy(self); | 198 | comp.gpa().destroy(self); |
| 199 | } | 199 | } |
| 200 | }; | 200 | }; |
| 201 | 201 | ||
| ... | @@ -216,7 +216,7 @@ pub const Scope = struct { | ... | @@ -216,7 +216,7 @@ pub const Scope = struct { |
| 216 | kind: Kind, | 216 | kind: Kind, |
| 217 | defer_expr_scope: *DeferExpr, | 217 | defer_expr_scope: *DeferExpr, |
| 218 | ) !*Defer { | 218 | ) !*Defer { |
| 219 | const self = try comp.a().create(Defer{ | 219 | const self = try comp.gpa().create(Defer{ |
| 220 | .base = Scope{ | 220 | .base = Scope{ |
| 221 | .id = Id.Defer, | 221 | .id = Id.Defer, |
| 222 | .parent = parent, | 222 | .parent = parent, |
| ... | @@ -225,7 +225,7 @@ pub const Scope = struct { | ... | @@ -225,7 +225,7 @@ pub const Scope = struct { |
| 225 | .defer_expr_scope = defer_expr_scope, | 225 | .defer_expr_scope = defer_expr_scope, |
| 226 | .kind = kind, | 226 | .kind = kind, |
| 227 | }); | 227 | }); |
| 228 | errdefer comp.a().destroy(self); | 228 | errdefer comp.gpa().destroy(self); |
| 229 | 229 | ||
| 230 | defer_expr_scope.base.ref(); | 230 | defer_expr_scope.base.ref(); |
| 231 | 231 | ||
| ... | @@ -235,7 +235,7 @@ pub const Scope = struct { | ... | @@ -235,7 +235,7 @@ pub const Scope = struct { |
| 235 | 235 | ||
| 236 | pub fn destroy(self: *Defer, comp: *Compilation) void { | 236 | pub fn destroy(self: *Defer, comp: *Compilation) void { |
| 237 | self.defer_expr_scope.base.deref(comp); | 237 | self.defer_expr_scope.base.deref(comp); |
| 238 | comp.a().destroy(self); | 238 | comp.gpa().destroy(self); |
| 239 | } | 239 | } |
| 240 | }; | 240 | }; |
| 241 | 241 | ||
| ... | @@ -245,7 +245,7 @@ pub const Scope = struct { | ... | @@ -245,7 +245,7 @@ pub const Scope = struct { |
| 245 | 245 | ||
| 246 | /// Creates a DeferExpr scope with 1 reference | 246 | /// Creates a DeferExpr scope with 1 reference |
| 247 | pub fn create(comp: *Compilation, parent: ?*Scope, expr_node: *ast.Node) !*DeferExpr { | 247 | pub fn create(comp: *Compilation, parent: ?*Scope, expr_node: *ast.Node) !*DeferExpr { |
| 248 | const self = try comp.a().create(DeferExpr{ | 248 | const self = try comp.gpa().create(DeferExpr{ |
| 249 | .base = Scope{ | 249 | .base = Scope{ |
| 250 | .id = Id.DeferExpr, | 250 | .id = Id.DeferExpr, |
| 251 | .parent = parent, | 251 | .parent = parent, |
| ... | @@ -253,14 +253,14 @@ pub const Scope = struct { | ... | @@ -253,14 +253,14 @@ pub const Scope = struct { |
| 253 | }, | 253 | }, |
| 254 | .expr_node = expr_node, | 254 | .expr_node = expr_node, |
| 255 | }); | 255 | }); |
| 256 | errdefer comp.a().destroy(self); | 256 | errdefer comp.gpa().destroy(self); |
| 257 | 257 | ||
| 258 | if (parent) |p| p.ref(); | 258 | if (parent) |p| p.ref(); |
| 259 | return self; | 259 | return self; |
| 260 | } | 260 | } |
| 261 | 261 | ||
| 262 | pub fn destroy(self: *DeferExpr, comp: *Compilation) void { | 262 | pub fn destroy(self: *DeferExpr, comp: *Compilation) void { |
| 263 | comp.a().destroy(self); | 263 | comp.gpa().destroy(self); |
| 264 | } | 264 | } |
| 265 | }; | 265 | }; |
| 266 | }; | 266 | }; |
src-self-hosted/target.zig+87-29| ... | @@ -1,60 +1,118 @@ | ... | @@ -1,60 +1,118 @@ |
| 1 | const std = @import("std"); | ||
| 1 | const builtin = @import("builtin"); | 2 | const builtin = @import("builtin"); |
| 2 | const c = @import("c.zig"); | 3 | const llvm = @import("llvm.zig"); |
| 3 | |||
| 4 | pub const CrossTarget = struct { | ||
| 5 | arch: builtin.Arch, | ||
| 6 | os: builtin.Os, | ||
| 7 | environ: builtin.Environ, | ||
| 8 | }; | ||
| 9 | 4 | ||
| 10 | pub const Target = union(enum) { | 5 | pub const Target = union(enum) { |
| 11 | Native, | 6 | Native, |
| 12 | Cross: CrossTarget, | 7 | Cross: Cross, |
| 13 | 8 | ||
| 14 | pub fn oFileExt(self: *const Target) []const u8 { | 9 | pub const Cross = struct { |
| 15 | const environ = switch (self.*) { | 10 | arch: builtin.Arch, |
| 16 | Target.Native => builtin.environ, | 11 | os: builtin.Os, |
| 17 | Target.Cross => |t| t.environ, | 12 | environ: builtin.Environ, |
| 18 | }; | 13 | object_format: builtin.ObjectFormat, |
| 19 | return switch (environ) { | 14 | }; |
| 20 | builtin.Environ.msvc => ".obj", | 15 | |
| 16 | pub fn oFileExt(self: Target) []const u8 { | ||
| 17 | return switch (self.getObjectFormat()) { | ||
| 18 | builtin.ObjectFormat.coff => ".obj", | ||
| 21 | else => ".o", | 19 | else => ".o", |
| 22 | }; | 20 | }; |
| 23 | } | 21 | } |
| 24 | 22 | ||
| 25 | pub fn exeFileExt(self: *const Target) []const u8 { | 23 | pub fn exeFileExt(self: Target) []const u8 { |
| 26 | return switch (self.getOs()) { | 24 | return switch (self.getOs()) { |
| 27 | builtin.Os.windows => ".exe", | 25 | builtin.Os.windows => ".exe", |
| 28 | else => "", | 26 | else => "", |
| 29 | }; | 27 | }; |
| 30 | } | 28 | } |
| 31 | 29 | ||
| 32 | pub fn getOs(self: *const Target) builtin.Os { | 30 | pub fn getOs(self: Target) builtin.Os { |
| 33 | return switch (self.*) { | 31 | return switch (self) { |
| 34 | Target.Native => builtin.os, | 32 | Target.Native => builtin.os, |
| 35 | Target.Cross => |t| t.os, | 33 | @TagType(Target).Cross => |t| t.os, |
| 34 | }; | ||
| 35 | } | ||
| 36 | |||
| 37 | pub fn getArch(self: Target) builtin.Arch { | ||
| 38 | return switch (self) { | ||
| 39 | Target.Native => builtin.arch, | ||
| 40 | @TagType(Target).Cross => |t| t.arch, | ||
| 41 | }; | ||
| 42 | } | ||
| 43 | |||
| 44 | pub fn getEnviron(self: Target) builtin.Environ { | ||
| 45 | return switch (self) { | ||
| 46 | Target.Native => builtin.environ, | ||
| 47 | @TagType(Target).Cross => |t| t.environ, | ||
| 48 | }; | ||
| 49 | } | ||
| 50 | |||
| 51 | pub fn getObjectFormat(self: Target) builtin.ObjectFormat { | ||
| 52 | return switch (self) { | ||
| 53 | Target.Native => builtin.object_format, | ||
| 54 | @TagType(Target).Cross => |t| t.object_format, | ||
| 36 | }; | 55 | }; |
| 37 | } | 56 | } |
| 38 | 57 | ||
| 39 | pub fn isDarwin(self: *const Target) bool { | 58 | pub fn isWasm(self: Target) bool { |
| 59 | return switch (self.getArch()) { | ||
| 60 | builtin.Arch.wasm32, builtin.Arch.wasm64 => true, | ||
| 61 | else => false, | ||
| 62 | }; | ||
| 63 | } | ||
| 64 | |||
| 65 | pub fn isDarwin(self: Target) bool { | ||
| 40 | return switch (self.getOs()) { | 66 | return switch (self.getOs()) { |
| 41 | builtin.Os.ios, builtin.Os.macosx => true, | 67 | builtin.Os.ios, builtin.Os.macosx => true, |
| 42 | else => false, | 68 | else => false, |
| 43 | }; | 69 | }; |
| 44 | } | 70 | } |
| 45 | 71 | ||
| 46 | pub fn isWindows(self: *const Target) bool { | 72 | pub fn isWindows(self: Target) bool { |
| 47 | return switch (self.getOs()) { | 73 | return switch (self.getOs()) { |
| 48 | builtin.Os.windows => true, | 74 | builtin.Os.windows => true, |
| 49 | else => false, | 75 | else => false, |
| 50 | }; | 76 | }; |
| 51 | } | 77 | } |
| 52 | }; | ||
| 53 | 78 | ||
| 54 | pub fn initializeAll() void { | 79 | pub fn initializeAll() void { |
| 55 | c.LLVMInitializeAllTargets(); | 80 | llvm.InitializeAllTargets(); |
| 56 | c.LLVMInitializeAllTargetInfos(); | 81 | llvm.InitializeAllTargetInfos(); |
| 57 | c.LLVMInitializeAllTargetMCs(); | 82 | llvm.InitializeAllTargetMCs(); |
| 58 | c.LLVMInitializeAllAsmPrinters(); | 83 | llvm.InitializeAllAsmPrinters(); |
| 59 | c.LLVMInitializeAllAsmParsers(); | 84 | llvm.InitializeAllAsmParsers(); |
| 60 | } | 85 | } |
| 86 | |||
| 87 | pub fn getTriple(self: Target, allocator: *std.mem.Allocator) !std.Buffer { | ||
| 88 | var result = try std.Buffer.initSize(allocator, 0); | ||
| 89 | errdefer result.deinit(); | ||
| 90 | |||
| 91 | // LLVM WebAssembly output support requires the target to be activated at | ||
| 92 | // build type with -DCMAKE_LLVM_EXPIERMENTAL_TARGETS_TO_BUILD=WebAssembly. | ||
| 93 | // | ||
| 94 | // LLVM determines the output format based on the environment suffix, | ||
| 95 | // defaulting to an object based on the architecture. The default format in | ||
| 96 | // LLVM 6 sets the wasm arch output incorrectly to ELF. We need to | ||
| 97 | // explicitly set this ourself in order for it to work. | ||
| 98 | // | ||
| 99 | // This is fixed in LLVM 7 and you will be able to get wasm output by | ||
| 100 | // using the target triple `wasm32-unknown-unknown-unknown`. | ||
| 101 | const env_name = if (self.isWasm()) "wasm" else @tagName(self.getEnviron()); | ||
| 102 | |||
| 103 | var out = &std.io.BufferOutStream.init(&result).stream; | ||
| 104 | try out.print("{}-unknown-{}-{}", @tagName(self.getArch()), @tagName(self.getOs()), env_name); | ||
| 105 | |||
| 106 | return result; | ||
| 107 | } | ||
| 108 | |||
| 109 | pub fn llvmTargetFromTriple(triple: std.Buffer) !llvm.TargetRef { | ||
| 110 | var result: llvm.TargetRef = undefined; | ||
| 111 | var err_msg: [*]u8 = undefined; | ||
| 112 | if (llvm.GetTargetFromTriple(triple.ptr(), &result, &err_msg) != 0) { | ||
| 113 | std.debug.warn("triple: {s} error: {s}\n", triple.ptr(), err_msg); | ||
| 114 | return error.UnsupportedTarget; | ||
| 115 | } | ||
| 116 | return result; | ||
| 117 | } | ||
| 118 | }; |
src-self-hosted/test.zig+2-1| ... | @@ -46,7 +46,7 @@ pub const TestContext = struct { | ... | @@ -46,7 +46,7 @@ pub const TestContext = struct { |
| 46 | try self.loop.initMultiThreaded(allocator); | 46 | try self.loop.initMultiThreaded(allocator); |
| 47 | errdefer self.loop.deinit(); | 47 | errdefer self.loop.deinit(); |
| 48 | 48 | ||
| 49 | self.event_loop_local = EventLoopLocal.init(&self.loop); | 49 | self.event_loop_local = try EventLoopLocal.init(&self.loop); |
| 50 | errdefer self.event_loop_local.deinit(); | 50 | errdefer self.event_loop_local.deinit(); |
| 51 | 51 | ||
| 52 | self.group = std.event.Group(error!void).init(&self.loop); | 52 | self.group = std.event.Group(error!void).init(&self.loop); |
| ... | @@ -107,6 +107,7 @@ pub const TestContext = struct { | ... | @@ -107,6 +107,7 @@ pub const TestContext = struct { |
| 107 | Target.Native, | 107 | Target.Native, |
| 108 | Compilation.Kind.Obj, | 108 | Compilation.Kind.Obj, |
| 109 | builtin.Mode.Debug, | 109 | builtin.Mode.Debug, |
| 110 | true, // is_static | ||
| 110 | self.zig_lib_dir, | 111 | self.zig_lib_dir, |
| 111 | self.zig_cache_dir, | 112 | self.zig_cache_dir, |
| 112 | ); | 113 | ); |
src-self-hosted/type.zig+29-29| ... | @@ -160,7 +160,7 @@ pub const Type = struct { | ... | @@ -160,7 +160,7 @@ pub const Type = struct { |
| 160 | decls: *Scope.Decls, | 160 | decls: *Scope.Decls, |
| 161 | 161 | ||
| 162 | pub fn destroy(self: *Struct, comp: *Compilation) void { | 162 | pub fn destroy(self: *Struct, comp: *Compilation) void { |
| 163 | comp.a().destroy(self); | 163 | comp.gpa().destroy(self); |
| 164 | } | 164 | } |
| 165 | 165 | ||
| 166 | pub fn getLlvmType(self: *Struct, ofile: *ObjectFile) llvm.TypeRef { | 166 | pub fn getLlvmType(self: *Struct, ofile: *ObjectFile) llvm.TypeRef { |
| ... | @@ -180,7 +180,7 @@ pub const Type = struct { | ... | @@ -180,7 +180,7 @@ pub const Type = struct { |
| 180 | }; | 180 | }; |
| 181 | 181 | ||
| 182 | pub fn create(comp: *Compilation, return_type: *Type, params: []Param, is_var_args: bool) !*Fn { | 182 | pub fn create(comp: *Compilation, return_type: *Type, params: []Param, is_var_args: bool) !*Fn { |
| 183 | const result = try comp.a().create(Fn{ | 183 | const result = try comp.gpa().create(Fn{ |
| 184 | .base = Type{ | 184 | .base = Type{ |
| 185 | .base = Value{ | 185 | .base = Value{ |
| 186 | .id = Value.Id.Type, | 186 | .id = Value.Id.Type, |
| ... | @@ -193,7 +193,7 @@ pub const Type = struct { | ... | @@ -193,7 +193,7 @@ pub const Type = struct { |
| 193 | .params = params, | 193 | .params = params, |
| 194 | .is_var_args = is_var_args, | 194 | .is_var_args = is_var_args, |
| 195 | }); | 195 | }); |
| 196 | errdefer comp.a().destroy(result); | 196 | errdefer comp.gpa().destroy(result); |
| 197 | 197 | ||
| 198 | result.return_type.base.ref(); | 198 | result.return_type.base.ref(); |
| 199 | for (result.params) |param| { | 199 | for (result.params) |param| { |
| ... | @@ -207,7 +207,7 @@ pub const Type = struct { | ... | @@ -207,7 +207,7 @@ pub const Type = struct { |
| 207 | for (self.params) |param| { | 207 | for (self.params) |param| { |
| 208 | param.typeof.base.deref(comp); | 208 | param.typeof.base.deref(comp); |
| 209 | } | 209 | } |
| 210 | comp.a().destroy(self); | 210 | comp.gpa().destroy(self); |
| 211 | } | 211 | } |
| 212 | 212 | ||
| 213 | pub fn getLlvmType(self: *Fn, ofile: *ObjectFile) !llvm.TypeRef { | 213 | pub fn getLlvmType(self: *Fn, ofile: *ObjectFile) !llvm.TypeRef { |
| ... | @@ -215,8 +215,8 @@ pub const Type = struct { | ... | @@ -215,8 +215,8 @@ pub const Type = struct { |
| 215 | Type.Id.Void => llvm.VoidTypeInContext(ofile.context) orelse return error.OutOfMemory, | 215 | Type.Id.Void => llvm.VoidTypeInContext(ofile.context) orelse return error.OutOfMemory, |
| 216 | else => try self.return_type.getLlvmType(ofile), | 216 | else => try self.return_type.getLlvmType(ofile), |
| 217 | }; | 217 | }; |
| 218 | const llvm_param_types = try ofile.a().alloc(llvm.TypeRef, self.params.len); | 218 | const llvm_param_types = try ofile.gpa().alloc(llvm.TypeRef, self.params.len); |
| 219 | defer ofile.a().free(llvm_param_types); | 219 | defer ofile.gpa().free(llvm_param_types); |
| 220 | for (llvm_param_types) |*llvm_param_type, i| { | 220 | for (llvm_param_types) |*llvm_param_type, i| { |
| 221 | llvm_param_type.* = try self.params[i].typeof.getLlvmType(ofile); | 221 | llvm_param_type.* = try self.params[i].typeof.getLlvmType(ofile); |
| 222 | } | 222 | } |
| ... | @@ -241,7 +241,7 @@ pub const Type = struct { | ... | @@ -241,7 +241,7 @@ pub const Type = struct { |
| 241 | } | 241 | } |
| 242 | 242 | ||
| 243 | pub fn destroy(self: *MetaType, comp: *Compilation) void { | 243 | pub fn destroy(self: *MetaType, comp: *Compilation) void { |
| 244 | comp.a().destroy(self); | 244 | comp.gpa().destroy(self); |
| 245 | } | 245 | } |
| 246 | }; | 246 | }; |
| 247 | 247 | ||
| ... | @@ -255,7 +255,7 @@ pub const Type = struct { | ... | @@ -255,7 +255,7 @@ pub const Type = struct { |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | pub fn destroy(self: *Void, comp: *Compilation) void { | 257 | pub fn destroy(self: *Void, comp: *Compilation) void { |
| 258 | comp.a().destroy(self); | 258 | comp.gpa().destroy(self); |
| 259 | } | 259 | } |
| 260 | }; | 260 | }; |
| 261 | 261 | ||
| ... | @@ -269,7 +269,7 @@ pub const Type = struct { | ... | @@ -269,7 +269,7 @@ pub const Type = struct { |
| 269 | } | 269 | } |
| 270 | 270 | ||
| 271 | pub fn destroy(self: *Bool, comp: *Compilation) void { | 271 | pub fn destroy(self: *Bool, comp: *Compilation) void { |
| 272 | comp.a().destroy(self); | 272 | comp.gpa().destroy(self); |
| 273 | } | 273 | } |
| 274 | 274 | ||
| 275 | pub fn getLlvmType(self: *Bool, ofile: *ObjectFile) llvm.TypeRef { | 275 | pub fn getLlvmType(self: *Bool, ofile: *ObjectFile) llvm.TypeRef { |
| ... | @@ -287,7 +287,7 @@ pub const Type = struct { | ... | @@ -287,7 +287,7 @@ pub const Type = struct { |
| 287 | } | 287 | } |
| 288 | 288 | ||
| 289 | pub fn destroy(self: *NoReturn, comp: *Compilation) void { | 289 | pub fn destroy(self: *NoReturn, comp: *Compilation) void { |
| 290 | comp.a().destroy(self); | 290 | comp.gpa().destroy(self); |
| 291 | } | 291 | } |
| 292 | }; | 292 | }; |
| 293 | 293 | ||
| ... | @@ -295,7 +295,7 @@ pub const Type = struct { | ... | @@ -295,7 +295,7 @@ pub const Type = struct { |
| 295 | base: Type, | 295 | base: Type, |
| 296 | 296 | ||
| 297 | pub fn destroy(self: *Int, comp: *Compilation) void { | 297 | pub fn destroy(self: *Int, comp: *Compilation) void { |
| 298 | comp.a().destroy(self); | 298 | comp.gpa().destroy(self); |
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | pub fn getLlvmType(self: *Int, ofile: *ObjectFile) llvm.TypeRef { | 301 | pub fn getLlvmType(self: *Int, ofile: *ObjectFile) llvm.TypeRef { |
| ... | @@ -307,7 +307,7 @@ pub const Type = struct { | ... | @@ -307,7 +307,7 @@ pub const Type = struct { |
| 307 | base: Type, | 307 | base: Type, |
| 308 | 308 | ||
| 309 | pub fn destroy(self: *Float, comp: *Compilation) void { | 309 | pub fn destroy(self: *Float, comp: *Compilation) void { |
| 310 | comp.a().destroy(self); | 310 | comp.gpa().destroy(self); |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | pub fn getLlvmType(self: *Float, ofile: *ObjectFile) llvm.TypeRef { | 313 | pub fn getLlvmType(self: *Float, ofile: *ObjectFile) llvm.TypeRef { |
| ... | @@ -332,7 +332,7 @@ pub const Type = struct { | ... | @@ -332,7 +332,7 @@ pub const Type = struct { |
| 332 | pub const Size = builtin.TypeInfo.Pointer.Size; | 332 | pub const Size = builtin.TypeInfo.Pointer.Size; |
| 333 | 333 | ||
| 334 | pub fn destroy(self: *Pointer, comp: *Compilation) void { | 334 | pub fn destroy(self: *Pointer, comp: *Compilation) void { |
| 335 | comp.a().destroy(self); | 335 | comp.gpa().destroy(self); |
| 336 | } | 336 | } |
| 337 | 337 | ||
| 338 | pub fn get( | 338 | pub fn get( |
| ... | @@ -355,7 +355,7 @@ pub const Type = struct { | ... | @@ -355,7 +355,7 @@ pub const Type = struct { |
| 355 | base: Type, | 355 | base: Type, |
| 356 | 356 | ||
| 357 | pub fn destroy(self: *Array, comp: *Compilation) void { | 357 | pub fn destroy(self: *Array, comp: *Compilation) void { |
| 358 | comp.a().destroy(self); | 358 | comp.gpa().destroy(self); |
| 359 | } | 359 | } |
| 360 | 360 | ||
| 361 | pub fn getLlvmType(self: *Array, ofile: *ObjectFile) llvm.TypeRef { | 361 | pub fn getLlvmType(self: *Array, ofile: *ObjectFile) llvm.TypeRef { |
| ... | @@ -367,7 +367,7 @@ pub const Type = struct { | ... | @@ -367,7 +367,7 @@ pub const Type = struct { |
| 367 | base: Type, | 367 | base: Type, |
| 368 | 368 | ||
| 369 | pub fn destroy(self: *ComptimeFloat, comp: *Compilation) void { | 369 | pub fn destroy(self: *ComptimeFloat, comp: *Compilation) void { |
| 370 | comp.a().destroy(self); | 370 | comp.gpa().destroy(self); |
| 371 | } | 371 | } |
| 372 | }; | 372 | }; |
| 373 | 373 | ||
| ... | @@ -375,7 +375,7 @@ pub const Type = struct { | ... | @@ -375,7 +375,7 @@ pub const Type = struct { |
| 375 | base: Type, | 375 | base: Type, |
| 376 | 376 | ||
| 377 | pub fn destroy(self: *ComptimeInt, comp: *Compilation) void { | 377 | pub fn destroy(self: *ComptimeInt, comp: *Compilation) void { |
| 378 | comp.a().destroy(self); | 378 | comp.gpa().destroy(self); |
| 379 | } | 379 | } |
| 380 | }; | 380 | }; |
| 381 | 381 | ||
| ... | @@ -383,7 +383,7 @@ pub const Type = struct { | ... | @@ -383,7 +383,7 @@ pub const Type = struct { |
| 383 | base: Type, | 383 | base: Type, |
| 384 | 384 | ||
| 385 | pub fn destroy(self: *Undefined, comp: *Compilation) void { | 385 | pub fn destroy(self: *Undefined, comp: *Compilation) void { |
| 386 | comp.a().destroy(self); | 386 | comp.gpa().destroy(self); |
| 387 | } | 387 | } |
| 388 | }; | 388 | }; |
| 389 | 389 | ||
| ... | @@ -391,7 +391,7 @@ pub const Type = struct { | ... | @@ -391,7 +391,7 @@ pub const Type = struct { |
| 391 | base: Type, | 391 | base: Type, |
| 392 | 392 | ||
| 393 | pub fn destroy(self: *Null, comp: *Compilation) void { | 393 | pub fn destroy(self: *Null, comp: *Compilation) void { |
| 394 | comp.a().destroy(self); | 394 | comp.gpa().destroy(self); |
| 395 | } | 395 | } |
| 396 | }; | 396 | }; |
| 397 | 397 | ||
| ... | @@ -399,7 +399,7 @@ pub const Type = struct { | ... | @@ -399,7 +399,7 @@ pub const Type = struct { |
| 399 | base: Type, | 399 | base: Type, |
| 400 | 400 | ||
| 401 | pub fn destroy(self: *Optional, comp: *Compilation) void { | 401 | pub fn destroy(self: *Optional, comp: *Compilation) void { |
| 402 | comp.a().destroy(self); | 402 | comp.gpa().destroy(self); |
| 403 | } | 403 | } |
| 404 | 404 | ||
| 405 | pub fn getLlvmType(self: *Optional, ofile: *ObjectFile) llvm.TypeRef { | 405 | pub fn getLlvmType(self: *Optional, ofile: *ObjectFile) llvm.TypeRef { |
| ... | @@ -411,7 +411,7 @@ pub const Type = struct { | ... | @@ -411,7 +411,7 @@ pub const Type = struct { |
| 411 | base: Type, | 411 | base: Type, |
| 412 | 412 | ||
| 413 | pub fn destroy(self: *ErrorUnion, comp: *Compilation) void { | 413 | pub fn destroy(self: *ErrorUnion, comp: *Compilation) void { |
| 414 | comp.a().destroy(self); | 414 | comp.gpa().destroy(self); |
| 415 | } | 415 | } |
| 416 | 416 | ||
| 417 | pub fn getLlvmType(self: *ErrorUnion, ofile: *ObjectFile) llvm.TypeRef { | 417 | pub fn getLlvmType(self: *ErrorUnion, ofile: *ObjectFile) llvm.TypeRef { |
| ... | @@ -423,7 +423,7 @@ pub const Type = struct { | ... | @@ -423,7 +423,7 @@ pub const Type = struct { |
| 423 | base: Type, | 423 | base: Type, |
| 424 | 424 | ||
| 425 | pub fn destroy(self: *ErrorSet, comp: *Compilation) void { | 425 | pub fn destroy(self: *ErrorSet, comp: *Compilation) void { |
| 426 | comp.a().destroy(self); | 426 | comp.gpa().destroy(self); |
| 427 | } | 427 | } |
| 428 | 428 | ||
| 429 | pub fn getLlvmType(self: *ErrorSet, ofile: *ObjectFile) llvm.TypeRef { | 429 | pub fn getLlvmType(self: *ErrorSet, ofile: *ObjectFile) llvm.TypeRef { |
| ... | @@ -435,7 +435,7 @@ pub const Type = struct { | ... | @@ -435,7 +435,7 @@ pub const Type = struct { |
| 435 | base: Type, | 435 | base: Type, |
| 436 | 436 | ||
| 437 | pub fn destroy(self: *Enum, comp: *Compilation) void { | 437 | pub fn destroy(self: *Enum, comp: *Compilation) void { |
| 438 | comp.a().destroy(self); | 438 | comp.gpa().destroy(self); |
| 439 | } | 439 | } |
| 440 | 440 | ||
| 441 | pub fn getLlvmType(self: *Enum, ofile: *ObjectFile) llvm.TypeRef { | 441 | pub fn getLlvmType(self: *Enum, ofile: *ObjectFile) llvm.TypeRef { |
| ... | @@ -447,7 +447,7 @@ pub const Type = struct { | ... | @@ -447,7 +447,7 @@ pub const Type = struct { |
| 447 | base: Type, | 447 | base: Type, |
| 448 | 448 | ||
| 449 | pub fn destroy(self: *Union, comp: *Compilation) void { | 449 | pub fn destroy(self: *Union, comp: *Compilation) void { |
| 450 | comp.a().destroy(self); | 450 | comp.gpa().destroy(self); |
| 451 | } | 451 | } |
| 452 | 452 | ||
| 453 | pub fn getLlvmType(self: *Union, ofile: *ObjectFile) llvm.TypeRef { | 453 | pub fn getLlvmType(self: *Union, ofile: *ObjectFile) llvm.TypeRef { |
| ... | @@ -459,7 +459,7 @@ pub const Type = struct { | ... | @@ -459,7 +459,7 @@ pub const Type = struct { |
| 459 | base: Type, | 459 | base: Type, |
| 460 | 460 | ||
| 461 | pub fn destroy(self: *Namespace, comp: *Compilation) void { | 461 | pub fn destroy(self: *Namespace, comp: *Compilation) void { |
| 462 | comp.a().destroy(self); | 462 | comp.gpa().destroy(self); |
| 463 | } | 463 | } |
| 464 | }; | 464 | }; |
| 465 | 465 | ||
| ... | @@ -467,7 +467,7 @@ pub const Type = struct { | ... | @@ -467,7 +467,7 @@ pub const Type = struct { |
| 467 | base: Type, | 467 | base: Type, |
| 468 | 468 | ||
| 469 | pub fn destroy(self: *Block, comp: *Compilation) void { | 469 | pub fn destroy(self: *Block, comp: *Compilation) void { |
| 470 | comp.a().destroy(self); | 470 | comp.gpa().destroy(self); |
| 471 | } | 471 | } |
| 472 | }; | 472 | }; |
| 473 | 473 | ||
| ... | @@ -475,7 +475,7 @@ pub const Type = struct { | ... | @@ -475,7 +475,7 @@ pub const Type = struct { |
| 475 | base: Type, | 475 | base: Type, |
| 476 | 476 | ||
| 477 | pub fn destroy(self: *BoundFn, comp: *Compilation) void { | 477 | pub fn destroy(self: *BoundFn, comp: *Compilation) void { |
| 478 | comp.a().destroy(self); | 478 | comp.gpa().destroy(self); |
| 479 | } | 479 | } |
| 480 | 480 | ||
| 481 | pub fn getLlvmType(self: *BoundFn, ofile: *ObjectFile) llvm.TypeRef { | 481 | pub fn getLlvmType(self: *BoundFn, ofile: *ObjectFile) llvm.TypeRef { |
| ... | @@ -487,7 +487,7 @@ pub const Type = struct { | ... | @@ -487,7 +487,7 @@ pub const Type = struct { |
| 487 | base: Type, | 487 | base: Type, |
| 488 | 488 | ||
| 489 | pub fn destroy(self: *ArgTuple, comp: *Compilation) void { | 489 | pub fn destroy(self: *ArgTuple, comp: *Compilation) void { |
| 490 | comp.a().destroy(self); | 490 | comp.gpa().destroy(self); |
| 491 | } | 491 | } |
| 492 | }; | 492 | }; |
| 493 | 493 | ||
| ... | @@ -495,7 +495,7 @@ pub const Type = struct { | ... | @@ -495,7 +495,7 @@ pub const Type = struct { |
| 495 | base: Type, | 495 | base: Type, |
| 496 | 496 | ||
| 497 | pub fn destroy(self: *Opaque, comp: *Compilation) void { | 497 | pub fn destroy(self: *Opaque, comp: *Compilation) void { |
| 498 | comp.a().destroy(self); | 498 | comp.gpa().destroy(self); |
| 499 | } | 499 | } |
| 500 | 500 | ||
| 501 | pub fn getLlvmType(self: *Opaque, ofile: *ObjectFile) llvm.TypeRef { | 501 | pub fn getLlvmType(self: *Opaque, ofile: *ObjectFile) llvm.TypeRef { |
| ... | @@ -507,7 +507,7 @@ pub const Type = struct { | ... | @@ -507,7 +507,7 @@ pub const Type = struct { |
| 507 | base: Type, | 507 | base: Type, |
| 508 | 508 | ||
| 509 | pub fn destroy(self: *Promise, comp: *Compilation) void { | 509 | pub fn destroy(self: *Promise, comp: *Compilation) void { |
| 510 | comp.a().destroy(self); | 510 | comp.gpa().destroy(self); |
| 511 | } | 511 | } |
| 512 | 512 | ||
| 513 | pub fn getLlvmType(self: *Promise, ofile: *ObjectFile) llvm.TypeRef { | 513 | pub fn getLlvmType(self: *Promise, ofile: *ObjectFile) llvm.TypeRef { |
src-self-hosted/value.zig+33-8| ... | @@ -4,6 +4,7 @@ const Scope = @import("scope.zig").Scope; | ... | @@ -4,6 +4,7 @@ const Scope = @import("scope.zig").Scope; |
| 4 | const Compilation = @import("compilation.zig").Compilation; | 4 | const Compilation = @import("compilation.zig").Compilation; |
| 5 | const ObjectFile = @import("codegen.zig").ObjectFile; | 5 | const ObjectFile = @import("codegen.zig").ObjectFile; |
| 6 | const llvm = @import("llvm.zig"); | 6 | const llvm = @import("llvm.zig"); |
| 7 | const Buffer = std.Buffer; | ||
| 7 | 8 | ||
| 8 | /// Values are ref-counted, heap-allocated, and copy-on-write | 9 | /// Values are ref-counted, heap-allocated, and copy-on-write |
| 9 | /// If there is only 1 ref then write need not copy | 10 | /// If there is only 1 ref then write need not copy |
| ... | @@ -68,7 +69,7 @@ pub const Value = struct { | ... | @@ -68,7 +69,7 @@ pub const Value = struct { |
| 68 | 69 | ||
| 69 | /// The main external name that is used in the .o file. | 70 | /// The main external name that is used in the .o file. |
| 70 | /// TODO https://github.com/ziglang/zig/issues/265 | 71 | /// TODO https://github.com/ziglang/zig/issues/265 |
| 71 | symbol_name: std.Buffer, | 72 | symbol_name: Buffer, |
| 72 | 73 | ||
| 73 | /// parent should be the top level decls or container decls | 74 | /// parent should be the top level decls or container decls |
| 74 | fndef_scope: *Scope.FnDef, | 75 | fndef_scope: *Scope.FnDef, |
| ... | @@ -79,10 +80,22 @@ pub const Value = struct { | ... | @@ -79,10 +80,22 @@ pub const Value = struct { |
| 79 | /// parent is child_scope | 80 | /// parent is child_scope |
| 80 | block_scope: *Scope.Block, | 81 | block_scope: *Scope.Block, |
| 81 | 82 | ||
| 83 | /// Path to the object file that contains this function | ||
| 84 | containing_object: Buffer, | ||
| 85 | |||
| 86 | link_set_node: *std.LinkedList(?*Value.Fn).Node, | ||
| 87 | |||
| 82 | /// Creates a Fn value with 1 ref | 88 | /// Creates a Fn value with 1 ref |
| 83 | /// Takes ownership of symbol_name | 89 | /// Takes ownership of symbol_name |
| 84 | pub fn create(comp: *Compilation, fn_type: *Type.Fn, fndef_scope: *Scope.FnDef, symbol_name: std.Buffer) !*Fn { | 90 | pub fn create(comp: *Compilation, fn_type: *Type.Fn, fndef_scope: *Scope.FnDef, symbol_name: Buffer) !*Fn { |
| 85 | const self = try comp.a().create(Fn{ | 91 | const link_set_node = try comp.gpa().create(Compilation.FnLinkSet.Node{ |
| 92 | .data = null, | ||
| 93 | .next = undefined, | ||
| 94 | .prev = undefined, | ||
| 95 | }); | ||
| 96 | errdefer comp.gpa().destroy(link_set_node); | ||
| 97 | |||
| 98 | const self = try comp.gpa().create(Fn{ | ||
| 86 | .base = Value{ | 99 | .base = Value{ |
| 87 | .id = Value.Id.Fn, | 100 | .id = Value.Id.Fn, |
| 88 | .typeof = &fn_type.base, | 101 | .typeof = &fn_type.base, |
| ... | @@ -92,6 +105,8 @@ pub const Value = struct { | ... | @@ -92,6 +105,8 @@ pub const Value = struct { |
| 92 | .child_scope = &fndef_scope.base, | 105 | .child_scope = &fndef_scope.base, |
| 93 | .block_scope = undefined, | 106 | .block_scope = undefined, |
| 94 | .symbol_name = symbol_name, | 107 | .symbol_name = symbol_name, |
| 108 | .containing_object = Buffer.initNull(comp.gpa()), | ||
| 109 | .link_set_node = link_set_node, | ||
| 95 | }); | 110 | }); |
| 96 | fn_type.base.base.ref(); | 111 | fn_type.base.base.ref(); |
| 97 | fndef_scope.fn_val = self; | 112 | fndef_scope.fn_val = self; |
| ... | @@ -100,9 +115,19 @@ pub const Value = struct { | ... | @@ -100,9 +115,19 @@ pub const Value = struct { |
| 100 | } | 115 | } |
| 101 | 116 | ||
| 102 | pub fn destroy(self: *Fn, comp: *Compilation) void { | 117 | pub fn destroy(self: *Fn, comp: *Compilation) void { |
| 118 | // remove with a tombstone so that we do not have to grab a lock | ||
| 119 | if (self.link_set_node.data != null) { | ||
| 120 | // it's now the job of the link step to find this tombstone and | ||
| 121 | // deallocate it. | ||
| 122 | self.link_set_node.data = null; | ||
| 123 | } else { | ||
| 124 | comp.gpa().destroy(self.link_set_node); | ||
| 125 | } | ||
| 126 | |||
| 127 | self.containing_object.deinit(); | ||
| 103 | self.fndef_scope.base.deref(comp); | 128 | self.fndef_scope.base.deref(comp); |
| 104 | self.symbol_name.deinit(); | 129 | self.symbol_name.deinit(); |
| 105 | comp.a().destroy(self); | 130 | comp.gpa().destroy(self); |
| 106 | } | 131 | } |
| 107 | }; | 132 | }; |
| 108 | 133 | ||
| ... | @@ -115,7 +140,7 @@ pub const Value = struct { | ... | @@ -115,7 +140,7 @@ pub const Value = struct { |
| 115 | } | 140 | } |
| 116 | 141 | ||
| 117 | pub fn destroy(self: *Void, comp: *Compilation) void { | 142 | pub fn destroy(self: *Void, comp: *Compilation) void { |
| 118 | comp.a().destroy(self); | 143 | comp.gpa().destroy(self); |
| 119 | } | 144 | } |
| 120 | }; | 145 | }; |
| 121 | 146 | ||
| ... | @@ -134,7 +159,7 @@ pub const Value = struct { | ... | @@ -134,7 +159,7 @@ pub const Value = struct { |
| 134 | } | 159 | } |
| 135 | 160 | ||
| 136 | pub fn destroy(self: *Bool, comp: *Compilation) void { | 161 | pub fn destroy(self: *Bool, comp: *Compilation) void { |
| 137 | comp.a().destroy(self); | 162 | comp.gpa().destroy(self); |
| 138 | } | 163 | } |
| 139 | 164 | ||
| 140 | pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?llvm.ValueRef { | 165 | pub fn getLlvmConst(self: *Bool, ofile: *ObjectFile) ?llvm.ValueRef { |
| ... | @@ -156,7 +181,7 @@ pub const Value = struct { | ... | @@ -156,7 +181,7 @@ pub const Value = struct { |
| 156 | } | 181 | } |
| 157 | 182 | ||
| 158 | pub fn destroy(self: *NoReturn, comp: *Compilation) void { | 183 | pub fn destroy(self: *NoReturn, comp: *Compilation) void { |
| 159 | comp.a().destroy(self); | 184 | comp.gpa().destroy(self); |
| 160 | } | 185 | } |
| 161 | }; | 186 | }; |
| 162 | 187 | ||
| ... | @@ -170,7 +195,7 @@ pub const Value = struct { | ... | @@ -170,7 +195,7 @@ pub const Value = struct { |
| 170 | }; | 195 | }; |
| 171 | 196 | ||
| 172 | pub fn destroy(self: *Ptr, comp: *Compilation) void { | 197 | pub fn destroy(self: *Ptr, comp: *Compilation) void { |
| 173 | comp.a().destroy(self); | 198 | comp.gpa().destroy(self); |
| 174 | } | 199 | } |
| 175 | }; | 200 | }; |
| 176 | }; | 201 | }; |
src/zig_llvm.cpp+5| ... | @@ -440,6 +440,11 @@ ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unreso | ... | @@ -440,6 +440,11 @@ ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unreso |
| 440 | return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder); | 440 | return reinterpret_cast<ZigLLVMDIBuilder *>(di_builder); |
| 441 | } | 441 | } |
| 442 | 442 | ||
| 443 | void ZigLLVMDisposeDIBuilder(ZigLLVMDIBuilder *dbuilder) { | ||
| 444 | DIBuilder *di_builder = reinterpret_cast<DIBuilder *>(dbuilder); | ||
| 445 | delete di_builder; | ||
| 446 | } | ||
| 447 | |||
| 443 | void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column, ZigLLVMDIScope *scope) { | 448 | void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column, ZigLLVMDIScope *scope) { |
| 444 | unwrap(builder)->SetCurrentDebugLocation(DebugLoc::get( | 449 | unwrap(builder)->SetCurrentDebugLocation(DebugLoc::get( |
| 445 | line, column, reinterpret_cast<DIScope*>(scope))); | 450 | line, column, reinterpret_cast<DIScope*>(scope))); |
src/zig_llvm.h+2-1| ... | @@ -39,7 +39,7 @@ struct ZigLLVMInsertionPoint; | ... | @@ -39,7 +39,7 @@ struct ZigLLVMInsertionPoint; |
| 39 | ZIG_EXTERN_C void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R); | 39 | ZIG_EXTERN_C void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R); |
| 40 | ZIG_EXTERN_C void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R); | 40 | ZIG_EXTERN_C void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R); |
| 41 | 41 | ||
| 42 | /// Caller must free memory. | 42 | /// Caller must free memory with LLVMDisposeMessage |
| 43 | ZIG_EXTERN_C char *ZigLLVMGetHostCPUName(void); | 43 | ZIG_EXTERN_C char *ZigLLVMGetHostCPUName(void); |
| 44 | ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void); | 44 | ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void); |
| 45 | 45 | ||
| ... | @@ -139,6 +139,7 @@ ZIG_EXTERN_C unsigned ZigLLVMTag_DW_enumeration_type(void); | ... | @@ -139,6 +139,7 @@ ZIG_EXTERN_C unsigned ZigLLVMTag_DW_enumeration_type(void); |
| 139 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void); | 139 | ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void); |
| 140 | 140 | ||
| 141 | ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); | 141 | ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved); |
| 142 | ZIG_EXTERN_C void ZigLLVMDisposeDIBuilder(struct ZigLLVMDIBuilder *dbuilder); | ||
| 142 | ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); | 143 | ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module); |
| 143 | ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module); | 144 | ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module); |
| 144 | 145 |
std/atomic/int.zig+4| ... | @@ -25,5 +25,9 @@ pub fn Int(comptime T: type) type { | ... | @@ -25,5 +25,9 @@ pub fn Int(comptime T: type) type { |
| 25 | pub fn get(self: *Self) T { | 25 | pub fn get(self: *Self) T { |
| 26 | return @atomicLoad(T, &self.unprotected_value, AtomicOrder.SeqCst); | 26 | return @atomicLoad(T, &self.unprotected_value, AtomicOrder.SeqCst); |
| 27 | } | 27 | } |
| 28 | |||
| 29 | pub fn xchg(self: *Self, new_value: T) T { | ||
| 30 | return @atomicRmw(T, &self.unprotected_value, builtin.AtomicRmwOp.Xchg, new_value, AtomicOrder.SeqCst); | ||
| 31 | } | ||
| 28 | }; | 32 | }; |
| 29 | } | 33 | } |
std/buffer.zig+13| ... | @@ -54,6 +54,19 @@ pub const Buffer = struct { | ... | @@ -54,6 +54,19 @@ pub const Buffer = struct { |
| 54 | return result; | 54 | return result; |
| 55 | } | 55 | } |
| 56 | 56 | ||
| 57 | pub fn allocPrint(allocator: *Allocator, comptime format: []const u8, args: ...) !Buffer { | ||
| 58 | const countSize = struct { | ||
| 59 | fn countSize(size: *usize, bytes: []const u8) (error{}!void) { | ||
| 60 | size.* += bytes.len; | ||
| 61 | } | ||
| 62 | }.countSize; | ||
| 63 | var size: usize = 0; | ||
| 64 | std.fmt.format(&size, error{}, countSize, format, args) catch |err| switch (err) {}; | ||
| 65 | var self = try Buffer.initSize(allocator, size); | ||
| 66 | assert((std.fmt.bufPrint(self.list.items, format, args) catch unreachable).len == size); | ||
| 67 | return self; | ||
| 68 | } | ||
| 69 | |||
| 57 | pub fn deinit(self: *Buffer) void { | 70 | pub fn deinit(self: *Buffer) void { |
| 58 | self.list.deinit(); | 71 | self.list.deinit(); |
| 59 | } | 72 | } |
std/dwarf.zig+37| ... | @@ -639,3 +639,40 @@ pub const LNE_define_file = 0x03; | ... | @@ -639,3 +639,40 @@ pub const LNE_define_file = 0x03; |
| 639 | pub const LNE_set_discriminator = 0x04; | 639 | pub const LNE_set_discriminator = 0x04; |
| 640 | pub const LNE_lo_user = 0x80; | 640 | pub const LNE_lo_user = 0x80; |
| 641 | pub const LNE_hi_user = 0xff; | 641 | pub const LNE_hi_user = 0xff; |
| 642 | |||
| 643 | pub const LANG_C89 = 0x0001; | ||
| 644 | pub const LANG_C = 0x0002; | ||
| 645 | pub const LANG_Ada83 = 0x0003; | ||
| 646 | pub const LANG_C_plus_plus = 0x0004; | ||
| 647 | pub const LANG_Cobol74 = 0x0005; | ||
| 648 | pub const LANG_Cobol85 = 0x0006; | ||
| 649 | pub const LANG_Fortran77 = 0x0007; | ||
| 650 | pub const LANG_Fortran90 = 0x0008; | ||
| 651 | pub const LANG_Pascal83 = 0x0009; | ||
| 652 | pub const LANG_Modula2 = 0x000a; | ||
| 653 | pub const LANG_Java = 0x000b; | ||
| 654 | pub const LANG_C99 = 0x000c; | ||
| 655 | pub const LANG_Ada95 = 0x000d; | ||
| 656 | pub const LANG_Fortran95 = 0x000e; | ||
| 657 | pub const LANG_PLI = 0x000f; | ||
| 658 | pub const LANG_ObjC = 0x0010; | ||
| 659 | pub const LANG_ObjC_plus_plus = 0x0011; | ||
| 660 | pub const LANG_UPC = 0x0012; | ||
| 661 | pub const LANG_D = 0x0013; | ||
| 662 | pub const LANG_Python = 0x0014; | ||
| 663 | pub const LANG_Go = 0x0016; | ||
| 664 | pub const LANG_C_plus_plus_11 = 0x001a; | ||
| 665 | pub const LANG_Rust = 0x001c; | ||
| 666 | pub const LANG_C11 = 0x001d; | ||
| 667 | pub const LANG_C_plus_plus_14 = 0x0021; | ||
| 668 | pub const LANG_Fortran03 = 0x0022; | ||
| 669 | pub const LANG_Fortran08 = 0x0023; | ||
| 670 | pub const LANG_lo_user = 0x8000; | ||
| 671 | pub const LANG_hi_user = 0xffff; | ||
| 672 | pub const LANG_Mips_Assembler = 0x8001; | ||
| 673 | pub const LANG_Upc = 0x8765; | ||
| 674 | pub const LANG_HP_Bliss = 0x8003; | ||
| 675 | pub const LANG_HP_Basic91 = 0x8004; | ||
| 676 | pub const LANG_HP_Pascal91 = 0x8005; | ||
| 677 | pub const LANG_HP_IMacro = 0x8006; | ||
| 678 | pub const LANG_HP_Assembler = 0x8007; |
std/event/future.zig+31-8| ... | @@ -6,15 +6,20 @@ const AtomicOrder = builtin.AtomicOrder; | ... | @@ -6,15 +6,20 @@ const AtomicOrder = builtin.AtomicOrder; |
| 6 | const Lock = std.event.Lock; | 6 | const Lock = std.event.Lock; |
| 7 | const Loop = std.event.Loop; | 7 | const Loop = std.event.Loop; |
| 8 | 8 | ||
| 9 | /// This is a value that starts out unavailable, until a value is put(). | 9 | /// This is a value that starts out unavailable, until resolve() is called |
| 10 | /// While it is unavailable, coroutines suspend when they try to get() it, | 10 | /// While it is unavailable, coroutines suspend when they try to get() it, |
| 11 | /// and then are resumed when the value is put(). | 11 | /// and then are resumed when resolve() is called. |
| 12 | /// At this point the value remains forever available, and another put() is not allowed. | 12 | /// At this point the value remains forever available, and another resolve() is not allowed. |
| 13 | pub fn Future(comptime T: type) type { | 13 | pub fn Future(comptime T: type) type { |
| 14 | return struct { | 14 | return struct { |
| 15 | lock: Lock, | 15 | lock: Lock, |
| 16 | data: T, | 16 | data: T, |
| 17 | available: u8, // TODO make this a bool | 17 | |
| 18 | /// TODO make this an enum | ||
| 19 | /// 0 - not started | ||
| 20 | /// 1 - started | ||
| 21 | /// 2 - finished | ||
| 22 | available: u8, | ||
| 18 | 23 | ||
| 19 | const Self = this; | 24 | const Self = this; |
| 20 | const Queue = std.atomic.Queue(promise); | 25 | const Queue = std.atomic.Queue(promise); |
| ... | @@ -31,7 +36,7 @@ pub fn Future(comptime T: type) type { | ... | @@ -31,7 +36,7 @@ pub fn Future(comptime T: type) type { |
| 31 | /// available. | 36 | /// available. |
| 32 | /// Thread-safe. | 37 | /// Thread-safe. |
| 33 | pub async fn get(self: *Self) *T { | 38 | pub async fn get(self: *Self) *T { |
| 34 | if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 1) { | 39 | if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) { |
| 35 | return &self.data; | 40 | return &self.data; |
| 36 | } | 41 | } |
| 37 | const held = await (async self.lock.acquire() catch unreachable); | 42 | const held = await (async self.lock.acquire() catch unreachable); |
| ... | @@ -43,18 +48,36 @@ pub fn Future(comptime T: type) type { | ... | @@ -43,18 +48,36 @@ pub fn Future(comptime T: type) type { |
| 43 | /// Gets the data without waiting for it. If it's available, a pointer is | 48 | /// Gets the data without waiting for it. If it's available, a pointer is |
| 44 | /// returned. Otherwise, null is returned. | 49 | /// returned. Otherwise, null is returned. |
| 45 | pub fn getOrNull(self: *Self) ?*T { | 50 | pub fn getOrNull(self: *Self) ?*T { |
| 46 | if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 1) { | 51 | if (@atomicLoad(u8, &self.available, AtomicOrder.SeqCst) == 2) { |
| 47 | return &self.data; | 52 | return &self.data; |
| 48 | } else { | 53 | } else { |
| 49 | return null; | 54 | return null; |
| 50 | } | 55 | } |
| 51 | } | 56 | } |
| 52 | 57 | ||
| 58 | /// If someone else has started working on the data, wait for them to complete | ||
| 59 | /// and return a pointer to the data. Otherwise, return null, and the caller | ||
| 60 | /// should start working on the data. | ||
| 61 | /// It's not required to call start() before resolve() but it can be useful since | ||
| 62 | /// this method is thread-safe. | ||
| 63 | pub async fn start(self: *Self) ?*T { | ||
| 64 | const state = @cmpxchgStrong(u8, &self.available, 0, 1, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return null; | ||
| 65 | switch (state) { | ||
| 66 | 1 => { | ||
| 67 | const held = await (async self.lock.acquire() catch unreachable); | ||
| 68 | held.release(); | ||
| 69 | return &self.data; | ||
| 70 | }, | ||
| 71 | 2 => return &self.data, | ||
| 72 | else => unreachable, | ||
| 73 | } | ||
| 74 | } | ||
| 75 | |||
| 53 | /// Make the data become available. May be called only once. | 76 | /// Make the data become available. May be called only once. |
| 54 | /// Before calling this, modify the `data` property. | 77 | /// Before calling this, modify the `data` property. |
| 55 | pub fn resolve(self: *Self) void { | 78 | pub fn resolve(self: *Self) void { |
| 56 | const prev = @atomicRmw(u8, &self.available, AtomicRmwOp.Xchg, 1, AtomicOrder.SeqCst); | 79 | const prev = @atomicRmw(u8, &self.available, AtomicRmwOp.Xchg, 2, AtomicOrder.SeqCst); |
| 57 | assert(prev == 0); // put() called twice | 80 | assert(prev == 0 or prev == 1); // resolve() called twice |
| 58 | Lock.Held.release(Lock.Held{ .lock = &self.lock }); | 81 | Lock.Held.release(Lock.Held{ .lock = &self.lock }); |
| 59 | } | 82 | } |
| 60 | }; | 83 | }; |
std/index.zig+3| ... | @@ -36,6 +36,8 @@ pub const sort = @import("sort.zig"); | ... | @@ -36,6 +36,8 @@ pub const sort = @import("sort.zig"); |
| 36 | pub const unicode = @import("unicode.zig"); | 36 | pub const unicode = @import("unicode.zig"); |
| 37 | pub const zig = @import("zig/index.zig"); | 37 | pub const zig = @import("zig/index.zig"); |
| 38 | 38 | ||
| 39 | pub const lazyInit = @import("lazy_init.zig").lazyInit; | ||
| 40 | |||
| 39 | test "std" { | 41 | test "std" { |
| 40 | // run tests from these | 42 | // run tests from these |
| 41 | _ = @import("atomic/index.zig"); | 43 | _ = @import("atomic/index.zig"); |
| ... | @@ -71,4 +73,5 @@ test "std" { | ... | @@ -71,4 +73,5 @@ test "std" { |
| 71 | _ = @import("sort.zig"); | 73 | _ = @import("sort.zig"); |
| 72 | _ = @import("unicode.zig"); | 74 | _ = @import("unicode.zig"); |
| 73 | _ = @import("zig/index.zig"); | 75 | _ = @import("zig/index.zig"); |
| 76 | _ = @import("lazy_init.zig"); | ||
| 74 | } | 77 | } |
std/lazy_init.zig created+85| ... | @@ -0,0 +1,85 @@ | ||
| 1 | const std = @import("index.zig"); | ||
| 2 | const builtin = @import("builtin"); | ||
| 3 | const assert = std.debug.assert; | ||
| 4 | const AtomicRmwOp = builtin.AtomicRmwOp; | ||
| 5 | const AtomicOrder = builtin.AtomicOrder; | ||
| 6 | |||
| 7 | /// Thread-safe initialization of global data. | ||
| 8 | /// TODO use a mutex instead of a spinlock | ||
| 9 | pub fn lazyInit(comptime T: type) LazyInit(T) { | ||
| 10 | return LazyInit(T){ | ||
| 11 | .data = undefined, | ||
| 12 | .state = 0, | ||
| 13 | }; | ||
| 14 | } | ||
| 15 | |||
| 16 | fn LazyInit(comptime T: type) type { | ||
| 17 | return struct { | ||
| 18 | state: u8, // TODO make this an enum | ||
| 19 | data: Data, | ||
| 20 | |||
| 21 | const Self = this; | ||
| 22 | |||
| 23 | // TODO this isn't working for void, investigate and then remove this special case | ||
| 24 | const Data = if (@sizeOf(T) == 0) u8 else T; | ||
| 25 | const Ptr = if (T == void) void else *T; | ||
| 26 | |||
| 27 | /// Returns a usable pointer to the initialized data, | ||
| 28 | /// or returns null, indicating that the caller should | ||
| 29 | /// perform the initialization and then call resolve(). | ||
| 30 | pub fn get(self: *Self) ?Ptr { | ||
| 31 | while (true) { | ||
| 32 | var state = @cmpxchgWeak(u8, &self.state, 0, 1, AtomicOrder.SeqCst, AtomicOrder.SeqCst) orelse return null; | ||
| 33 | switch (state) { | ||
| 34 | 0 => continue, | ||
| 35 | 1 => { | ||
| 36 | // TODO mutex instead of a spinlock | ||
| 37 | continue; | ||
| 38 | }, | ||
| 39 | 2 => { | ||
| 40 | if (@sizeOf(T) == 0) { | ||
| 41 | return T(undefined); | ||
| 42 | } else { | ||
| 43 | return &self.data; | ||
| 44 | } | ||
| 45 | }, | ||
| 46 | else => unreachable, | ||
| 47 | } | ||
| 48 | } | ||
| 49 | } | ||
| 50 | |||
| 51 | pub fn resolve(self: *Self) void { | ||
| 52 | const prev = @atomicRmw(u8, &self.state, AtomicRmwOp.Xchg, 2, AtomicOrder.SeqCst); | ||
| 53 | assert(prev == 1); // resolve() called twice | ||
| 54 | } | ||
| 55 | }; | ||
| 56 | } | ||
| 57 | |||
| 58 | var global_number = lazyInit(i32); | ||
| 59 | |||
| 60 | test "std.lazyInit" { | ||
| 61 | if (global_number.get()) |_| @panic("bad") else { | ||
| 62 | global_number.data = 1234; | ||
| 63 | global_number.resolve(); | ||
| 64 | } | ||
| 65 | if (global_number.get()) |x| { | ||
| 66 | assert(x.* == 1234); | ||
| 67 | } else { | ||
| 68 | @panic("bad"); | ||
| 69 | } | ||
| 70 | if (global_number.get()) |x| { | ||
| 71 | assert(x.* == 1234); | ||
| 72 | } else { | ||
| 73 | @panic("bad"); | ||
| 74 | } | ||
| 75 | } | ||
| 76 | |||
| 77 | var global_void = lazyInit(void); | ||
| 78 | |||
| 79 | test "std.lazyInit(void)" { | ||
| 80 | if (global_void.get()) |_| @panic("bad") else { | ||
| 81 | global_void.resolve(); | ||
| 82 | } | ||
| 83 | assert(global_void.get() != null); | ||
| 84 | assert(global_void.get() != null); | ||
| 85 | } | ||