authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-16 20:52:50-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-16 20:52:50-04:00
log97bfeac13f89e1b5a22fcd7d4705341b4c3e1950
tree4a3e23a8b3908450b23f2dbba72e5f6c091d7114
parent0fa24b6b7568557c29c9b3ee213ce2b06fcd6367

self-hosted: create tmp dir for .o files and emit .o file for fn


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 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");
2const Compilation = @import("compilation.zig").Compilation;3const 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
6const llvm = @import("llvm.zig");4const llvm = @import("llvm.zig");
5const c = @import("c.zig");
7const ir = @import("ir.zig");6const ir = @import("ir.zig");
8const Value = @import("value.zig").Value;7const Value = @import("value.zig").Value;
9const Type = @import("type.zig").Type;8const Type = @import("type.zig").Type;
10const event = std.event;9const event = std.event;
11const assert = std.debug.assert;10const assert = std.debug.assert;
11const DW = std.dwarf;
1212
13pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code) !void {13pub 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();
1720
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);
2528
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);
2840
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 //}
4389
44 // TODO90 llvm.DIBuilderFinalize(dibuilder);
45 //ZigLLVMDIBuilderFinalize(g->dbuilder);
4691
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}
57126
58pub const ObjectFile = struct {127pub 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,
64134
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};
69139
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;
26const Type = Value.Type;26const Type = Value.Type;
27const Span = errmsg.Span;27const Span = errmsg.Span;
28const codegen = @import("codegen.zig");28const codegen = @import("codegen.zig");
29const Package = @import("package.zig").Package;
2930
30/// Data that is local to the event loop.31/// Data that is local to the event loop.
31pub const EventLoopLocal = struct {32pub 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),
3435
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 }
4156
...@@ -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),
83104
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,
110133
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,
113142
...@@ -141,7 +170,7 @@ pub const Compilation = struct {...@@ -141,7 +170,7 @@ pub const Compilation = struct {
141170
142 /// Before code generation starts, must wait on this group to make sure171 /// 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),
145174
146 compile_errors: event.Locked(CompileErrList),175 compile_errors: event.Locked(CompileErrList),
147176
...@@ -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,
157186
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);
159198
160 // TODO handle some of these earlier and report them in a way other than error codes199 // 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 one235 Unimplemented, // TODO remove this one
197 SemanticAnalysisFailed, // TODO remove this one236 SemanticAnalysisFailed, // TODO remove this one
237 ReadOnlyFileSystem,
238 LinkQuotaExceeded,
239 EnvironmentVariableNotFound,
198 };240 };
199241
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;
244287 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,
262304
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)),
308351
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 }
321433
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);
337449
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);
349461
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);
361473
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);
373485
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);
382494
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);
392504
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);
402514
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 }
412524
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);
421537
422 self.events.destroy();538 self.events.destroy();
423 self.name.deinit();
424539
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 }
427547
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 }
438558
439 _ = try async<self.a()> self.buildAsync();559 _ = try async<self.gpa()> self.buildAsync();
440 }560 }
441561
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 references586 // if there's an error then the compile errors have dangling references
467 self.a().free(compile_errors);587 self.gpa().free(compile_errors);
468588
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.real599 // 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);
485605
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);
492612
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);
498618
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();
501621
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 };
527647
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);
542662
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 }
552672
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);
555675
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 }
561681
...@@ -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);
565685
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 }
568688
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 }
627747
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 }
640760
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};
645827
646fn printError(comptime format: []const u8, args: ...) !void {828fn 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
662844
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.
664pub async fn resolveDecl(comp: *Compilation, decl: *Decl) !void {846pub 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}
673853
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);
700880
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();
703883
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());
723903
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());
742922
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 {
747927
748 // Kick off rendering to LLVM module, but it doesn't block the fn decl928 // 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
934async 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
946fn 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
954fn 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,
455455
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;
484484
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());
493493
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 }
503503
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 }
507507
508 /// Call code.destroy() when done508 /// 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");
2const c = @import("c.zig");2const c = @import("c.zig");
3const assert = @import("std").debug.assert;3const assert = @import("std").debug.assert;
44
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
5pub const AttributeIndex = c_uint;11pub const AttributeIndex = c_uint;
6pub const Bool = c_int;12pub const Bool = c_int;
713
...@@ -12,25 +18,51 @@ pub const ValueRef = removeNullability(c.LLVMValueRef);...@@ -12,25 +18,51 @@ pub const ValueRef = removeNullability(c.LLVMValueRef);
12pub const TypeRef = removeNullability(c.LLVMTypeRef);18pub const TypeRef = removeNullability(c.LLVMTypeRef);
13pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef);19pub const BasicBlockRef = removeNullability(c.LLVMBasicBlockRef);
14pub const AttributeRef = removeNullability(c.LLVMAttributeRef);20pub const AttributeRef = removeNullability(c.LLVMAttributeRef);
21pub const TargetRef = removeNullability(c.LLVMTargetRef);
22pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef);
23pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef);
24pub const DIBuilder = c.ZigLLVMDIBuilder;
1525
16pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;26pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;
17pub const AddFunction = c.LLVMAddFunction;27pub const AddFunction = c.LLVMAddFunction;
28pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
29pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
18pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;30pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
31pub const ConstAllOnes = c.LLVMConstAllOnes;
19pub const ConstInt = c.LLVMConstInt;32pub const ConstInt = c.LLVMConstInt;
33pub const ConstNull = c.LLVMConstNull;
20pub const ConstStringInContext = c.LLVMConstStringInContext;34pub const ConstStringInContext = c.LLVMConstStringInContext;
21pub const ConstStructInContext = c.LLVMConstStructInContext;35pub const ConstStructInContext = c.LLVMConstStructInContext;
36pub const CopyStringRepOfTargetData = c.LLVMCopyStringRepOfTargetData;
22pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext;37pub const CreateBuilderInContext = c.LLVMCreateBuilderInContext;
38pub const CreateCompileUnit = c.ZigLLVMCreateCompileUnit;
39pub const CreateDIBuilder = c.ZigLLVMCreateDIBuilder;
23pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute;40pub const CreateEnumAttribute = c.LLVMCreateEnumAttribute;
41pub const CreateFile = c.ZigLLVMCreateFile;
24pub const CreateStringAttribute = c.LLVMCreateStringAttribute;42pub const CreateStringAttribute = c.LLVMCreateStringAttribute;
43pub const CreateTargetDataLayout = c.LLVMCreateTargetDataLayout;
44pub const CreateTargetMachine = c.LLVMCreateTargetMachine;
45pub const DIBuilderFinalize = c.ZigLLVMDIBuilderFinalize;
25pub const DisposeBuilder = c.LLVMDisposeBuilder;46pub const DisposeBuilder = c.LLVMDisposeBuilder;
47pub const DisposeDIBuilder = c.ZigLLVMDisposeDIBuilder;
48pub const DisposeMessage = c.LLVMDisposeMessage;
26pub const DisposeModule = c.LLVMDisposeModule;49pub const DisposeModule = c.LLVMDisposeModule;
50pub const DisposeTargetData = c.LLVMDisposeTargetData;
51pub const DisposeTargetMachine = c.LLVMDisposeTargetMachine;
27pub const DoubleTypeInContext = c.LLVMDoubleTypeInContext;52pub const DoubleTypeInContext = c.LLVMDoubleTypeInContext;
28pub const DumpModule = c.LLVMDumpModule;53pub const DumpModule = c.LLVMDumpModule;
29pub const FP128TypeInContext = c.LLVMFP128TypeInContext;54pub const FP128TypeInContext = c.LLVMFP128TypeInContext;
30pub const FloatTypeInContext = c.LLVMFloatTypeInContext;55pub const FloatTypeInContext = c.LLVMFloatTypeInContext;
31pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;56pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
57pub const GetHostCPUName = c.ZigLLVMGetHostCPUName;
32pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;58pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
59pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures;
33pub const HalfTypeInContext = c.LLVMHalfTypeInContext;60pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
61pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;
62pub const InitializeAllAsmPrinters = c.LLVMInitializeAllAsmPrinters;
63pub const InitializeAllTargetInfos = c.LLVMInitializeAllTargetInfos;
64pub const InitializeAllTargetMCs = c.LLVMInitializeAllTargetMCs;
65pub const InitializeAllTargets = c.LLVMInitializeAllTargets;
34pub const InsertBasicBlockInContext = c.LLVMInsertBasicBlockInContext;66pub const InsertBasicBlockInContext = c.LLVMInsertBasicBlockInContext;
35pub const Int128TypeInContext = c.LLVMInt128TypeInContext;67pub const Int128TypeInContext = c.LLVMInt128TypeInContext;
36pub const Int16TypeInContext = c.LLVMInt16TypeInContext;68pub const Int16TypeInContext = c.LLVMInt16TypeInContext;
...@@ -47,13 +79,16 @@ pub const MDStringInContext = c.LLVMMDStringInContext;...@@ -47,13 +79,16 @@ pub const MDStringInContext = c.LLVMMDStringInContext;
47pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;79pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
48pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;80pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
49pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;81pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
82pub const SetDataLayout = c.LLVMSetDataLayout;
83pub const SetTarget = c.LLVMSetTarget;
50pub const StructTypeInContext = c.LLVMStructTypeInContext;84pub const StructTypeInContext = c.LLVMStructTypeInContext;
51pub const TokenTypeInContext = c.LLVMTokenTypeInContext;85pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
52pub const VoidTypeInContext = c.LLVMVoidTypeInContext;86pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
53pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;87pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
54pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;88pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
55pub const ConstAllOnes = c.LLVMConstAllOnes;89
56pub const ConstNull = c.LLVMConstNull;90pub const GetTargetFromTriple = LLVMGetTargetFromTriple;
91extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool;
5792
58pub const VerifyModule = LLVMVerifyModule;93pub const VerifyModule = LLVMVerifyModule;
59extern fn LLVMVerifyModule(M: ModuleRef, Action: VerifierFailureAction, OutMessage: *?[*]u8) Bool;94extern 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;
83pub const ReturnStatusAction = VerifierFailureAction.LLVMReturnStatusAction;118pub const ReturnStatusAction = VerifierFailureAction.LLVMReturnStatusAction;
84pub const VerifierFailureAction = c.LLVMVerifierFailureAction;119pub const VerifierFailureAction = c.LLVMVerifierFailureAction;
85120
121pub const CodeGenLevelNone = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelNone;
122pub const CodeGenLevelLess = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelLess;
123pub const CodeGenLevelDefault = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelDefault;
124pub const CodeGenLevelAggressive = c.LLVMCodeGenOptLevel.LLVMCodeGenLevelAggressive;
125pub const CodeGenOptLevel = c.LLVMCodeGenOptLevel;
126
127pub const RelocDefault = c.LLVMRelocMode.LLVMRelocDefault;
128pub const RelocStatic = c.LLVMRelocMode.LLVMRelocStatic;
129pub const RelocPIC = c.LLVMRelocMode.LLVMRelocPIC;
130pub const RelocDynamicNoPic = c.LLVMRelocMode.LLVMRelocDynamicNoPic;
131pub const RelocMode = c.LLVMRelocMode;
132
133pub const CodeModelDefault = c.LLVMCodeModel.LLVMCodeModelDefault;
134pub const CodeModelJITDefault = c.LLVMCodeModel.LLVMCodeModelJITDefault;
135pub const CodeModelSmall = c.LLVMCodeModel.LLVMCodeModelSmall;
136pub const CodeModelKernel = c.LLVMCodeModel.LLVMCodeModelKernel;
137pub const CodeModelMedium = c.LLVMCodeModel.LLVMCodeModelMedium;
138pub const CodeModelLarge = c.LLVMCodeModel.LLVMCodeModelLarge;
139pub const CodeModel = c.LLVMCodeModel;
140
141pub const EmitAssembly = EmitOutputType.ZigLLVM_EmitAssembly;
142pub const EmitBinary = EmitOutputType.ZigLLVM_EmitBinary;
143pub const EmitLLVMIr = EmitOutputType.ZigLLVM_EmitLLVMIr;
144pub const EmitOutputType = c.ZigLLVM_EmitOutputType;
145
86fn removeNullability(comptime T: type) type {146fn 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 {
90150
91pub const BuildRet = LLVMBuildRet;151pub const BuildRet = LLVMBuildRet;
92extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ValueRef;152extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ValueRef;
153
154pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
155extern 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 };
365365
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();
391393
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();
394396
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();
427430
428 comp.strip = flags.present("strip");431 comp.strip = flags.present("strip");
429 comp.is_static = flags.present("static");
430432
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 }
482484
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;
487489
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 @@
1const std = @import("std");
2const mem = std.mem;
3const assert = std.debug.assert;
4const Buffer = std.Buffer;
5
6pub 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 {
6464
65 /// Creates a Decls scope with 1 reference65 /// 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);
7676
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();
7979
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 {
126126
127 /// Creates a Block scope with 1 reference127 /// 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);
142142
143 if (parent) |p| p.ref();143 if (parent) |p| p.ref();
144 return self;144 return self;
145 }145 }
146146
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 };
151151
...@@ -158,7 +158,7 @@ pub const Scope = struct {...@@ -158,7 +158,7 @@ pub const Scope = struct {
158 /// Creates a FnDef scope with 1 reference158 /// Creates a FnDef scope with 1 reference
159 /// Must set the fn_val later159 /// 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 }
174174
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 };
179179
...@@ -182,7 +182,7 @@ pub const Scope = struct {...@@ -182,7 +182,7 @@ pub const Scope = struct {
182182
183 /// Creates a CompTime scope with 1 reference183 /// 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 }
196196
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 };
201201
...@@ -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);
229229
230 defer_expr_scope.base.ref();230 defer_expr_scope.base.ref();
231231
...@@ -235,7 +235,7 @@ pub const Scope = struct {...@@ -235,7 +235,7 @@ pub const Scope = struct {
235235
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 };
241241
...@@ -245,7 +245,7 @@ pub const Scope = struct {...@@ -245,7 +245,7 @@ pub const Scope = struct {
245245
246 /// Creates a DeferExpr scope with 1 reference246 /// 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);
257257
258 if (parent) |p| p.ref();258 if (parent) |p| p.ref();
259 return self;259 return self;
260 }260 }
261261
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 @@
1const std = @import("std");
1const builtin = @import("builtin");2const builtin = @import("builtin");
2const c = @import("c.zig");3const llvm = @import("llvm.zig");
3
4pub const CrossTarget = struct {
5 arch: builtin.Arch,
6 os: builtin.Os,
7 environ: builtin.Environ,
8};
94
10pub const Target = union(enum) {5pub const Target = union(enum) {
11 Native,6 Native,
12 Cross: CrossTarget,7 Cross: Cross,
138
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 }
2422
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 }
3129
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 }
3857
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 }
4571
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};
5378
54pub 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();
4848
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();
5151
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,
161161
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 }
165165
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 };
181181
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);
197197
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 }
212212
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 }
242242
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 };
247247
...@@ -255,7 +255,7 @@ pub const Type = struct {...@@ -255,7 +255,7 @@ pub const Type = struct {
255 }255 }
256256
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 };
261261
...@@ -269,7 +269,7 @@ pub const Type = struct {...@@ -269,7 +269,7 @@ pub const Type = struct {
269 }269 }
270270
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 }
274274
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 }
288288
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 };
293293
...@@ -295,7 +295,7 @@ pub const Type = struct {...@@ -295,7 +295,7 @@ pub const Type = struct {
295 base: Type,295 base: Type,
296296
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 }
300300
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,
308308
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 }
312312
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;
333333
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 }
337337
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,
356356
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 }
360360
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,
368368
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 };
373373
...@@ -375,7 +375,7 @@ pub const Type = struct {...@@ -375,7 +375,7 @@ pub const Type = struct {
375 base: Type,375 base: Type,
376376
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 };
381381
...@@ -383,7 +383,7 @@ pub const Type = struct {...@@ -383,7 +383,7 @@ pub const Type = struct {
383 base: Type,383 base: Type,
384384
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 };
389389
...@@ -391,7 +391,7 @@ pub const Type = struct {...@@ -391,7 +391,7 @@ pub const Type = struct {
391 base: Type,391 base: Type,
392392
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 };
397397
...@@ -399,7 +399,7 @@ pub const Type = struct {...@@ -399,7 +399,7 @@ pub const Type = struct {
399 base: Type,399 base: Type,
400400
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 }
404404
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,
412412
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 }
416416
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,
424424
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 }
428428
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,
436436
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 }
440440
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,
448448
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 }
452452
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,
460460
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 };
465465
...@@ -467,7 +467,7 @@ pub const Type = struct {...@@ -467,7 +467,7 @@ pub const Type = struct {
467 base: Type,467 base: Type,
468468
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 };
473473
...@@ -475,7 +475,7 @@ pub const Type = struct {...@@ -475,7 +475,7 @@ pub const Type = struct {
475 base: Type,475 base: Type,
476476
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 }
480480
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,
488488
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 };
493493
...@@ -495,7 +495,7 @@ pub const Type = struct {...@@ -495,7 +495,7 @@ pub const Type = struct {
495 base: Type,495 base: Type,
496496
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 }
500500
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,
508508
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 }
512512
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;
4const Compilation = @import("compilation.zig").Compilation;4const Compilation = @import("compilation.zig").Compilation;
5const ObjectFile = @import("codegen.zig").ObjectFile;5const ObjectFile = @import("codegen.zig").ObjectFile;
6const llvm = @import("llvm.zig");6const llvm = @import("llvm.zig");
7const Buffer = std.Buffer;
78
8/// Values are ref-counted, heap-allocated, and copy-on-write9/// Values are ref-counted, heap-allocated, and copy-on-write
9/// If there is only 1 ref then write need not copy10/// 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 {
6869
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/26571 /// TODO https://github.com/ziglang/zig/issues/265
71 symbol_name: std.Buffer,72 symbol_name: Buffer,
7273
73 /// parent should be the top level decls or container decls74 /// 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_scope80 /// parent is child_scope
80 block_scope: *Scope.Block,81 block_scope: *Scope.Block,
8182
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 ref88 /// Creates a Fn value with 1 ref
83 /// Takes ownership of symbol_name89 /// 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 }
101116
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 };
108133
...@@ -115,7 +140,7 @@ pub const Value = struct {...@@ -115,7 +140,7 @@ pub const Value = struct {
115 }140 }
116141
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 };
121146
...@@ -134,7 +159,7 @@ pub const Value = struct {...@@ -134,7 +159,7 @@ pub const Value = struct {
134 }159 }
135160
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 }
139164
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 }
157182
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 };
162187
...@@ -170,7 +195,7 @@ pub const Value = struct {...@@ -170,7 +195,7 @@ pub const Value = struct {
170 };195 };
171196
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}
442442
443void ZigLLVMDisposeDIBuilder(ZigLLVMDIBuilder *dbuilder) {
444 DIBuilder *di_builder = reinterpret_cast<DIBuilder *>(dbuilder);
445 delete di_builder;
446}
447
443void ZigLLVMSetCurrentDebugLocation(LLVMBuilderRef builder, int line, int column, ZigLLVMDIScope *scope) {448void 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;
39ZIG_EXTERN_C void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R);39ZIG_EXTERN_C void ZigLLVMInitializeLoopStrengthReducePass(LLVMPassRegistryRef R);
40ZIG_EXTERN_C void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R);40ZIG_EXTERN_C void ZigLLVMInitializeLowerIntrinsicsPass(LLVMPassRegistryRef R);
4141
42/// Caller must free memory.42/// Caller must free memory with LLVMDisposeMessage
43ZIG_EXTERN_C char *ZigLLVMGetHostCPUName(void);43ZIG_EXTERN_C char *ZigLLVMGetHostCPUName(void);
44ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void);44ZIG_EXTERN_C char *ZigLLVMGetNativeFeatures(void);
4545
...@@ -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);
139ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void);139ZIG_EXTERN_C unsigned ZigLLVMTag_DW_union_type(void);
140140
141ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);141ZIG_EXTERN_C struct ZigLLVMDIBuilder *ZigLLVMCreateDIBuilder(LLVMModuleRef module, bool allow_unresolved);
142ZIG_EXTERN_C void ZigLLVMDisposeDIBuilder(struct ZigLLVMDIBuilder *dbuilder);
142ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);143ZIG_EXTERN_C void ZigLLVMAddModuleDebugInfoFlag(LLVMModuleRef module);
143ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module);144ZIG_EXTERN_C void ZigLLVMAddModuleCodeViewFlag(LLVMModuleRef module);
144145
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 }
5656
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;
639pub const LNE_set_discriminator = 0x04;639pub const LNE_set_discriminator = 0x04;
640pub const LNE_lo_user = 0x80;640pub const LNE_lo_user = 0x80;
641pub const LNE_hi_user = 0xff;641pub const LNE_hi_user = 0xff;
642
643pub const LANG_C89 = 0x0001;
644pub const LANG_C = 0x0002;
645pub const LANG_Ada83 = 0x0003;
646pub const LANG_C_plus_plus = 0x0004;
647pub const LANG_Cobol74 = 0x0005;
648pub const LANG_Cobol85 = 0x0006;
649pub const LANG_Fortran77 = 0x0007;
650pub const LANG_Fortran90 = 0x0008;
651pub const LANG_Pascal83 = 0x0009;
652pub const LANG_Modula2 = 0x000a;
653pub const LANG_Java = 0x000b;
654pub const LANG_C99 = 0x000c;
655pub const LANG_Ada95 = 0x000d;
656pub const LANG_Fortran95 = 0x000e;
657pub const LANG_PLI = 0x000f;
658pub const LANG_ObjC = 0x0010;
659pub const LANG_ObjC_plus_plus = 0x0011;
660pub const LANG_UPC = 0x0012;
661pub const LANG_D = 0x0013;
662pub const LANG_Python = 0x0014;
663pub const LANG_Go = 0x0016;
664pub const LANG_C_plus_plus_11 = 0x001a;
665pub const LANG_Rust = 0x001c;
666pub const LANG_C11 = 0x001d;
667pub const LANG_C_plus_plus_14 = 0x0021;
668pub const LANG_Fortran03 = 0x0022;
669pub const LANG_Fortran08 = 0x0023;
670pub const LANG_lo_user = 0x8000;
671pub const LANG_hi_user = 0xffff;
672pub const LANG_Mips_Assembler = 0x8001;
673pub const LANG_Upc = 0x8765;
674pub const LANG_HP_Bliss = 0x8003;
675pub const LANG_HP_Basic91 = 0x8004;
676pub const LANG_HP_Pascal91 = 0x8005;
677pub const LANG_HP_IMacro = 0x8006;
678pub 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;
6const Lock = std.event.Lock;6const Lock = std.event.Lock;
7const Loop = std.event.Loop;7const Loop = std.event.Loop;
88
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.
13pub fn Future(comptime T: type) type {13pub 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 bool17
18 /// TODO make this an enum
19 /// 0 - not started
20 /// 1 - started
21 /// 2 - finished
22 available: u8,
1823
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 is48 /// 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 }
5257
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 twice80 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");
36pub const unicode = @import("unicode.zig");36pub const unicode = @import("unicode.zig");
37pub const zig = @import("zig/index.zig");37pub const zig = @import("zig/index.zig");
3838
39pub const lazyInit = @import("lazy_init.zig").lazyInit;
40
39test "std" {41test "std" {
40 // run tests from these42 // 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 @@
1const std = @import("index.zig");
2const builtin = @import("builtin");
3const assert = std.debug.assert;
4const AtomicRmwOp = builtin.AtomicRmwOp;
5const AtomicOrder = builtin.AtomicOrder;
6
7/// Thread-safe initialization of global data.
8/// TODO use a mutex instead of a spinlock
9pub fn lazyInit(comptime T: type) LazyInit(T) {
10 return LazyInit(T){
11 .data = undefined,
12 .state = 0,
13 };
14}
15
16fn 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
58var global_number = lazyInit(i32);
59
60test "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
77var global_void = lazyInit(void);
78
79test "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}