authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2018-07-24 00:31:33-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2018-07-24 00:31:33-04:00
log10bdf73a02c90dc375985e49b08b5020cfc20b93
tree2485d62496dd7436bcbabe80e7b47ca369ccbd38
parent99153ac0aa390f01091308073b39947c45851ae6
parent72599d420b1bebb37efb2179a91d8256287f7c28
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #1266 from ziglang/self-hosted-libc-hello-world

Self hosted libc hello world

46 files changed, 5624 insertions(+), 1204 deletions(-)

CMakeLists.txt+9
...@@ -426,6 +426,7 @@ set(ZIG_SOURCES...@@ -426,6 +426,7 @@ set(ZIG_SOURCES
426)426)
427set(ZIG_CPP_SOURCES427set(ZIG_CPP_SOURCES
428 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"428 "${CMAKE_SOURCE_DIR}/src/zig_llvm.cpp"
429 "${CMAKE_SOURCE_DIR}/src/windows_sdk.cpp"
429)430)
430431
431set(ZIG_STD_FILES432set(ZIG_STD_FILES
...@@ -489,6 +490,7 @@ set(ZIG_STD_FILES...@@ -489,6 +490,7 @@ set(ZIG_STD_FILES
489 "math/atan.zig"490 "math/atan.zig"
490 "math/atan2.zig"491 "math/atan2.zig"
491 "math/atanh.zig"492 "math/atanh.zig"
493 "math/big/index.zig"
492 "math/big/int.zig"494 "math/big/int.zig"
493 "math/cbrt.zig"495 "math/cbrt.zig"
494 "math/ceil.zig"496 "math/ceil.zig"
...@@ -566,8 +568,14 @@ set(ZIG_STD_FILES...@@ -566,8 +568,14 @@ set(ZIG_STD_FILES
566 "os/linux/x86_64.zig"568 "os/linux/x86_64.zig"
567 "os/path.zig"569 "os/path.zig"
568 "os/time.zig"570 "os/time.zig"
571 "os/windows/advapi32.zig"
569 "os/windows/error.zig"572 "os/windows/error.zig"
570 "os/windows/index.zig"573 "os/windows/index.zig"
574 "os/windows/kernel32.zig"
575 "os/windows/ole32.zig"
576 "os/windows/shell32.zig"
577 "os/windows/shlwapi.zig"
578 "os/windows/user32.zig"
571 "os/windows/util.zig"579 "os/windows/util.zig"
572 "os/zen.zig"580 "os/zen.zig"
573 "rand/index.zig"581 "rand/index.zig"
...@@ -616,6 +624,7 @@ set(ZIG_STD_FILES...@@ -616,6 +624,7 @@ set(ZIG_STD_FILES
616 "zig/ast.zig"624 "zig/ast.zig"
617 "zig/index.zig"625 "zig/index.zig"
618 "zig/parse.zig"626 "zig/parse.zig"
627 "zig/parse_string_literal.zig"
619 "zig/render.zig"628 "zig/render.zig"
620 "zig/tokenizer.zig"629 "zig/tokenizer.zig"
621)630)
README.md+4-4
...@@ -21,19 +21,19 @@ clarity....@@ -21,19 +21,19 @@ clarity.
21 * Compatible with C libraries with no wrapper necessary. Directly include21 * Compatible with C libraries with no wrapper necessary. Directly include
22 C .h files and get access to the functions and symbols therein.22 C .h files and get access to the functions and symbols therein.
23 * Provides standard library which competes with the C standard library and is23 * Provides standard library which competes with the C standard library and is
24 always compiled against statically in source form. Compile units do not24 always compiled against statically in source form. Zig binaries do not
25 depend on libc unless explicitly linked.25 depend on libc unless explicitly linked.
26 * Nullable type instead of null pointers.26 * Optional type instead of null pointers.
27 * Safe unions, tagged unions, and C ABI compatible unions.27 * Safe unions, tagged unions, and C ABI compatible unions.
28 * Generics so that one can write efficient data structures that work for any28 * Generics so that one can write efficient data structures that work for any
29 data type.29 data type.
30 * No header files required. Top level declarations are entirely30 * No header files required. Top level declarations are entirely
31 order-independent.31 order-independent.
32 * Compile-time code execution. Compile-time reflection.32 * Compile-time code execution. Compile-time reflection.
33 * Partial compile-time function evaluation with eliminates the need for33 * Partial compile-time function evaluation which eliminates the need for
34 a preprocessor or macros.34 a preprocessor or macros.
35 * The binaries produced by Zig have complete debugging information so you can,35 * The binaries produced by Zig have complete debugging information so you can,
36 for example, use GDB or MSVC to debug your software.36 for example, use GDB, MSVC, or LLDB to debug your software.
37 * Built-in unit tests with `zig test`.37 * Built-in unit tests with `zig test`.
38 * Friendly toward package maintainers. Reproducible build, bootstrapping38 * Friendly toward package maintainers. Reproducible build, bootstrapping
39 process carefully documented. Issues filed by package maintainers are39 process carefully documented. Issues filed by package maintainers are
src-self-hosted/c.zig+1
...@@ -4,4 +4,5 @@ pub use @cImport({...@@ -4,4 +4,5 @@ pub use @cImport({
4 @cInclude("inttypes.h");4 @cInclude("inttypes.h");
5 @cInclude("config.h");5 @cInclude("config.h");
6 @cInclude("zig_llvm.h");6 @cInclude("zig_llvm.h");
7 @cInclude("windows_sdk.h");
7});8});
src-self-hosted/c_int.zig created+68
...@@ -0,0 +1,68 @@
1pub const CInt = struct {
2 id: Id,
3 zig_name: []const u8,
4 c_name: []const u8,
5 is_signed: bool,
6
7 pub const Id = enum {
8 Short,
9 UShort,
10 Int,
11 UInt,
12 Long,
13 ULong,
14 LongLong,
15 ULongLong,
16 };
17
18 pub const list = []CInt{
19 CInt{
20 .id = Id.Short,
21 .zig_name = "c_short",
22 .c_name = "short",
23 .is_signed = true,
24 },
25 CInt{
26 .id = Id.UShort,
27 .zig_name = "c_ushort",
28 .c_name = "unsigned short",
29 .is_signed = false,
30 },
31 CInt{
32 .id = Id.Int,
33 .zig_name = "c_int",
34 .c_name = "int",
35 .is_signed = true,
36 },
37 CInt{
38 .id = Id.UInt,
39 .zig_name = "c_uint",
40 .c_name = "unsigned int",
41 .is_signed = false,
42 },
43 CInt{
44 .id = Id.Long,
45 .zig_name = "c_long",
46 .c_name = "long",
47 .is_signed = true,
48 },
49 CInt{
50 .id = Id.ULong,
51 .zig_name = "c_ulong",
52 .c_name = "unsigned long",
53 .is_signed = false,
54 },
55 CInt{
56 .id = Id.LongLong,
57 .zig_name = "c_longlong",
58 .c_name = "long long",
59 .is_signed = true,
60 },
61 CInt{
62 .id = Id.ULongLong,
63 .zig_name = "c_ulonglong",
64 .c_name = "unsigned long long",
65 .is_signed = false,
66 },
67 };
68};
src-self-hosted/codegen.zig+5-3
...@@ -15,7 +15,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)...@@ -15,7 +15,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
15 defer fn_val.base.deref(comp);15 defer fn_val.base.deref(comp);
16 defer code.destroy(comp.gpa());16 defer code.destroy(comp.gpa());
1717
18 var output_path = try await (async comp.createRandomOutputPath(comp.target.oFileExt()) catch unreachable);18 var output_path = try await (async comp.createRandomOutputPath(comp.target.objFileExt()) catch unreachable);
19 errdefer output_path.deinit();19 errdefer output_path.deinit();
2020
21 const llvm_handle = try comp.event_loop_local.getAnyLlvmContext();21 const llvm_handle = try comp.event_loop_local.getAnyLlvmContext();
...@@ -78,6 +78,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)...@@ -78,6 +78,7 @@ pub async fn renderToLlvm(comp: *Compilation, fn_val: *Value.Fn, code: *ir.Code)
78 .dibuilder = dibuilder,78 .dibuilder = dibuilder,
79 .context = context,79 .context = context,
80 .lock = event.Lock.init(comp.loop),80 .lock = event.Lock.init(comp.loop),
81 .arena = &code.arena.allocator,
81 };82 };
8283
83 try renderToLlvmModule(&ofile, fn_val, code);84 try renderToLlvmModule(&ofile, fn_val, code);
...@@ -139,6 +140,7 @@ pub const ObjectFile = struct {...@@ -139,6 +140,7 @@ pub const ObjectFile = struct {
139 dibuilder: *llvm.DIBuilder,140 dibuilder: *llvm.DIBuilder,
140 context: llvm.ContextRef,141 context: llvm.ContextRef,
141 lock: event.Lock,142 lock: event.Lock,
143 arena: *std.mem.Allocator,
142144
143 fn gpa(self: *ObjectFile) *std.mem.Allocator {145 fn gpa(self: *ObjectFile) *std.mem.Allocator {
144 return self.comp.gpa();146 return self.comp.gpa();
...@@ -147,7 +149,7 @@ pub const ObjectFile = struct {...@@ -147,7 +149,7 @@ pub const ObjectFile = struct {
147149
148pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code) !void {150pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code) !void {
149 // TODO audit more of codegen.cpp:fn_llvm_value and port more logic151 // TODO audit more of codegen.cpp:fn_llvm_value and port more logic
150 const llvm_fn_type = try fn_val.base.typeof.getLlvmType(ofile);152 const llvm_fn_type = try fn_val.base.typ.getLlvmType(ofile.arena, ofile.context);
151 const llvm_fn = llvm.AddFunction(153 const llvm_fn = llvm.AddFunction(
152 ofile.module,154 ofile.module,
153 fn_val.symbol_name.ptr(),155 fn_val.symbol_name.ptr(),
...@@ -165,7 +167,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)...@@ -165,7 +167,7 @@ pub fn renderToLlvmModule(ofile: *ObjectFile, fn_val: *Value.Fn, code: *ir.Code)
165 // try addLLVMFnAttrInt(ofile, llvm_fn, "alignstack", align_stack);167 // try addLLVMFnAttrInt(ofile, llvm_fn, "alignstack", align_stack);
166 //}168 //}
167169
168 const fn_type = fn_val.base.typeof.cast(Type.Fn).?;170 const fn_type = fn_val.base.typ.cast(Type.Fn).?;
169171
170 try addLLVMFnAttr(ofile, llvm_fn, "nounwind");172 try addLLVMFnAttr(ofile, llvm_fn, "nounwind");
171 //add_uwtable_attr(g, fn_table_entry->llvm_value);173 //add_uwtable_attr(g, fn_table_entry->llvm_value);
src-self-hosted/compilation.zig+479-193
...@@ -21,13 +21,15 @@ const Scope = @import("scope.zig").Scope;...@@ -21,13 +21,15 @@ const Scope = @import("scope.zig").Scope;
21const Decl = @import("decl.zig").Decl;21const Decl = @import("decl.zig").Decl;
22const ir = @import("ir.zig");22const ir = @import("ir.zig");
23const Visib = @import("visib.zig").Visib;23const Visib = @import("visib.zig").Visib;
24const ParsedFile = @import("parsed_file.zig").ParsedFile;
25const Value = @import("value.zig").Value;24const Value = @import("value.zig").Value;
26const Type = Value.Type;25const Type = Value.Type;
27const Span = errmsg.Span;26const Span = errmsg.Span;
27const Msg = errmsg.Msg;
28const codegen = @import("codegen.zig");28const codegen = @import("codegen.zig");
29const Package = @import("package.zig").Package;29const Package = @import("package.zig").Package;
30const link = @import("link.zig").link;30const link = @import("link.zig").link;
31const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
32const CInt = @import("c_int.zig").CInt;
3133
32/// Data that is local to the event loop.34/// Data that is local to the event loop.
33pub const EventLoopLocal = struct {35pub const EventLoopLocal = struct {
...@@ -37,6 +39,8 @@ pub const EventLoopLocal = struct {...@@ -37,6 +39,8 @@ pub const EventLoopLocal = struct {
37 /// TODO pool these so that it doesn't have to lock39 /// TODO pool these so that it doesn't have to lock
38 prng: event.Locked(std.rand.DefaultPrng),40 prng: event.Locked(std.rand.DefaultPrng),
3941
42 native_libc: event.Future(LibCInstallation),
43
40 var lazy_init_targets = std.lazyInit(void);44 var lazy_init_targets = std.lazyInit(void);
4145
42 fn init(loop: *event.Loop) !EventLoopLocal {46 fn init(loop: *event.Loop) !EventLoopLocal {
...@@ -48,13 +52,16 @@ pub const EventLoopLocal = struct {...@@ -48,13 +52,16 @@ pub const EventLoopLocal = struct {
48 var seed_bytes: [@sizeOf(u64)]u8 = undefined;52 var seed_bytes: [@sizeOf(u64)]u8 = undefined;
49 try std.os.getRandomBytes(seed_bytes[0..]);53 try std.os.getRandomBytes(seed_bytes[0..]);
50 const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big);54 const seed = std.mem.readInt(seed_bytes, u64, builtin.Endian.Big);
55
51 return EventLoopLocal{56 return EventLoopLocal{
52 .loop = loop,57 .loop = loop,
53 .llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(),58 .llvm_handle_pool = std.atomic.Stack(llvm.ContextRef).init(),
54 .prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)),59 .prng = event.Locked(std.rand.DefaultPrng).init(loop, std.rand.DefaultPrng.init(seed)),
60 .native_libc = event.Future(LibCInstallation).init(loop),
55 };61 };
56 }62 }
5763
64 /// Must be called only after EventLoop.run completes.
58 fn deinit(self: *EventLoopLocal) void {65 fn deinit(self: *EventLoopLocal) void {
59 while (self.llvm_handle_pool.pop()) |node| {66 while (self.llvm_handle_pool.pop()) |node| {
60 c.LLVMContextDispose(node.data);67 c.LLVMContextDispose(node.data);
...@@ -78,6 +85,13 @@ pub const EventLoopLocal = struct {...@@ -78,6 +85,13 @@ pub const EventLoopLocal = struct {
7885
79 return LlvmHandle{ .node = node };86 return LlvmHandle{ .node = node };
80 }87 }
88
89 pub async fn getNativeLibC(self: *EventLoopLocal) !*LibCInstallation {
90 if (await (async self.native_libc.start() catch unreachable)) |ptr| return ptr;
91 try await (async self.native_libc.data.findNative(self.loop) catch unreachable);
92 self.native_libc.resolve();
93 return &self.native_libc.data;
94 }
81};95};
8296
83pub const LlvmHandle = struct {97pub const LlvmHandle = struct {
...@@ -108,13 +122,6 @@ pub const Compilation = struct {...@@ -108,13 +122,6 @@ pub const Compilation = struct {
108 version_patch: u32,122 version_patch: u32,
109123
110 linker_script: ?[]const u8,124 linker_script: ?[]const u8,
111 cache_dir: []const u8,
112 libc_lib_dir: ?[]const u8,
113 libc_static_lib_dir: ?[]const u8,
114 libc_include_dir: ?[]const u8,
115 msvc_lib_dir: ?[]const u8,
116 kernel32_lib_dir: ?[]const u8,
117 dynamic_linker: ?[]const u8,
118 out_h_path: ?[]const u8,125 out_h_path: ?[]const u8,
119126
120 is_test: bool,127 is_test: bool,
...@@ -179,6 +186,8 @@ pub const Compilation = struct {...@@ -179,6 +186,8 @@ pub const Compilation = struct {
179 void_type: *Type.Void,186 void_type: *Type.Void,
180 bool_type: *Type.Bool,187 bool_type: *Type.Bool,
181 noreturn_type: *Type.NoReturn,188 noreturn_type: *Type.NoReturn,
189 comptime_int_type: *Type.ComptimeInt,
190 u8_type: *Type.Int,
182191
183 void_value: *Value.Void,192 void_value: *Value.Void,
184 true_value: *Value.Bool,193 true_value: *Value.Bool,
...@@ -188,6 +197,7 @@ pub const Compilation = struct {...@@ -188,6 +197,7 @@ pub const Compilation = struct {
188 target_machine: llvm.TargetMachineRef,197 target_machine: llvm.TargetMachineRef,
189 target_data_ref: llvm.TargetDataRef,198 target_data_ref: llvm.TargetDataRef,
190 target_layout_str: [*]u8,199 target_layout_str: [*]u8,
200 target_ptr_bits: u32,
191201
192 /// for allocating things which have the same lifetime as this Compilation202 /// for allocating things which have the same lifetime as this Compilation
193 arena_allocator: std.heap.ArenaAllocator,203 arena_allocator: std.heap.ArenaAllocator,
...@@ -195,7 +205,30 @@ pub const Compilation = struct {...@@ -195,7 +205,30 @@ pub const Compilation = struct {
195 root_package: *Package,205 root_package: *Package,
196 std_package: *Package,206 std_package: *Package,
197207
198 const CompileErrList = std.ArrayList(*errmsg.Msg);208 override_libc: ?*LibCInstallation,
209
210 /// need to wait on this group before deinitializing
211 deinit_group: event.Group(void),
212
213 destroy_handle: promise,
214
215 have_err_ret_tracing: bool,
216
217 /// not locked because it is read-only
218 primitive_type_table: TypeTable,
219
220 int_type_table: event.Locked(IntTypeTable),
221 array_type_table: event.Locked(ArrayTypeTable),
222 ptr_type_table: event.Locked(PtrTypeTable),
223
224 c_int_types: [CInt.list.len]*Type.Int,
225
226 const IntTypeTable = std.HashMap(*const Type.Int.Key, *Type.Int, Type.Int.Key.hash, Type.Int.Key.eql);
227 const ArrayTypeTable = std.HashMap(*const Type.Array.Key, *Type.Array, Type.Array.Key.hash, Type.Array.Key.eql);
228 const PtrTypeTable = std.HashMap(*const Type.Pointer.Key, *Type.Pointer, Type.Pointer.Key.hash, Type.Pointer.Key.eql);
229 const TypeTable = std.HashMap([]const u8, *Type, mem.hash_slice_u8, mem.eql_slice_u8);
230
231 const CompileErrList = std.ArrayList(*Msg);
199232
200 // TODO handle some of these earlier and report them in a way other than error codes233 // TODO handle some of these earlier and report them in a way other than error codes
201 pub const BuildError = error{234 pub const BuildError = error{
...@@ -240,12 +273,16 @@ pub const Compilation = struct {...@@ -240,12 +273,16 @@ pub const Compilation = struct {
240 EnvironmentVariableNotFound,273 EnvironmentVariableNotFound,
241 AppDataDirUnavailable,274 AppDataDirUnavailable,
242 LinkFailed,275 LinkFailed,
276 LibCRequiredButNotProvidedOrFound,
277 LibCMissingDynamicLinker,
278 InvalidDarwinVersionString,
279 UnsupportedLinkArchitecture,
243 };280 };
244281
245 pub const Event = union(enum) {282 pub const Event = union(enum) {
246 Ok,283 Ok,
247 Error: BuildError,284 Error: BuildError,
248 Fail: []*errmsg.Msg,285 Fail: []*Msg,
249 };286 };
250287
251 pub const DarwinVersionMin = union(enum) {288 pub const DarwinVersionMin = union(enum) {
...@@ -284,7 +321,6 @@ pub const Compilation = struct {...@@ -284,7 +321,6 @@ pub const Compilation = struct {
284 build_mode: builtin.Mode,321 build_mode: builtin.Mode,
285 is_static: bool,322 is_static: bool,
286 zig_lib_dir: []const u8,323 zig_lib_dir: []const u8,
287 cache_dir: []const u8,
288 ) !*Compilation {324 ) !*Compilation {
289 const loop = event_loop_local.loop;325 const loop = event_loop_local.loop;
290 const comp = try event_loop_local.loop.allocator.create(Compilation{326 const comp = try event_loop_local.loop.allocator.create(Compilation{
...@@ -299,7 +335,6 @@ pub const Compilation = struct {...@@ -299,7 +335,6 @@ pub const Compilation = struct {
299 .build_mode = build_mode,335 .build_mode = build_mode,
300 .zig_lib_dir = zig_lib_dir,336 .zig_lib_dir = zig_lib_dir,
301 .zig_std_dir = undefined,337 .zig_std_dir = undefined,
302 .cache_dir = cache_dir,
303 .tmp_dir = event.Future(BuildError![]u8).init(loop),338 .tmp_dir = event.Future(BuildError![]u8).init(loop),
304339
305 .name = undefined,340 .name = undefined,
...@@ -318,12 +353,6 @@ pub const Compilation = struct {...@@ -318,12 +353,6 @@ pub const Compilation = struct {
318 .verbose_link = false,353 .verbose_link = false,
319354
320 .linker_script = null,355 .linker_script = null,
321 .libc_lib_dir = null,
322 .libc_static_lib_dir = null,
323 .libc_include_dir = null,
324 .msvc_lib_dir = null,
325 .kernel32_lib_dir = null,
326 .dynamic_linker = null,
327 .out_h_path = null,356 .out_h_path = null,
328 .is_test = false,357 .is_test = false,
329 .each_lib_rpath = false,358 .each_lib_rpath = false,
...@@ -350,7 +379,12 @@ pub const Compilation = struct {...@@ -350,7 +379,12 @@ pub const Compilation = struct {
350 .link_out_file = null,379 .link_out_file = null,
351 .exported_symbol_names = event.Locked(Decl.Table).init(loop, Decl.Table.init(loop.allocator)),380 .exported_symbol_names = event.Locked(Decl.Table).init(loop, Decl.Table.init(loop.allocator)),
352 .prelink_group = event.Group(BuildError!void).init(loop),381 .prelink_group = event.Group(BuildError!void).init(loop),
382 .deinit_group = event.Group(void).init(loop),
353 .compile_errors = event.Locked(CompileErrList).init(loop, CompileErrList.init(loop.allocator)),383 .compile_errors = event.Locked(CompileErrList).init(loop, CompileErrList.init(loop.allocator)),
384 .int_type_table = event.Locked(IntTypeTable).init(loop, IntTypeTable.init(loop.allocator)),
385 .array_type_table = event.Locked(ArrayTypeTable).init(loop, ArrayTypeTable.init(loop.allocator)),
386 .ptr_type_table = event.Locked(PtrTypeTable).init(loop, PtrTypeTable.init(loop.allocator)),
387 .c_int_types = undefined,
354388
355 .meta_type = undefined,389 .meta_type = undefined,
356 .void_type = undefined,390 .void_type = undefined,
...@@ -360,15 +394,26 @@ pub const Compilation = struct {...@@ -360,15 +394,26 @@ pub const Compilation = struct {
360 .false_value = undefined,394 .false_value = undefined,
361 .noreturn_type = undefined,395 .noreturn_type = undefined,
362 .noreturn_value = undefined,396 .noreturn_value = undefined,
397 .comptime_int_type = undefined,
398 .u8_type = undefined,
363399
364 .target_machine = undefined,400 .target_machine = undefined,
365 .target_data_ref = undefined,401 .target_data_ref = undefined,
366 .target_layout_str = undefined,402 .target_layout_str = undefined,
403 .target_ptr_bits = target.getArchPtrBitWidth(),
367404
368 .root_package = undefined,405 .root_package = undefined,
369 .std_package = undefined,406 .std_package = undefined,
407
408 .override_libc = null,
409 .destroy_handle = undefined,
410 .have_err_ret_tracing = false,
411 .primitive_type_table = undefined,
370 });412 });
371 errdefer {413 errdefer {
414 comp.int_type_table.private_data.deinit();
415 comp.array_type_table.private_data.deinit();
416 comp.ptr_type_table.private_data.deinit();
372 comp.arena_allocator.deinit();417 comp.arena_allocator.deinit();
373 comp.loop.allocator.destroy(comp);418 comp.loop.allocator.destroy(comp);
374 }419 }
...@@ -378,6 +423,7 @@ pub const Compilation = struct {...@@ -378,6 +423,7 @@ pub const Compilation = struct {
378 comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple);423 comp.llvm_target = try Target.llvmTargetFromTriple(comp.llvm_triple);
379 comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena());424 comp.link_libs_list = ArrayList(*LinkLib).init(comp.arena());
380 comp.zig_std_dir = try std.os.path.join(comp.arena(), zig_lib_dir, "std");425 comp.zig_std_dir = try std.os.path.join(comp.arena(), zig_lib_dir, "std");
426 comp.primitive_type_table = TypeTable.init(comp.arena());
381427
382 const opt_level = switch (build_mode) {428 const opt_level = switch (build_mode) {
383 builtin.Mode.Debug => llvm.CodeGenLevelNone,429 builtin.Mode.Debug => llvm.CodeGenLevelNone,
...@@ -431,123 +477,221 @@ pub const Compilation = struct {...@@ -431,123 +477,221 @@ pub const Compilation = struct {
431477
432 try comp.initTypes();478 try comp.initTypes();
433479
480 comp.destroy_handle = try async<loop.allocator> comp.internalDeinit();
481
434 return comp;482 return comp;
435 }483 }
436484
485 /// it does ref the result because it could be an arbitrary integer size
486 pub async fn getPrimitiveType(comp: *Compilation, name: []const u8) !?*Type {
487 if (name.len >= 2) {
488 switch (name[0]) {
489 'i', 'u' => blk: {
490 for (name[1..]) |byte|
491 switch (byte) {
492 '0'...'9' => {},
493 else => break :blk,
494 };
495 const is_signed = name[0] == 'i';
496 const bit_count = std.fmt.parseUnsigned(u32, name[1..], 10) catch |err| switch (err) {
497 error.Overflow => return error.Overflow,
498 error.InvalidCharacter => unreachable, // we just checked the characters above
499 };
500 const int_type = try await (async Type.Int.get(comp, Type.Int.Key{
501 .bit_count = bit_count,
502 .is_signed = is_signed,
503 }) catch unreachable);
504 errdefer int_type.base.base.deref();
505 return &int_type.base;
506 },
507 else => {},
508 }
509 }
510
511 if (comp.primitive_type_table.get(name)) |entry| {
512 entry.value.base.ref();
513 return entry.value;
514 }
515
516 return null;
517 }
518
437 fn initTypes(comp: *Compilation) !void {519 fn initTypes(comp: *Compilation) !void {
438 comp.meta_type = try comp.gpa().create(Type.MetaType{520 comp.meta_type = try comp.arena().create(Type.MetaType{
439 .base = Type{521 .base = Type{
522 .name = "type",
440 .base = Value{523 .base = Value{
441 .id = Value.Id.Type,524 .id = Value.Id.Type,
442 .typeof = undefined,525 .typ = undefined,
443 .ref_count = std.atomic.Int(usize).init(3), // 3 because it references itself twice526 .ref_count = std.atomic.Int(usize).init(3), // 3 because it references itself twice
444 },527 },
445 .id = builtin.TypeId.Type,528 .id = builtin.TypeId.Type,
529 .abi_alignment = Type.AbiAlignment.init(comp.loop),
446 },530 },
447 .value = undefined,531 .value = undefined,
448 });532 });
449 comp.meta_type.value = &comp.meta_type.base;533 comp.meta_type.value = &comp.meta_type.base;
450 comp.meta_type.base.base.typeof = &comp.meta_type.base;534 comp.meta_type.base.base.typ = &comp.meta_type.base;
451 errdefer comp.gpa().destroy(comp.meta_type);535 assert((try comp.primitive_type_table.put(comp.meta_type.base.name, &comp.meta_type.base)) == null);
452536
453 comp.void_type = try comp.gpa().create(Type.Void{537 comp.void_type = try comp.arena().create(Type.Void{
454 .base = Type{538 .base = Type{
539 .name = "void",
455 .base = Value{540 .base = Value{
456 .id = Value.Id.Type,541 .id = Value.Id.Type,
457 .typeof = &Type.MetaType.get(comp).base,542 .typ = &Type.MetaType.get(comp).base,
458 .ref_count = std.atomic.Int(usize).init(1),543 .ref_count = std.atomic.Int(usize).init(1),
459 },544 },
460 .id = builtin.TypeId.Void,545 .id = builtin.TypeId.Void,
546 .abi_alignment = Type.AbiAlignment.init(comp.loop),
461 },547 },
462 });548 });
463 errdefer comp.gpa().destroy(comp.void_type);549 assert((try comp.primitive_type_table.put(comp.void_type.base.name, &comp.void_type.base)) == null);
464550
465 comp.noreturn_type = try comp.gpa().create(Type.NoReturn{551 comp.noreturn_type = try comp.arena().create(Type.NoReturn{
466 .base = Type{552 .base = Type{
553 .name = "noreturn",
467 .base = Value{554 .base = Value{
468 .id = Value.Id.Type,555 .id = Value.Id.Type,
469 .typeof = &Type.MetaType.get(comp).base,556 .typ = &Type.MetaType.get(comp).base,
470 .ref_count = std.atomic.Int(usize).init(1),557 .ref_count = std.atomic.Int(usize).init(1),
471 },558 },
472 .id = builtin.TypeId.NoReturn,559 .id = builtin.TypeId.NoReturn,
560 .abi_alignment = Type.AbiAlignment.init(comp.loop),
561 },
562 });
563 assert((try comp.primitive_type_table.put(comp.noreturn_type.base.name, &comp.noreturn_type.base)) == null);
564
565 comp.comptime_int_type = try comp.arena().create(Type.ComptimeInt{
566 .base = Type{
567 .name = "comptime_int",
568 .base = Value{
569 .id = Value.Id.Type,
570 .typ = &Type.MetaType.get(comp).base,
571 .ref_count = std.atomic.Int(usize).init(1),
572 },
573 .id = builtin.TypeId.ComptimeInt,
574 .abi_alignment = Type.AbiAlignment.init(comp.loop),
473 },575 },
474 });576 });
475 errdefer comp.gpa().destroy(comp.noreturn_type);577 assert((try comp.primitive_type_table.put(comp.comptime_int_type.base.name, &comp.comptime_int_type.base)) == null);
476578
477 comp.bool_type = try comp.gpa().create(Type.Bool{579 comp.bool_type = try comp.arena().create(Type.Bool{
478 .base = Type{580 .base = Type{
581 .name = "bool",
479 .base = Value{582 .base = Value{
480 .id = Value.Id.Type,583 .id = Value.Id.Type,
481 .typeof = &Type.MetaType.get(comp).base,584 .typ = &Type.MetaType.get(comp).base,
482 .ref_count = std.atomic.Int(usize).init(1),585 .ref_count = std.atomic.Int(usize).init(1),
483 },586 },
484 .id = builtin.TypeId.Bool,587 .id = builtin.TypeId.Bool,
588 .abi_alignment = Type.AbiAlignment.init(comp.loop),
485 },589 },
486 });590 });
487 errdefer comp.gpa().destroy(comp.bool_type);591 assert((try comp.primitive_type_table.put(comp.bool_type.base.name, &comp.bool_type.base)) == null);
488592
489 comp.void_value = try comp.gpa().create(Value.Void{593 comp.void_value = try comp.arena().create(Value.Void{
490 .base = Value{594 .base = Value{
491 .id = Value.Id.Void,595 .id = Value.Id.Void,
492 .typeof = &Type.Void.get(comp).base,596 .typ = &Type.Void.get(comp).base,
493 .ref_count = std.atomic.Int(usize).init(1),597 .ref_count = std.atomic.Int(usize).init(1),
494 },598 },
495 });599 });
496 errdefer comp.gpa().destroy(comp.void_value);
497600
498 comp.true_value = try comp.gpa().create(Value.Bool{601 comp.true_value = try comp.arena().create(Value.Bool{
499 .base = Value{602 .base = Value{
500 .id = Value.Id.Bool,603 .id = Value.Id.Bool,
501 .typeof = &Type.Bool.get(comp).base,604 .typ = &Type.Bool.get(comp).base,
502 .ref_count = std.atomic.Int(usize).init(1),605 .ref_count = std.atomic.Int(usize).init(1),
503 },606 },
504 .x = true,607 .x = true,
505 });608 });
506 errdefer comp.gpa().destroy(comp.true_value);
507609
508 comp.false_value = try comp.gpa().create(Value.Bool{610 comp.false_value = try comp.arena().create(Value.Bool{
509 .base = Value{611 .base = Value{
510 .id = Value.Id.Bool,612 .id = Value.Id.Bool,
511 .typeof = &Type.Bool.get(comp).base,613 .typ = &Type.Bool.get(comp).base,
512 .ref_count = std.atomic.Int(usize).init(1),614 .ref_count = std.atomic.Int(usize).init(1),
513 },615 },
514 .x = false,616 .x = false,
515 });617 });
516 errdefer comp.gpa().destroy(comp.false_value);
517618
518 comp.noreturn_value = try comp.gpa().create(Value.NoReturn{619 comp.noreturn_value = try comp.arena().create(Value.NoReturn{
519 .base = Value{620 .base = Value{
520 .id = Value.Id.NoReturn,621 .id = Value.Id.NoReturn,
521 .typeof = &Type.NoReturn.get(comp).base,622 .typ = &Type.NoReturn.get(comp).base,
522 .ref_count = std.atomic.Int(usize).init(1),623 .ref_count = std.atomic.Int(usize).init(1),
523 },624 },
524 });625 });
525 errdefer comp.gpa().destroy(comp.noreturn_value);626
627 for (CInt.list) |cint, i| {
628 const c_int_type = try comp.arena().create(Type.Int{
629 .base = Type{
630 .name = cint.zig_name,
631 .base = Value{
632 .id = Value.Id.Type,
633 .typ = &Type.MetaType.get(comp).base,
634 .ref_count = std.atomic.Int(usize).init(1),
635 },
636 .id = builtin.TypeId.Int,
637 .abi_alignment = Type.AbiAlignment.init(comp.loop),
638 },
639 .key = Type.Int.Key{
640 .is_signed = cint.is_signed,
641 .bit_count = comp.target.cIntTypeSizeInBits(cint.id),
642 },
643 .garbage_node = undefined,
644 });
645 comp.c_int_types[i] = c_int_type;
646 assert((try comp.primitive_type_table.put(cint.zig_name, &c_int_type.base)) == null);
647 }
648 comp.u8_type = try comp.arena().create(Type.Int{
649 .base = Type{
650 .name = "u8",
651 .base = Value{
652 .id = Value.Id.Type,
653 .typ = &Type.MetaType.get(comp).base,
654 .ref_count = std.atomic.Int(usize).init(1),
655 },
656 .id = builtin.TypeId.Int,
657 .abi_alignment = Type.AbiAlignment.init(comp.loop),
658 },
659 .key = Type.Int.Key{
660 .is_signed = false,
661 .bit_count = 8,
662 },
663 .garbage_node = undefined,
664 });
665 assert((try comp.primitive_type_table.put(comp.u8_type.base.name, &comp.u8_type.base)) == null);
526 }666 }
527667
528 pub fn destroy(self: *Compilation) void {668 /// This function can safely use async/await, because it manages Compilation's lifetime,
669 /// and EventLoopLocal.deinit will not be called until the event.Loop.run() completes.
670 async fn internalDeinit(self: *Compilation) void {
671 suspend;
672
673 await (async self.deinit_group.wait() catch unreachable);
529 if (self.tmp_dir.getOrNull()) |tmp_dir_result| if (tmp_dir_result.*) |tmp_dir| {674 if (self.tmp_dir.getOrNull()) |tmp_dir_result| if (tmp_dir_result.*) |tmp_dir| {
675 // TODO evented I/O?
530 os.deleteTree(self.arena(), tmp_dir) catch {};676 os.deleteTree(self.arena(), tmp_dir) catch {};
531 } else |_| {};677 } else |_| {};
532678
533 self.noreturn_value.base.deref(self);
534 self.void_value.base.deref(self);
535 self.false_value.base.deref(self);
536 self.true_value.base.deref(self);
537 self.noreturn_type.base.base.deref(self);
538 self.void_type.base.base.deref(self);
539 self.meta_type.base.base.deref(self);
540
541 self.events.destroy();679 self.events.destroy();
542680
543 llvm.DisposeMessage(self.target_layout_str);681 llvm.DisposeMessage(self.target_layout_str);
544 llvm.DisposeTargetData(self.target_data_ref);682 llvm.DisposeTargetData(self.target_data_ref);
545 llvm.DisposeTargetMachine(self.target_machine);683 llvm.DisposeTargetMachine(self.target_machine);
546684
685 self.primitive_type_table.deinit();
686
547 self.arena_allocator.deinit();687 self.arena_allocator.deinit();
548 self.gpa().destroy(self);688 self.gpa().destroy(self);
549 }689 }
550690
691 pub fn destroy(self: *Compilation) void {
692 resume self.destroy_handle;
693 }
694
551 pub fn build(self: *Compilation) !void {695 pub fn build(self: *Compilation) !void {
552 if (self.llvm_argv.len != 0) {696 if (self.llvm_argv.len != 0) {
553 var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.arena(), [][]const []const u8{697 var c_compatible_args = try std.cstr.NullTerminated2DArray.fromSlices(self.arena(), [][]const []const u8{
...@@ -597,79 +741,103 @@ pub const Compilation = struct {...@@ -597,79 +741,103 @@ pub const Compilation = struct {
597 }741 }
598742
599 async fn compileAndLink(self: *Compilation) !void {743 async fn compileAndLink(self: *Compilation) !void {
600 const root_src_path = self.root_src_path orelse @panic("TODO handle null root src path");744 if (self.root_src_path) |root_src_path| {
601 // TODO async/await os.path.real745 // TODO async/await os.path.real
602 const root_src_real_path = os.path.real(self.gpa(), root_src_path) catch |err| {746 const root_src_real_path = os.path.real(self.gpa(), root_src_path) catch |err| {
603 try printError("unable to get real path '{}': {}", root_src_path, err);747 try printError("unable to get real path '{}': {}", root_src_path, err);
604 return err;748 return err;
605 };749 };
606 errdefer self.gpa().free(root_src_real_path);750 const root_scope = blk: {
751 errdefer self.gpa().free(root_src_real_path);
752
753 // TODO async/await readFileAlloc()
754 const source_code = io.readFileAlloc(self.gpa(), root_src_real_path) catch |err| {
755 try printError("unable to open '{}': {}", root_src_real_path, err);
756 return err;
757 };
758 errdefer self.gpa().free(source_code);
759
760 const tree = try self.gpa().createOne(ast.Tree);
761 tree.* = try std.zig.parse(self.gpa(), source_code);
762 errdefer {
763 tree.deinit();
764 self.gpa().destroy(tree);
765 }
607766
608 // TODO async/await readFileAlloc()767 break :blk try Scope.Root.create(self, tree, root_src_real_path);
609 const source_code = io.readFileAlloc(self.gpa(), root_src_real_path) catch |err| {768 };
610 try printError("unable to open '{}': {}", root_src_real_path, err);769 defer root_scope.base.deref(self);
611 return err;770 const tree = root_scope.tree;
612 };
613 errdefer self.gpa().free(source_code);
614771
615 const parsed_file = try self.gpa().create(ParsedFile{772 var error_it = tree.errors.iterator(0);
616 .tree = undefined,773 while (error_it.next()) |parse_error| {
617 .realpath = root_src_real_path,774 const msg = try Msg.createFromParseErrorAndScope(self, root_scope, parse_error);
618 });775 errdefer msg.destroy();
619 errdefer self.gpa().destroy(parsed_file);
620
621 parsed_file.tree = try std.zig.parse(self.gpa(), source_code);
622 errdefer parsed_file.tree.deinit();
623
624 const tree = &parsed_file.tree;
625
626 // create empty struct for it
627 const decls = try Scope.Decls.create(self, null);
628 defer decls.base.deref(self);
629
630 var decl_group = event.Group(BuildError!void).init(self.loop);
631 errdefer decl_group.cancelAll();
632
633 var it = tree.root_node.decls.iterator(0);
634 while (it.next()) |decl_ptr| {
635 const decl = decl_ptr.*;
636 switch (decl.id) {
637 ast.Node.Id.Comptime => @panic("TODO"),
638 ast.Node.Id.VarDecl => @panic("TODO"),
639 ast.Node.Id.FnProto => {
640 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
641
642 const name = if (fn_proto.name_token) |name_token| tree.tokenSlice(name_token) else {
643 try self.addCompileError(parsed_file, Span{
644 .first = fn_proto.fn_token,
645 .last = fn_proto.fn_token + 1,
646 }, "missing function name");
647 continue;
648 };
649776
650 const fn_decl = try self.gpa().create(Decl.Fn{777 try await (async self.addCompileErrorAsync(msg) catch unreachable);
651 .base = Decl{778 }
652 .id = Decl.Id.Fn,779 if (tree.errors.len != 0) {
653 .name = name,780 return;
654 .visib = parseVisibToken(tree, fn_proto.visib_token),781 }
655 .resolution = event.Future(BuildError!void).init(self.loop),782
656 .resolution_in_progress = 0,783 const decls = try Scope.Decls.create(self, &root_scope.base);
657 .parsed_file = parsed_file,784 defer decls.base.deref(self);
658 .parent_scope = &decls.base,785
659 },786 var decl_group = event.Group(BuildError!void).init(self.loop);
660 .value = Decl.Fn.Val{ .Unresolved = {} },787 var decl_group_consumed = false;
661 .fn_proto = fn_proto,788 errdefer if (!decl_group_consumed) decl_group.cancelAll();
662 });789
663 errdefer self.gpa().destroy(fn_decl);790 var it = tree.root_node.decls.iterator(0);
664791 while (it.next()) |decl_ptr| {
665 try decl_group.call(addTopLevelDecl, self, &fn_decl.base);792 const decl = decl_ptr.*;
666 },793 switch (decl.id) {
667 ast.Node.Id.TestDecl => @panic("TODO"),794 ast.Node.Id.Comptime => {
668 else => unreachable,795 const comptime_node = @fieldParentPtr(ast.Node.Comptime, "base", decl);
796
797 try self.prelink_group.call(addCompTimeBlock, self, &decls.base, comptime_node);
798 },
799 ast.Node.Id.VarDecl => @panic("TODO"),
800 ast.Node.Id.FnProto => {
801 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", decl);
802
803 const name = if (fn_proto.name_token) |name_token| tree.tokenSlice(name_token) else {
804 try self.addCompileError(root_scope, Span{
805 .first = fn_proto.fn_token,
806 .last = fn_proto.fn_token + 1,
807 }, "missing function name");
808 continue;
809 };
810
811 const fn_decl = try self.gpa().create(Decl.Fn{
812 .base = Decl{
813 .id = Decl.Id.Fn,
814 .name = name,
815 .visib = parseVisibToken(tree, fn_proto.visib_token),
816 .resolution = event.Future(BuildError!void).init(self.loop),
817 .parent_scope = &decls.base,
818 },
819 .value = Decl.Fn.Val{ .Unresolved = {} },
820 .fn_proto = fn_proto,
821 });
822 errdefer self.gpa().destroy(fn_decl);
823
824 try decl_group.call(addTopLevelDecl, self, decls, &fn_decl.base);
825 },
826 ast.Node.Id.TestDecl => @panic("TODO"),
827 else => unreachable,
828 }
669 }829 }
830 decl_group_consumed = true;
831 try await (async decl_group.wait() catch unreachable);
832
833 // Now other code can rely on the decls scope having a complete list of names.
834 decls.name_future.resolve();
670 }835 }
671 try await (async decl_group.wait() catch unreachable);836
672 try await (async self.prelink_group.wait() catch unreachable);837 (await (async self.prelink_group.wait() catch unreachable)) catch |err| switch (err) {
838 error.SemanticAnalysisFailed => {},
839 else => return err,
840 };
673841
674 const any_prelink_errors = blk: {842 const any_prelink_errors = blk: {
675 const compile_errors = await (async self.compile_errors.acquire() catch unreachable);843 const compile_errors = await (async self.compile_errors.acquire() catch unreachable);
...@@ -679,39 +847,108 @@ pub const Compilation = struct {...@@ -679,39 +847,108 @@ pub const Compilation = struct {
679 };847 };
680848
681 if (!any_prelink_errors) {849 if (!any_prelink_errors) {
682 try link(self);850 try await (async link(self) catch unreachable);
683 }851 }
684 }852 }
685853
686 async fn addTopLevelDecl(self: *Compilation, decl: *Decl) !void {854 /// caller takes ownership of resulting Code
687 const is_export = decl.isExported(&decl.parsed_file.tree);855 async fn genAndAnalyzeCode(
856 comp: *Compilation,
857 scope: *Scope,
858 node: *ast.Node,
859 expected_type: ?*Type,
860 ) !*ir.Code {
861 const unanalyzed_code = try await (async ir.gen(
862 comp,
863 node,
864 scope,
865 ) catch unreachable);
866 defer unanalyzed_code.destroy(comp.gpa());
867
868 if (comp.verbose_ir) {
869 std.debug.warn("unanalyzed:\n");
870 unanalyzed_code.dump();
871 }
872
873 const analyzed_code = try await (async ir.analyze(
874 comp,
875 unanalyzed_code,
876 expected_type,
877 ) catch unreachable);
878 errdefer analyzed_code.destroy(comp.gpa());
879
880 if (comp.verbose_ir) {
881 std.debug.warn("analyzed:\n");
882 analyzed_code.dump();
883 }
884
885 return analyzed_code;
886 }
887
888 async fn addCompTimeBlock(
889 comp: *Compilation,
890 scope: *Scope,
891 comptime_node: *ast.Node.Comptime,
892 ) !void {
893 const void_type = Type.Void.get(comp);
894 defer void_type.base.base.deref(comp);
895
896 const analyzed_code = (await (async genAndAnalyzeCode(
897 comp,
898 scope,
899 comptime_node.expr,
900 &void_type.base,
901 ) catch unreachable)) catch |err| switch (err) {
902 // This poison value should not cause the errdefers to run. It simply means
903 // that comp.compile_errors is populated.
904 error.SemanticAnalysisFailed => return {},
905 else => return err,
906 };
907 analyzed_code.destroy(comp.gpa());
908 }
909
910 async fn addTopLevelDecl(self: *Compilation, decls: *Scope.Decls, decl: *Decl) !void {
911 const tree = decl.findRootScope().tree;
912 const is_export = decl.isExported(tree);
913
914 var add_to_table_resolved = false;
915 const add_to_table = async self.addDeclToTable(decls, decl) catch unreachable;
916 errdefer if (!add_to_table_resolved) cancel add_to_table; // TODO https://github.com/ziglang/zig/issues/1261
688917
689 if (is_export) {918 if (is_export) {
690 try self.prelink_group.call(verifyUniqueSymbol, self, decl);919 try self.prelink_group.call(verifyUniqueSymbol, self, decl);
691 try self.prelink_group.call(resolveDecl, self, decl);920 try self.prelink_group.call(resolveDecl, self, decl);
692 }921 }
922
923 add_to_table_resolved = true;
924 try await add_to_table;
693 }925 }
694926
695 fn addCompileError(self: *Compilation, parsed_file: *ParsedFile, span: Span, comptime fmt: []const u8, args: ...) !void {927 async fn addDeclToTable(self: *Compilation, decls: *Scope.Decls, decl: *Decl) !void {
696 const text = try std.fmt.allocPrint(self.loop.allocator, fmt, args);928 const held = await (async decls.table.acquire() catch unreachable);
697 errdefer self.loop.allocator.free(text);929 defer held.release();
698930
699 try self.prelink_group.call(addCompileErrorAsync, self, parsed_file, span, text);931 if (try held.value.put(decl.name, decl)) |other_decl| {
932 try self.addCompileError(decls.base.findRoot(), decl.getSpan(), "redefinition of '{}'", decl.name);
933 // TODO note: other definition here
934 }
935 }
936
937 fn addCompileError(self: *Compilation, root: *Scope.Root, span: Span, comptime fmt: []const u8, args: ...) !void {
938 const text = try std.fmt.allocPrint(self.gpa(), fmt, args);
939 errdefer self.gpa().free(text);
940
941 const msg = try Msg.createFromScope(self, root, span, text);
942 errdefer msg.destroy();
943
944 try self.prelink_group.call(addCompileErrorAsync, self, msg);
700 }945 }
701946
702 async fn addCompileErrorAsync(947 async fn addCompileErrorAsync(
703 self: *Compilation,948 self: *Compilation,
704 parsed_file: *ParsedFile,949 msg: *Msg,
705 span: Span,
706 text: []u8,
707 ) !void {950 ) !void {
708 const msg = try self.loop.allocator.create(errmsg.Msg{951 errdefer msg.destroy();
709 .path = parsed_file.realpath,
710 .text = text,
711 .span = span,
712 .tree = &parsed_file.tree,
713 });
714 errdefer self.loop.allocator.destroy(msg);
715952
716 const compile_errors = await (async self.compile_errors.acquire() catch unreachable);953 const compile_errors = await (async self.compile_errors.acquire() catch unreachable);
717 defer compile_errors.release();954 defer compile_errors.release();
...@@ -725,7 +962,7 @@ pub const Compilation = struct {...@@ -725,7 +962,7 @@ pub const Compilation = struct {
725962
726 if (try exported_symbol_names.value.put(decl.name, decl)) |other_decl| {963 if (try exported_symbol_names.value.put(decl.name, decl)) |other_decl| {
727 try self.addCompileError(964 try self.addCompileError(
728 decl.parsed_file,965 decl.findRootScope(),
729 decl.getSpan(),966 decl.getSpan(),
730 "exported symbol collision: '{}'",967 "exported symbol collision: '{}'",
731 decl.name,968 decl.name,
...@@ -762,10 +999,22 @@ pub const Compilation = struct {...@@ -762,10 +999,22 @@ pub const Compilation = struct {
762 try self.link_libs_list.append(link_lib);999 try self.link_libs_list.append(link_lib);
763 if (is_libc) {1000 if (is_libc) {
764 self.libc_link_lib = link_lib;1001 self.libc_link_lib = link_lib;
1002
1003 // get a head start on looking for the native libc
1004 if (self.target == Target.Native and self.override_libc == null) {
1005 try self.deinit_group.call(startFindingNativeLibC, self);
1006 }
765 }1007 }
766 return link_lib;1008 return link_lib;
767 }1009 }
7681010
1011 /// cancels itself so no need to await or cancel the promise.
1012 async fn startFindingNativeLibC(self: *Compilation) void {
1013 await (async self.loop.yield() catch unreachable);
1014 // we don't care if it fails, we're just trying to kick off the future resolution
1015 _ = (await (async self.event_loop_local.getNativeLibC() catch unreachable)) catch return;
1016 }
1017
769 /// General Purpose Allocator. Must free when done.1018 /// General Purpose Allocator. Must free when done.
770 fn gpa(self: Compilation) *mem.Allocator {1019 fn gpa(self: Compilation) *mem.Allocator {
771 return self.loop.allocator;1020 return self.loop.allocator;
...@@ -831,6 +1080,37 @@ pub const Compilation = struct {...@@ -831,6 +1080,37 @@ pub const Compilation = struct {
831 b64_fs_encoder.encode(result[0..], rand_bytes);1080 b64_fs_encoder.encode(result[0..], rand_bytes);
832 return result;1081 return result;
833 }1082 }
1083
1084 fn registerGarbage(comp: *Compilation, comptime T: type, node: *std.atomic.Stack(*T).Node) void {
1085 // TODO put the garbage somewhere
1086 }
1087
1088 /// Returns a value which has been ref()'d once
1089 async fn analyzeConstValue(comp: *Compilation, scope: *Scope, node: *ast.Node, expected_type: *Type) !*Value {
1090 const analyzed_code = try await (async comp.genAndAnalyzeCode(scope, node, expected_type) catch unreachable);
1091 defer analyzed_code.destroy(comp.gpa());
1092
1093 return analyzed_code.getCompTimeResult(comp);
1094 }
1095
1096 async fn analyzeTypeExpr(comp: *Compilation, scope: *Scope, node: *ast.Node) !*Type {
1097 const meta_type = &Type.MetaType.get(comp).base;
1098 defer meta_type.base.deref(comp);
1099
1100 const result_val = try await (async comp.analyzeConstValue(scope, node, meta_type) catch unreachable);
1101 errdefer result_val.base.deref(comp);
1102
1103 return result_val.cast(Type).?;
1104 }
1105
1106 /// This declaration has been blessed as going into the final code generation.
1107 pub async fn resolveDecl(comp: *Compilation, decl: *Decl) !void {
1108 if (await (async decl.resolution.start() catch unreachable)) |ptr| return ptr.*;
1109
1110 decl.resolution.data = try await (async generateDecl(comp, decl) catch unreachable);
1111 decl.resolution.resolve();
1112 return decl.resolution.data;
1113 }
834};1114};
8351115
836fn printError(comptime format: []const u8, args: ...) !void {1116fn printError(comptime format: []const u8, args: ...) !void {
...@@ -850,15 +1130,6 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib...@@ -850,15 +1130,6 @@ fn parseVisibToken(tree: *ast.Tree, optional_token_index: ?ast.TokenIndex) Visib
850 }1130 }
851}1131}
8521132
853/// This declaration has been blessed as going into the final code generation.
854pub async fn resolveDecl(comp: *Compilation, decl: *Decl) !void {
855 if (await (async decl.resolution.start() catch unreachable)) |ptr| return ptr.*;
856
857 decl.resolution.data = await (async generateDecl(comp, decl) catch unreachable);
858 decl.resolution.resolve();
859 return decl.resolution.data;
860}
861
862/// The function that actually does the generation.1133/// The function that actually does the generation.
863async fn generateDecl(comp: *Compilation, decl: *Decl) !void {1134async fn generateDecl(comp: *Compilation, decl: *Decl) !void {
864 switch (decl.id) {1135 switch (decl.id) {
...@@ -872,66 +1143,30 @@ async fn generateDecl(comp: *Compilation, decl: *Decl) !void {...@@ -872,66 +1143,30 @@ async fn generateDecl(comp: *Compilation, decl: *Decl) !void {
872}1143}
8731144
874async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {1145async fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
875 const body_node = fn_decl.fn_proto.body_node orelse @panic("TODO extern fn proto decl");1146 const body_node = fn_decl.fn_proto.body_node orelse return await (async generateDeclFnProto(comp, fn_decl) catch unreachable);
8761147
877 const fndef_scope = try Scope.FnDef.create(comp, fn_decl.base.parent_scope);1148 const fndef_scope = try Scope.FnDef.create(comp, fn_decl.base.parent_scope);
878 defer fndef_scope.base.deref(comp);1149 defer fndef_scope.base.deref(comp);
8791150
880 // TODO actually look at the return type of the AST1151 const fn_type = try await (async analyzeFnType(comp, fn_decl.base.parent_scope, fn_decl.fn_proto) catch unreachable);
881 const return_type = &Type.Void.get(comp).base;
882 defer return_type.base.deref(comp);
883
884 const is_var_args = false;
885 const params = ([*]Type.Fn.Param)(undefined)[0..0];
886 const fn_type = try Type.Fn.create(comp, return_type, params, is_var_args);
887 defer fn_type.base.base.deref(comp);1152 defer fn_type.base.base.deref(comp);
8881153
889 var symbol_name = try std.Buffer.init(comp.gpa(), fn_decl.base.name);1154 var symbol_name = try std.Buffer.init(comp.gpa(), fn_decl.base.name);
890 errdefer symbol_name.deinit();1155 var symbol_name_consumed = false;
1156 errdefer if (!symbol_name_consumed) symbol_name.deinit();
8911157
892 // The Decl.Fn owns the initial 1 reference count1158 // The Decl.Fn owns the initial 1 reference count
893 const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name);1159 const fn_val = try Value.Fn.create(comp, fn_type, fndef_scope, symbol_name);
894 fn_decl.value = Decl.Fn.Val{ .Ok = fn_val };1160 fn_decl.value = Decl.Fn.Val{ .Fn = fn_val };
1161 symbol_name_consumed = true;
8951162
896 const unanalyzed_code = (await (async ir.gen(1163 const analyzed_code = try await (async comp.genAndAnalyzeCode(
897 comp,
898 body_node,
899 &fndef_scope.base,1164 &fndef_scope.base,
900 Span.token(body_node.lastToken()),1165 body_node,
901 fn_decl.base.parsed_file,1166 fn_type.return_type,
902 ) catch unreachable)) catch |err| switch (err) {1167 ) catch unreachable);
903 // This poison value should not cause the errdefers to run. It simply means
904 // that self.compile_errors is populated.
905 // TODO https://github.com/ziglang/zig/issues/769
906 error.SemanticAnalysisFailed => return {},
907 else => return err,
908 };
909 defer unanalyzed_code.destroy(comp.gpa());
910
911 if (comp.verbose_ir) {
912 std.debug.warn("unanalyzed:\n");
913 unanalyzed_code.dump();
914 }
915
916 const analyzed_code = (await (async ir.analyze(
917 comp,
918 fn_decl.base.parsed_file,
919 unanalyzed_code,
920 null,
921 ) catch unreachable)) catch |err| switch (err) {
922 // This poison value should not cause the errdefers to run. It simply means
923 // that self.compile_errors is populated.
924 // TODO https://github.com/ziglang/zig/issues/769
925 error.SemanticAnalysisFailed => return {},
926 else => return err,
927 };
928 errdefer analyzed_code.destroy(comp.gpa());1168 errdefer analyzed_code.destroy(comp.gpa());
9291169
930 if (comp.verbose_ir) {
931 std.debug.warn("analyzed:\n");
932 analyzed_code.dump();
933 }
934
935 // Kick off rendering to LLVM module, but it doesn't block the fn decl1170 // Kick off rendering to LLVM module, but it doesn't block the fn decl
936 // analysis from being complete.1171 // analysis from being complete.
937 try comp.prelink_group.call(codegen.renderToLlvm, comp, fn_val, analyzed_code);1172 try comp.prelink_group.call(codegen.renderToLlvm, comp, fn_val, analyzed_code);
...@@ -953,3 +1188,54 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void {...@@ -953,3 +1188,54 @@ async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) void {
953fn getZigDir(allocator: *mem.Allocator) ![]u8 {1188fn getZigDir(allocator: *mem.Allocator) ![]u8 {
954 return os.getAppDataDir(allocator, "zig");1189 return os.getAppDataDir(allocator, "zig");
955}1190}
1191
1192async fn analyzeFnType(comp: *Compilation, scope: *Scope, fn_proto: *ast.Node.FnProto) !*Type.Fn {
1193 const return_type_node = switch (fn_proto.return_type) {
1194 ast.Node.FnProto.ReturnType.Explicit => |n| n,
1195 ast.Node.FnProto.ReturnType.InferErrorSet => |n| n,
1196 };
1197 const return_type = try await (async comp.analyzeTypeExpr(scope, return_type_node) catch unreachable);
1198 return_type.base.deref(comp);
1199
1200 var params = ArrayList(Type.Fn.Param).init(comp.gpa());
1201 var params_consumed = false;
1202 defer if (params_consumed) {
1203 for (params.toSliceConst()) |param| {
1204 param.typ.base.deref(comp);
1205 }
1206 params.deinit();
1207 };
1208
1209 const is_var_args = false;
1210 {
1211 var it = fn_proto.params.iterator(0);
1212 while (it.next()) |param_node_ptr| {
1213 const param_node = param_node_ptr.*.cast(ast.Node.ParamDecl).?;
1214 const param_type = try await (async comp.analyzeTypeExpr(scope, param_node.type_node) catch unreachable);
1215 errdefer param_type.base.deref(comp);
1216 try params.append(Type.Fn.Param{
1217 .typ = param_type,
1218 .is_noalias = param_node.noalias_token != null,
1219 });
1220 }
1221 }
1222 const fn_type = try Type.Fn.create(comp, return_type, params.toOwnedSlice(), is_var_args);
1223 params_consumed = true;
1224 errdefer fn_type.base.base.deref(comp);
1225
1226 return fn_type;
1227}
1228
1229async fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1230 const fn_type = try await (async analyzeFnType(comp, fn_decl.base.parent_scope, fn_decl.fn_proto) catch unreachable);
1231 defer fn_type.base.base.deref(comp);
1232
1233 var symbol_name = try std.Buffer.init(comp.gpa(), fn_decl.base.name);
1234 var symbol_name_consumed = false;
1235 defer if (!symbol_name_consumed) symbol_name.deinit();
1236
1237 // The Decl.Fn owns the initial 1 reference count
1238 const fn_proto_val = try Value.FnProto.create(comp, fn_type, symbol_name);
1239 fn_decl.value = Decl.Fn.Val{ .FnProto = fn_proto_val };
1240 symbol_name_consumed = true;
1241}
src-self-hosted/decl.zig+8-6
...@@ -3,7 +3,6 @@ const Allocator = mem.Allocator;...@@ -3,7 +3,6 @@ const Allocator = mem.Allocator;
3const mem = std.mem;3const mem = std.mem;
4const ast = std.zig.ast;4const ast = std.zig.ast;
5const Visib = @import("visib.zig").Visib;5const Visib = @import("visib.zig").Visib;
6const ParsedFile = @import("parsed_file.zig").ParsedFile;
7const event = std.event;6const event = std.event;
8const Value = @import("value.zig").Value;7const Value = @import("value.zig").Value;
9const Token = std.zig.Token;8const Token = std.zig.Token;
...@@ -16,8 +15,6 @@ pub const Decl = struct {...@@ -16,8 +15,6 @@ pub const Decl = struct {
16 name: []const u8,15 name: []const u8,
17 visib: Visib,16 visib: Visib,
18 resolution: event.Future(Compilation.BuildError!void),17 resolution: event.Future(Compilation.BuildError!void),
19 resolution_in_progress: u8,
20 parsed_file: *ParsedFile,
21 parent_scope: *Scope,18 parent_scope: *Scope,
2219
23 pub const Table = std.HashMap([]const u8, *Decl, mem.hash_slice_u8, mem.eql_slice_u8);20 pub const Table = std.HashMap([]const u8, *Decl, mem.hash_slice_u8, mem.eql_slice_u8);
...@@ -48,6 +45,10 @@ pub const Decl = struct {...@@ -48,6 +45,10 @@ pub const Decl = struct {
48 }45 }
49 }46 }
5047
48 pub fn findRootScope(base: *const Decl) *Scope.Root {
49 return base.parent_scope.findRoot();
50 }
51
51 pub const Id = enum {52 pub const Id = enum {
52 Var,53 Var,
53 Fn,54 Fn,
...@@ -61,12 +62,13 @@ pub const Decl = struct {...@@ -61,12 +62,13 @@ pub const Decl = struct {
61 pub const Fn = struct {62 pub const Fn = struct {
62 base: Decl,63 base: Decl,
63 value: Val,64 value: Val,
64 fn_proto: *const ast.Node.FnProto,65 fn_proto: *ast.Node.FnProto,
6566
66 // TODO https://github.com/ziglang/zig/issues/683 and then make this anonymous67 // TODO https://github.com/ziglang/zig/issues/683 and then make this anonymous
67 pub const Val = union {68 pub const Val = union(enum) {
68 Unresolved: void,69 Unresolved: void,
69 Ok: *Value.Fn,70 Fn: *Value.Fn,
71 FnProto: *Value.FnProto,
70 };72 };
7173
72 pub fn externLibName(self: Fn, tree: *ast.Tree) ?[]const u8 {74 pub fn externLibName(self: Fn, tree: *ast.Tree) ?[]const u8 {
src-self-hosted/errmsg.zig+203-66
...@@ -4,6 +4,8 @@ const os = std.os;...@@ -4,6 +4,8 @@ const os = std.os;
4const Token = std.zig.Token;4const Token = std.zig.Token;
5const ast = std.zig.ast;5const ast = std.zig.ast;
6const TokenIndex = std.zig.ast.TokenIndex;6const TokenIndex = std.zig.ast.TokenIndex;
7const Compilation = @import("compilation.zig").Compilation;
8const Scope = @import("scope.zig").Scope;
79
8pub const Color = enum {10pub const Color = enum {
9 Auto,11 Auto,
...@@ -16,85 +18,220 @@ pub const Span = struct {...@@ -16,85 +18,220 @@ pub const Span = struct {
16 last: ast.TokenIndex,18 last: ast.TokenIndex,
1719
18 pub fn token(i: TokenIndex) Span {20 pub fn token(i: TokenIndex) Span {
19 return Span {21 return Span{
20 .first = i,22 .first = i,
21 .last = i,23 .last = i,
22 };24 };
23 }25 }
26
27 pub fn node(n: *ast.Node) Span {
28 return Span{
29 .first = n.firstToken(),
30 .last = n.lastToken(),
31 };
32 }
24};33};
2534
26pub const Msg = struct {35pub const Msg = struct {
27 path: []const u8,
28 text: []u8,
29 span: Span,36 span: Span,
30 tree: *ast.Tree,37 text: []u8,
31};38 data: Data,
39
40 const Data = union(enum) {
41 PathAndTree: PathAndTree,
42 ScopeAndComp: ScopeAndComp,
43 };
44
45 const PathAndTree = struct {
46 realpath: []const u8,
47 tree: *ast.Tree,
48 allocator: *mem.Allocator,
49 };
50
51 const ScopeAndComp = struct {
52 root_scope: *Scope.Root,
53 compilation: *Compilation,
54 };
55
56 pub fn destroy(self: *Msg) void {
57 switch (self.data) {
58 Data.PathAndTree => |path_and_tree| {
59 path_and_tree.allocator.free(self.text);
60 path_and_tree.allocator.destroy(self);
61 },
62 Data.ScopeAndComp => |scope_and_comp| {
63 scope_and_comp.root_scope.base.deref(scope_and_comp.compilation);
64 scope_and_comp.compilation.gpa().free(self.text);
65 scope_and_comp.compilation.gpa().destroy(self);
66 },
67 }
68 }
69
70 fn getAllocator(self: *const Msg) *mem.Allocator {
71 switch (self.data) {
72 Data.PathAndTree => |path_and_tree| {
73 return path_and_tree.allocator;
74 },
75 Data.ScopeAndComp => |scope_and_comp| {
76 return scope_and_comp.compilation.gpa();
77 },
78 }
79 }
80
81 pub fn getRealPath(self: *const Msg) []const u8 {
82 switch (self.data) {
83 Data.PathAndTree => |path_and_tree| {
84 return path_and_tree.realpath;
85 },
86 Data.ScopeAndComp => |scope_and_comp| {
87 return scope_and_comp.root_scope.realpath;
88 },
89 }
90 }
91
92 pub fn getTree(self: *const Msg) *ast.Tree {
93 switch (self.data) {
94 Data.PathAndTree => |path_and_tree| {
95 return path_and_tree.tree;
96 },
97 Data.ScopeAndComp => |scope_and_comp| {
98 return scope_and_comp.root_scope.tree;
99 },
100 }
101 }
102
103 /// Takes ownership of text
104 /// References root_scope, and derefs when the msg is freed
105 pub fn createFromScope(comp: *Compilation, root_scope: *Scope.Root, span: Span, text: []u8) !*Msg {
106 const msg = try comp.gpa().create(Msg{
107 .text = text,
108 .span = span,
109 .data = Data{
110 .ScopeAndComp = ScopeAndComp{
111 .root_scope = root_scope,
112 .compilation = comp,
113 },
114 },
115 });
116 root_scope.base.ref();
117 return msg;
118 }
119
120 pub fn createFromParseErrorAndScope(
121 comp: *Compilation,
122 root_scope: *Scope.Root,
123 parse_error: *const ast.Error,
124 ) !*Msg {
125 const loc_token = parse_error.loc();
126 var text_buf = try std.Buffer.initSize(comp.gpa(), 0);
127 defer text_buf.deinit();
128
129 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
130 try parse_error.render(&root_scope.tree.tokens, out_stream);
131
132 const msg = try comp.gpa().create(Msg{
133 .text = undefined,
134 .span = Span{
135 .first = loc_token,
136 .last = loc_token,
137 },
138 .data = Data{
139 .ScopeAndComp = ScopeAndComp{
140 .root_scope = root_scope,
141 .compilation = comp,
142 },
143 },
144 });
145 root_scope.base.ref();
146 msg.text = text_buf.toOwnedSlice();
147 return msg;
148 }
149
150 /// `realpath` must outlive the returned Msg
151 /// `tree` must outlive the returned Msg
152 /// Caller owns returned Msg and must free with `allocator`
153 /// allocator will additionally be used for printing messages later.
154 pub fn createFromParseError(
155 allocator: *mem.Allocator,
156 parse_error: *const ast.Error,
157 tree: *ast.Tree,
158 realpath: []const u8,
159 ) !*Msg {
160 const loc_token = parse_error.loc();
161 var text_buf = try std.Buffer.initSize(allocator, 0);
162 defer text_buf.deinit();
163
164 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
165 try parse_error.render(&tree.tokens, out_stream);
166
167 const msg = try allocator.create(Msg{
168 .text = undefined,
169 .data = Data{
170 .PathAndTree = PathAndTree{
171 .allocator = allocator,
172 .realpath = realpath,
173 .tree = tree,
174 },
175 },
176 .span = Span{
177 .first = loc_token,
178 .last = loc_token,
179 },
180 });
181 msg.text = text_buf.toOwnedSlice();
182 errdefer allocator.destroy(msg);
183
184 return msg;
185 }
186
187 pub fn printToStream(msg: *const Msg, stream: var, color_on: bool) !void {
188 const allocator = msg.getAllocator();
189 const realpath = msg.getRealPath();
190 const tree = msg.getTree();
191
192 const cwd = try os.getCwd(allocator);
193 defer allocator.free(cwd);
194
195 const relpath = try os.path.relative(allocator, cwd, realpath);
196 defer allocator.free(relpath);
197
198 const path = if (relpath.len < realpath.len) relpath else realpath;
199
200 const first_token = tree.tokens.at(msg.span.first);
201 const last_token = tree.tokens.at(msg.span.last);
202 const start_loc = tree.tokenLocationPtr(0, first_token);
203 const end_loc = tree.tokenLocationPtr(first_token.end, last_token);
204 if (!color_on) {
205 try stream.print(
206 "{}:{}:{}: error: {}\n",
207 path,
208 start_loc.line + 1,
209 start_loc.column + 1,
210 msg.text,
211 );
212 return;
213 }
32214
33/// `path` must outlive the returned Msg
34/// `tree` must outlive the returned Msg
35/// Caller owns returned Msg and must free with `allocator`
36pub fn createFromParseError(
37 allocator: *mem.Allocator,
38 parse_error: *const ast.Error,
39 tree: *ast.Tree,
40 path: []const u8,
41) !*Msg {
42 const loc_token = parse_error.loc();
43 var text_buf = try std.Buffer.initSize(allocator, 0);
44 defer text_buf.deinit();
45
46 var out_stream = &std.io.BufferOutStream.init(&text_buf).stream;
47 try parse_error.render(&tree.tokens, out_stream);
48
49 const msg = try allocator.create(Msg{
50 .tree = tree,
51 .path = path,
52 .text = text_buf.toOwnedSlice(),
53 .span = Span{
54 .first = loc_token,
55 .last = loc_token,
56 },
57 });
58 errdefer allocator.destroy(msg);
59
60 return msg;
61}
62
63pub fn printToStream(stream: var, msg: *const Msg, color_on: bool) !void {
64 const first_token = msg.tree.tokens.at(msg.span.first);
65 const last_token = msg.tree.tokens.at(msg.span.last);
66 const start_loc = msg.tree.tokenLocationPtr(0, first_token);
67 const end_loc = msg.tree.tokenLocationPtr(first_token.end, last_token);
68 if (!color_on) {
69 try stream.print(215 try stream.print(
70 "{}:{}:{}: error: {}\n",216 "{}:{}:{}: error: {}\n{}\n",
71 msg.path,217 path,
72 start_loc.line + 1,218 start_loc.line + 1,
73 start_loc.column + 1,219 start_loc.column + 1,
74 msg.text,220 msg.text,
221 tree.source[start_loc.line_start..start_loc.line_end],
75 );222 );
76 return;223 try stream.writeByteNTimes(' ', start_loc.column);
224 try stream.writeByteNTimes('~', last_token.end - first_token.start);
225 try stream.write("\n");
77 }226 }
78227
79 try stream.print(228 pub fn printToFile(msg: *const Msg, file: *os.File, color: Color) !void {
80 "{}:{}:{}: error: {}\n{}\n",229 const color_on = switch (color) {
81 msg.path,230 Color.Auto => file.isTty(),
82 start_loc.line + 1,231 Color.On => true,
83 start_loc.column + 1,232 Color.Off => false,
84 msg.text,233 };
85 msg.tree.source[start_loc.line_start..start_loc.line_end],234 var stream = &std.io.FileOutStream.init(file).stream;
86 );235 return msg.printToStream(stream, color_on);
87 try stream.writeByteNTimes(' ', start_loc.column);236 }
88 try stream.writeByteNTimes('~', last_token.end - first_token.start);237};
89 try stream.write("\n");
90}
91
92pub fn printToFile(file: *os.File, msg: *const Msg, color: Color) !void {
93 const color_on = switch (color) {
94 Color.Auto => file.isTty(),
95 Color.On => true,
96 Color.Off => false,
97 };
98 var stream = &std.io.FileOutStream.init(file).stream;
99 return printToStream(stream, msg, color_on);
100}
src-self-hosted/ir.zig+1551-197
...@@ -8,10 +8,10 @@ const Value = @import("value.zig").Value;...@@ -8,10 +8,10 @@ const Value = @import("value.zig").Value;
8const Type = Value.Type;8const Type = Value.Type;
9const assert = std.debug.assert;9const assert = std.debug.assert;
10const Token = std.zig.Token;10const Token = std.zig.Token;
11const ParsedFile = @import("parsed_file.zig").ParsedFile;
12const Span = @import("errmsg.zig").Span;11const Span = @import("errmsg.zig").Span;
13const llvm = @import("llvm.zig");12const llvm = @import("llvm.zig");
14const ObjectFile = @import("codegen.zig").ObjectFile;13const ObjectFile = @import("codegen.zig").ObjectFile;
14const Decl = @import("decl.zig").Decl;
1515
16pub const LVal = enum {16pub const LVal = enum {
17 None,17 None,
...@@ -31,10 +31,10 @@ pub const IrVal = union(enum) {...@@ -31,10 +31,10 @@ pub const IrVal = union(enum) {
3131
32 pub fn dump(self: IrVal) void {32 pub fn dump(self: IrVal) void {
33 switch (self) {33 switch (self) {
34 IrVal.Unknown => typeof.dump(),34 IrVal.Unknown => std.debug.warn("Unknown"),
35 IrVal.KnownType => |typeof| {35 IrVal.KnownType => |typ| {
36 std.debug.warn("KnownType(");36 std.debug.warn("KnownType(");
37 typeof.dump();37 typ.dump();
38 std.debug.warn(")");38 std.debug.warn(")");
39 },39 },
40 IrVal.KnownValue => |value| {40 IrVal.KnownValue => |value| {
...@@ -46,7 +46,7 @@ pub const IrVal = union(enum) {...@@ -46,7 +46,7 @@ pub const IrVal = union(enum) {
46 }46 }
47};47};
4848
49pub const Instruction = struct {49pub const Inst = struct {
50 id: Id,50 id: Id,
51 scope: *Scope,51 scope: *Scope,
52 debug_id: usize,52 debug_id: usize,
...@@ -59,15 +59,15 @@ pub const Instruction = struct {...@@ -59,15 +59,15 @@ pub const Instruction = struct {
59 is_generated: bool,59 is_generated: bool,
6060
61 /// the instruction that is derived from this one in analysis61 /// the instruction that is derived from this one in analysis
62 child: ?*Instruction,62 child: ?*Inst,
6363
64 /// the instruction that this one derives from in analysis64 /// the instruction that this one derives from in analysis
65 parent: ?*Instruction,65 parent: ?*Inst,
6666
67 /// populated durign codegen67 /// populated durign codegen
68 llvm_value: ?llvm.ValueRef,68 llvm_value: ?llvm.ValueRef,
6969
70 pub fn cast(base: *Instruction, comptime T: type) ?*T {70 pub fn cast(base: *Inst, comptime T: type) ?*T {
71 if (base.id == comptime typeToId(T)) {71 if (base.id == comptime typeToId(T)) {
72 return @fieldParentPtr(T, "base", base);72 return @fieldParentPtr(T, "base", base);
73 }73 }
...@@ -77,18 +77,18 @@ pub const Instruction = struct {...@@ -77,18 +77,18 @@ pub const Instruction = struct {
77 pub fn typeToId(comptime T: type) Id {77 pub fn typeToId(comptime T: type) Id {
78 comptime var i = 0;78 comptime var i = 0;
79 inline while (i < @memberCount(Id)) : (i += 1) {79 inline while (i < @memberCount(Id)) : (i += 1) {
80 if (T == @field(Instruction, @memberName(Id, i))) {80 if (T == @field(Inst, @memberName(Id, i))) {
81 return @field(Id, @memberName(Id, i));81 return @field(Id, @memberName(Id, i));
82 }82 }
83 }83 }
84 unreachable;84 unreachable;
85 }85 }
8686
87 pub fn dump(base: *const Instruction) void {87 pub fn dump(base: *const Inst) void {
88 comptime var i = 0;88 comptime var i = 0;
89 inline while (i < @memberCount(Id)) : (i += 1) {89 inline while (i < @memberCount(Id)) : (i += 1) {
90 if (base.id == @field(Id, @memberName(Id, i))) {90 if (base.id == @field(Id, @memberName(Id, i))) {
91 const T = @field(Instruction, @memberName(Id, i));91 const T = @field(Inst, @memberName(Id, i));
92 std.debug.warn("#{} = {}(", base.debug_id, @tagName(base.id));92 std.debug.warn("#{} = {}(", base.debug_id, @tagName(base.id));
93 @fieldParentPtr(T, "base", base).dump();93 @fieldParentPtr(T, "base", base).dump();
94 std.debug.warn(")");94 std.debug.warn(")");
...@@ -98,32 +98,40 @@ pub const Instruction = struct {...@@ -98,32 +98,40 @@ pub const Instruction = struct {
98 unreachable;98 unreachable;
99 }99 }
100100
101 pub fn hasSideEffects(base: *const Instruction) bool {101 pub fn hasSideEffects(base: *const Inst) bool {
102 comptime var i = 0;102 comptime var i = 0;
103 inline while (i < @memberCount(Id)) : (i += 1) {103 inline while (i < @memberCount(Id)) : (i += 1) {
104 if (base.id == @field(Id, @memberName(Id, i))) {104 if (base.id == @field(Id, @memberName(Id, i))) {
105 const T = @field(Instruction, @memberName(Id, i));105 const T = @field(Inst, @memberName(Id, i));
106 return @fieldParentPtr(T, "base", base).hasSideEffects();106 return @fieldParentPtr(T, "base", base).hasSideEffects();
107 }107 }
108 }108 }
109 unreachable;109 unreachable;
110 }110 }
111111
112 pub fn analyze(base: *Instruction, ira: *Analyze) Analyze.Error!*Instruction {112 pub async fn analyze(base: *Inst, ira: *Analyze) Analyze.Error!*Inst {
113 comptime var i = 0;113 switch (base.id) {
114 inline while (i < @memberCount(Id)) : (i += 1) {114 Id.Return => return @fieldParentPtr(Return, "base", base).analyze(ira),
115 if (base.id == @field(Id, @memberName(Id, i))) {115 Id.Const => return @fieldParentPtr(Const, "base", base).analyze(ira),
116 const T = @field(Instruction, @memberName(Id, i));116 Id.Call => return @fieldParentPtr(Call, "base", base).analyze(ira),
117 return @fieldParentPtr(T, "base", base).analyze(ira);117 Id.DeclRef => return await (async @fieldParentPtr(DeclRef, "base", base).analyze(ira) catch unreachable),
118 }118 Id.Ref => return await (async @fieldParentPtr(Ref, "base", base).analyze(ira) catch unreachable),
119 Id.DeclVar => return @fieldParentPtr(DeclVar, "base", base).analyze(ira),
120 Id.CheckVoidStmt => return @fieldParentPtr(CheckVoidStmt, "base", base).analyze(ira),
121 Id.Phi => return @fieldParentPtr(Phi, "base", base).analyze(ira),
122 Id.Br => return @fieldParentPtr(Br, "base", base).analyze(ira),
123 Id.AddImplicitReturnType => return @fieldParentPtr(AddImplicitReturnType, "base", base).analyze(ira),
124 Id.PtrType => return await (async @fieldParentPtr(PtrType, "base", base).analyze(ira) catch unreachable),
119 }125 }
120 unreachable;
121 }126 }
122127
123 pub fn render(base: *Instruction, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) {128 pub fn render(base: *Inst, ofile: *ObjectFile, fn_val: *Value.Fn) (error{OutOfMemory}!?llvm.ValueRef) {
124 switch (base.id) {129 switch (base.id) {
125 Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),130 Id.Return => return @fieldParentPtr(Return, "base", base).render(ofile, fn_val),
126 Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),131 Id.Const => return @fieldParentPtr(Const, "base", base).render(ofile, fn_val),
132 Id.Call => return @fieldParentPtr(Call, "base", base).render(ofile, fn_val),
133 Id.DeclRef => unreachable,
134 Id.PtrType => unreachable,
127 Id.Ref => @panic("TODO"),135 Id.Ref => @panic("TODO"),
128 Id.DeclVar => @panic("TODO"),136 Id.DeclVar => @panic("TODO"),
129 Id.CheckVoidStmt => @panic("TODO"),137 Id.CheckVoidStmt => @panic("TODO"),
...@@ -133,14 +141,22 @@ pub const Instruction = struct {...@@ -133,14 +141,22 @@ pub const Instruction = struct {
133 }141 }
134 }142 }
135143
136 fn ref(base: *Instruction, builder: *Builder) void {144 fn ref(base: *Inst, builder: *Builder) void {
137 base.ref_count += 1;145 base.ref_count += 1;
138 if (base.owner_bb != builder.current_basic_block and !base.isCompTime()) {146 if (base.owner_bb != builder.current_basic_block and !base.isCompTime()) {
139 base.owner_bb.ref();147 base.owner_bb.ref(builder);
140 }148 }
141 }149 }
142150
143 fn getAsParam(param: *Instruction) !*Instruction {151 fn copyVal(base: *Inst, comp: *Compilation) !*Value {
152 if (base.parent.?.ref_count == 0) {
153 return base.val.KnownValue.derefAndCopy(comp);
154 }
155 return base.val.KnownValue.copy(comp);
156 }
157
158 fn getAsParam(param: *Inst) !*Inst {
159 param.ref_count -= 1;
144 const child = param.child orelse return error.SemanticAnalysisFailed;160 const child = param.child orelse return error.SemanticAnalysisFailed;
145 switch (child.val) {161 switch (child.val) {
146 IrVal.Unknown => return error.SemanticAnalysisFailed,162 IrVal.Unknown => return error.SemanticAnalysisFailed,
...@@ -148,32 +164,72 @@ pub const Instruction = struct {...@@ -148,32 +164,72 @@ pub const Instruction = struct {
148 }164 }
149 }165 }
150166
167 fn getConstVal(self: *Inst, ira: *Analyze) !*Value {
168 if (self.isCompTime()) {
169 return self.val.KnownValue;
170 } else {
171 try ira.addCompileError(self.span, "unable to evaluate constant expression");
172 return error.SemanticAnalysisFailed;
173 }
174 }
175
176 fn getAsConstType(param: *Inst, ira: *Analyze) !*Type {
177 const meta_type = Type.MetaType.get(ira.irb.comp);
178 meta_type.base.base.deref(ira.irb.comp);
179
180 const inst = try param.getAsParam();
181 const casted = try ira.implicitCast(inst, &meta_type.base);
182 const val = try casted.getConstVal(ira);
183 return val.cast(Value.Type).?;
184 }
185
186 fn getAsConstAlign(param: *Inst, ira: *Analyze) !u32 {
187 return error.Unimplemented;
188 //const align_type = Type.Int.get_align(ira.irb.comp);
189 //align_type.base.base.deref(ira.irb.comp);
190
191 //const inst = try param.getAsParam();
192 //const casted = try ira.implicitCast(inst, align_type);
193 //const val = try casted.getConstVal(ira);
194
195 //uint32_t align_bytes = bigint_as_unsigned(&const_val->data.x_bigint);
196 //if (align_bytes == 0) {
197 // ir_add_error(ira, value, buf_sprintf("alignment must be >= 1"));
198 // return false;
199 //}
200
201 //if (!is_power_of_2(align_bytes)) {
202 // ir_add_error(ira, value, buf_sprintf("alignment value %" PRIu32 " is not a power of 2", align_bytes));
203 // return false;
204 //}
205 }
206
151 /// asserts that the type is known207 /// asserts that the type is known
152 fn getKnownType(self: *Instruction) *Type {208 fn getKnownType(self: *Inst) *Type {
153 switch (self.val) {209 switch (self.val) {
154 IrVal.KnownType => |typeof| return typeof,210 IrVal.KnownType => |typ| return typ,
155 IrVal.KnownValue => |value| return value.typeof,211 IrVal.KnownValue => |value| return value.typ,
156 IrVal.Unknown => unreachable,212 IrVal.Unknown => unreachable,
157 }213 }
158 }214 }
159215
160 pub fn setGenerated(base: *Instruction) void {216 pub fn setGenerated(base: *Inst) void {
161 base.is_generated = true;217 base.is_generated = true;
162 }218 }
163219
164 pub fn isNoReturn(base: *const Instruction) bool {220 pub fn isNoReturn(base: *const Inst) bool {
165 switch (base.val) {221 switch (base.val) {
166 IrVal.Unknown => return false,222 IrVal.Unknown => return false,
167 IrVal.KnownValue => |x| return x.typeof.id == Type.Id.NoReturn,223 IrVal.KnownValue => |x| return x.typ.id == Type.Id.NoReturn,
168 IrVal.KnownType => |typeof| return typeof.id == Type.Id.NoReturn,224 IrVal.KnownType => |typ| return typ.id == Type.Id.NoReturn,
169 }225 }
170 }226 }
171227
172 pub fn isCompTime(base: *const Instruction) bool {228 pub fn isCompTime(base: *const Inst) bool {
173 return base.val == IrVal.KnownValue;229 return base.val == IrVal.KnownValue;
174 }230 }
175231
176 pub fn linkToParent(self: *Instruction, parent: *Instruction) void {232 pub fn linkToParent(self: *Inst, parent: *Inst) void {
177 assert(self.parent == null);233 assert(self.parent == null);
178 assert(parent.child == null);234 assert(parent.child == null);
179 self.parent = parent;235 self.parent = parent;
...@@ -189,10 +245,89 @@ pub const Instruction = struct {...@@ -189,10 +245,89 @@ pub const Instruction = struct {
189 Phi,245 Phi,
190 Br,246 Br,
191 AddImplicitReturnType,247 AddImplicitReturnType,
248 Call,
249 DeclRef,
250 PtrType,
251 };
252
253 pub const Call = struct {
254 base: Inst,
255 params: Params,
256
257 const Params = struct {
258 fn_ref: *Inst,
259 args: []*Inst,
260 };
261
262 const ir_val_init = IrVal.Init.Unknown;
263
264 pub fn dump(self: *const Call) void {
265 std.debug.warn("#{}(", self.params.fn_ref.debug_id);
266 for (self.params.args) |arg| {
267 std.debug.warn("#{},", arg.debug_id);
268 }
269 std.debug.warn(")");
270 }
271
272 pub fn hasSideEffects(self: *const Call) bool {
273 return true;
274 }
275
276 pub fn analyze(self: *const Call, ira: *Analyze) !*Inst {
277 const fn_ref = try self.params.fn_ref.getAsParam();
278 const fn_ref_type = fn_ref.getKnownType();
279 const fn_type = fn_ref_type.cast(Type.Fn) orelse {
280 try ira.addCompileError(fn_ref.span, "type '{}' not a function", fn_ref_type.name);
281 return error.SemanticAnalysisFailed;
282 };
283
284 if (fn_type.params.len != self.params.args.len) {
285 try ira.addCompileError(
286 self.base.span,
287 "expected {} arguments, found {}",
288 fn_type.params.len,
289 self.params.args.len,
290 );
291 return error.SemanticAnalysisFailed;
292 }
293
294 const args = try ira.irb.arena().alloc(*Inst, self.params.args.len);
295 for (self.params.args) |arg, i| {
296 args[i] = try arg.getAsParam();
297 }
298 const new_inst = try ira.irb.build(Call, self.base.scope, self.base.span, Params{
299 .fn_ref = fn_ref,
300 .args = args,
301 });
302 new_inst.val = IrVal{ .KnownType = fn_type.return_type };
303 return new_inst;
304 }
305
306 pub fn render(self: *Call, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
307 const fn_ref = self.params.fn_ref.llvm_value.?;
308
309 const args = try ofile.arena.alloc(llvm.ValueRef, self.params.args.len);
310 for (self.params.args) |arg, i| {
311 args[i] = arg.llvm_value.?;
312 }
313
314 const llvm_cc = llvm.CCallConv;
315 const fn_inline = llvm.FnInline.Auto;
316
317 return llvm.BuildCall(
318 ofile.builder,
319 fn_ref,
320 args.ptr,
321 @intCast(c_uint, args.len),
322 llvm_cc,
323 fn_inline,
324 c"",
325 ) orelse error.OutOfMemory;
326 }
192 };327 };
193328
194 pub const Const = struct {329 pub const Const = struct {
195 base: Instruction,330 base: Inst,
196 params: Params,331 params: Params,
197332
198 const Params = struct {};333 const Params = struct {};
...@@ -209,7 +344,7 @@ pub const Instruction = struct {...@@ -209,7 +344,7 @@ pub const Instruction = struct {
209 return false;344 return false;
210 }345 }
211346
212 pub fn analyze(self: *const Const, ira: *Analyze) !*Instruction {347 pub fn analyze(self: *const Const, ira: *Analyze) !*Inst {
213 const new_inst = try ira.irb.build(Const, self.base.scope, self.base.span, Params{});348 const new_inst = try ira.irb.build(Const, self.base.scope, self.base.span, Params{});
214 new_inst.val = IrVal{ .KnownValue = self.base.val.KnownValue.getRef() };349 new_inst.val = IrVal{ .KnownValue = self.base.val.KnownValue.getRef() };
215 return new_inst;350 return new_inst;
...@@ -221,11 +356,11 @@ pub const Instruction = struct {...@@ -221,11 +356,11 @@ pub const Instruction = struct {
221 };356 };
222357
223 pub const Return = struct {358 pub const Return = struct {
224 base: Instruction,359 base: Inst,
225 params: Params,360 params: Params,
226361
227 const Params = struct {362 const Params = struct {
228 return_value: *Instruction,363 return_value: *Inst,
229 };364 };
230365
231 const ir_val_init = IrVal.Init.NoReturn;366 const ir_val_init = IrVal.Init.NoReturn;
...@@ -238,7 +373,7 @@ pub const Instruction = struct {...@@ -238,7 +373,7 @@ pub const Instruction = struct {
238 return true;373 return true;
239 }374 }
240375
241 pub fn analyze(self: *const Return, ira: *Analyze) !*Instruction {376 pub fn analyze(self: *const Return, ira: *Analyze) !*Inst {
242 const value = try self.params.return_value.getAsParam();377 const value = try self.params.return_value.getAsParam();
243 const casted_value = try ira.implicitCast(value, ira.explicit_return_type);378 const casted_value = try ira.implicitCast(value, ira.explicit_return_type);
244379
...@@ -247,25 +382,25 @@ pub const Instruction = struct {...@@ -247,25 +382,25 @@ pub const Instruction = struct {
247 return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value });382 return ira.irb.build(Return, self.base.scope, self.base.span, Params{ .return_value = casted_value });
248 }383 }
249384
250 pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) ?llvm.ValueRef {385 pub fn render(self: *Return, ofile: *ObjectFile, fn_val: *Value.Fn) !?llvm.ValueRef {
251 const value = self.params.return_value.llvm_value;386 const value = self.params.return_value.llvm_value;
252 const return_type = self.params.return_value.getKnownType();387 const return_type = self.params.return_value.getKnownType();
253388
254 if (return_type.handleIsPtr()) {389 if (return_type.handleIsPtr()) {
255 @panic("TODO");390 @panic("TODO");
256 } else {391 } else {
257 _ = llvm.BuildRet(ofile.builder, value);392 _ = llvm.BuildRet(ofile.builder, value) orelse return error.OutOfMemory;
258 }393 }
259 return null;394 return null;
260 }395 }
261 };396 };
262397
263 pub const Ref = struct {398 pub const Ref = struct {
264 base: Instruction,399 base: Inst,
265 params: Params,400 params: Params,
266401
267 const Params = struct {402 const Params = struct {
268 target: *Instruction,403 target: *Inst,
269 mut: Type.Pointer.Mut,404 mut: Type.Pointer.Mut,
270 volatility: Type.Pointer.Vol,405 volatility: Type.Pointer.Vol,
271 };406 };
...@@ -278,7 +413,7 @@ pub const Instruction = struct {...@@ -278,7 +413,7 @@ pub const Instruction = struct {
278 return false;413 return false;
279 }414 }
280415
281 pub fn analyze(self: *const Ref, ira: *Analyze) !*Instruction {416 pub async fn analyze(self: *const Ref, ira: *Analyze) !*Inst {
282 const target = try self.params.target.getAsParam();417 const target = try self.params.target.getAsParam();
283418
284 if (ira.getCompTimeValOrNullUndefOk(target)) |val| {419 if (ira.getCompTimeValOrNullUndefOk(target)) |val| {
...@@ -287,7 +422,6 @@ pub const Instruction = struct {...@@ -287,7 +422,6 @@ pub const Instruction = struct {
287 Value.Ptr.Mut.CompTimeConst,422 Value.Ptr.Mut.CompTimeConst,
288 self.params.mut,423 self.params.mut,
289 self.params.volatility,424 self.params.volatility,
290 val.typeof.getAbiAlignment(ira.irb.comp),
291 );425 );
292 }426 }
293427
...@@ -297,14 +431,13 @@ pub const Instruction = struct {...@@ -297,14 +431,13 @@ pub const Instruction = struct {
297 .volatility = self.params.volatility,431 .volatility = self.params.volatility,
298 });432 });
299 const elem_type = target.getKnownType();433 const elem_type = target.getKnownType();
300 const ptr_type = Type.Pointer.get(434 const ptr_type = try await (async Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{
301 ira.irb.comp,435 .child_type = elem_type,
302 elem_type,436 .mut = self.params.mut,
303 self.params.mut,437 .vol = self.params.volatility,
304 self.params.volatility,438 .size = Type.Pointer.Size.One,
305 Type.Pointer.Size.One,439 .alignment = Type.Pointer.Align.Abi,
306 elem_type.getAbiAlignment(ira.irb.comp),440 }) catch unreachable);
307 );
308 // TODO: potentially set the hint that this is a stack pointer. But it might not be - this441 // TODO: potentially set the hint that this is a stack pointer. But it might not be - this
309 // could be a ref of a global, for example442 // could be a ref of a global, for example
310 new_inst.val = IrVal{ .KnownType = &ptr_type.base };443 new_inst.val = IrVal{ .KnownType = &ptr_type.base };
...@@ -313,8 +446,99 @@ pub const Instruction = struct {...@@ -313,8 +446,99 @@ pub const Instruction = struct {
313 }446 }
314 };447 };
315448
449 pub const DeclRef = struct {
450 base: Inst,
451 params: Params,
452
453 const Params = struct {
454 decl: *Decl,
455 lval: LVal,
456 };
457
458 const ir_val_init = IrVal.Init.Unknown;
459
460 pub fn dump(inst: *const DeclRef) void {}
461
462 pub fn hasSideEffects(inst: *const DeclRef) bool {
463 return false;
464 }
465
466 pub async fn analyze(self: *const DeclRef, ira: *Analyze) !*Inst {
467 (await (async ira.irb.comp.resolveDecl(self.params.decl) catch unreachable)) catch |err| switch (err) {
468 error.OutOfMemory => return error.OutOfMemory,
469 else => return error.SemanticAnalysisFailed,
470 };
471 switch (self.params.decl.id) {
472 Decl.Id.CompTime => unreachable,
473 Decl.Id.Var => return error.Unimplemented,
474 Decl.Id.Fn => {
475 const fn_decl = @fieldParentPtr(Decl.Fn, "base", self.params.decl);
476 const decl_val = switch (fn_decl.value) {
477 Decl.Fn.Val.Unresolved => unreachable,
478 Decl.Fn.Val.Fn => |fn_val| &fn_val.base,
479 Decl.Fn.Val.FnProto => |fn_proto| &fn_proto.base,
480 };
481 switch (self.params.lval) {
482 LVal.None => {
483 return ira.irb.buildConstValue(self.base.scope, self.base.span, decl_val);
484 },
485 LVal.Ptr => return error.Unimplemented,
486 }
487 },
488 }
489 }
490 };
491
492 pub const PtrType = struct {
493 base: Inst,
494 params: Params,
495
496 const Params = struct {
497 child_type: *Inst,
498 mut: Type.Pointer.Mut,
499 vol: Type.Pointer.Vol,
500 size: Type.Pointer.Size,
501 alignment: ?*Inst,
502 };
503
504 const ir_val_init = IrVal.Init.Unknown;
505
506 pub fn dump(inst: *const PtrType) void {}
507
508 pub fn hasSideEffects(inst: *const PtrType) bool {
509 return false;
510 }
511
512 pub async fn analyze(self: *const PtrType, ira: *Analyze) !*Inst {
513 const child_type = try self.params.child_type.getAsConstType(ira);
514 // if (child_type->id == TypeTableEntryIdUnreachable) {
515 // ir_add_error(ira, &instruction->base, buf_sprintf("pointer to noreturn not allowed"));
516 // return ira->codegen->builtin_types.entry_invalid;
517 // } else if (child_type->id == TypeTableEntryIdOpaque && instruction->ptr_len == PtrLenUnknown) {
518 // ir_add_error(ira, &instruction->base, buf_sprintf("unknown-length pointer to opaque"));
519 // return ira->codegen->builtin_types.entry_invalid;
520 // }
521 const alignment = if (self.params.alignment) |align_inst| blk: {
522 const amt = try align_inst.getAsConstAlign(ira);
523 break :blk Type.Pointer.Align{ .Override = amt };
524 } else blk: {
525 break :blk Type.Pointer.Align{ .Abi = {} };
526 };
527 const ptr_type = try await (async Type.Pointer.get(ira.irb.comp, Type.Pointer.Key{
528 .child_type = child_type,
529 .mut = self.params.mut,
530 .vol = self.params.vol,
531 .size = self.params.size,
532 .alignment = alignment,
533 }) catch unreachable);
534 ptr_type.base.base.deref(ira.irb.comp);
535
536 return ira.irb.buildConstValue(self.base.scope, self.base.span, &ptr_type.base.base);
537 }
538 };
539
316 pub const DeclVar = struct {540 pub const DeclVar = struct {
317 base: Instruction,541 base: Inst,
318 params: Params,542 params: Params,
319543
320 const Params = struct {544 const Params = struct {
...@@ -329,39 +553,46 @@ pub const Instruction = struct {...@@ -329,39 +553,46 @@ pub const Instruction = struct {
329 return true;553 return true;
330 }554 }
331555
332 pub fn analyze(self: *const DeclVar, ira: *Analyze) !*Instruction {556 pub fn analyze(self: *const DeclVar, ira: *Analyze) !*Inst {
333 return error.Unimplemented; // TODO557 return error.Unimplemented; // TODO
334 }558 }
335 };559 };
336560
337 pub const CheckVoidStmt = struct {561 pub const CheckVoidStmt = struct {
338 base: Instruction,562 base: Inst,
339 params: Params,563 params: Params,
340564
341 const Params = struct {565 const Params = struct {
342 target: *Instruction,566 target: *Inst,
343 };567 };
344568
345 const ir_val_init = IrVal.Init.Unknown;569 const ir_val_init = IrVal.Init.Unknown;
346570
347 pub fn dump(inst: *const CheckVoidStmt) void {}571 pub fn dump(self: *const CheckVoidStmt) void {
572 std.debug.warn("#{}", self.params.target.debug_id);
573 }
348574
349 pub fn hasSideEffects(inst: *const CheckVoidStmt) bool {575 pub fn hasSideEffects(inst: *const CheckVoidStmt) bool {
350 return true;576 return true;
351 }577 }
352578
353 pub fn analyze(self: *const CheckVoidStmt, ira: *Analyze) !*Instruction {579 pub fn analyze(self: *const CheckVoidStmt, ira: *Analyze) !*Inst {
354 return error.Unimplemented; // TODO580 const target = try self.params.target.getAsParam();
581 if (target.getKnownType().id != Type.Id.Void) {
582 try ira.addCompileError(self.base.span, "expression value is ignored");
583 return error.SemanticAnalysisFailed;
584 }
585 return ira.irb.buildConstVoid(self.base.scope, self.base.span, true);
355 }586 }
356 };587 };
357588
358 pub const Phi = struct {589 pub const Phi = struct {
359 base: Instruction,590 base: Inst,
360 params: Params,591 params: Params,
361592
362 const Params = struct {593 const Params = struct {
363 incoming_blocks: []*BasicBlock,594 incoming_blocks: []*BasicBlock,
364 incoming_values: []*Instruction,595 incoming_values: []*Inst,
365 };596 };
366597
367 const ir_val_init = IrVal.Init.Unknown;598 const ir_val_init = IrVal.Init.Unknown;
...@@ -372,18 +603,18 @@ pub const Instruction = struct {...@@ -372,18 +603,18 @@ pub const Instruction = struct {
372 return false;603 return false;
373 }604 }
374605
375 pub fn analyze(self: *const Phi, ira: *Analyze) !*Instruction {606 pub fn analyze(self: *const Phi, ira: *Analyze) !*Inst {
376 return error.Unimplemented; // TODO607 return error.Unimplemented; // TODO
377 }608 }
378 };609 };
379610
380 pub const Br = struct {611 pub const Br = struct {
381 base: Instruction,612 base: Inst,
382 params: Params,613 params: Params,
383614
384 const Params = struct {615 const Params = struct {
385 dest_block: *BasicBlock,616 dest_block: *BasicBlock,
386 is_comptime: *Instruction,617 is_comptime: *Inst,
387 };618 };
388619
389 const ir_val_init = IrVal.Init.NoReturn;620 const ir_val_init = IrVal.Init.NoReturn;
...@@ -394,17 +625,41 @@ pub const Instruction = struct {...@@ -394,17 +625,41 @@ pub const Instruction = struct {
394 return true;625 return true;
395 }626 }
396627
397 pub fn analyze(self: *const Br, ira: *Analyze) !*Instruction {628 pub fn analyze(self: *const Br, ira: *Analyze) !*Inst {
629 return error.Unimplemented; // TODO
630 }
631 };
632
633 pub const CondBr = struct {
634 base: Inst,
635 params: Params,
636
637 const Params = struct {
638 condition: *Inst,
639 then_block: *BasicBlock,
640 else_block: *BasicBlock,
641 is_comptime: *Inst,
642 };
643
644 const ir_val_init = IrVal.Init.NoReturn;
645
646 pub fn dump(inst: *const CondBr) void {}
647
648 pub fn hasSideEffects(inst: *const CondBr) bool {
649 return true;
650 }
651
652 pub fn analyze(self: *const CondBr, ira: *Analyze) !*Inst {
398 return error.Unimplemented; // TODO653 return error.Unimplemented; // TODO
399 }654 }
400 };655 };
401656
402 pub const AddImplicitReturnType = struct {657 pub const AddImplicitReturnType = struct {
403 base: Instruction,658 base: Inst,
404 params: Params,659 params: Params,
405660
406 pub const Params = struct {661 pub const Params = struct {
407 target: *Instruction,662 target: *Inst,
408 };663 };
409664
410 const ir_val_init = IrVal.Init.Unknown;665 const ir_val_init = IrVal.Init.Unknown;
...@@ -417,12 +672,117 @@ pub const Instruction = struct {...@@ -417,12 +672,117 @@ pub const Instruction = struct {
417 return true;672 return true;
418 }673 }
419674
420 pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Instruction {675 pub fn analyze(self: *const AddImplicitReturnType, ira: *Analyze) !*Inst {
421 const target = try self.params.target.getAsParam();676 const target = try self.params.target.getAsParam();
422 try ira.src_implicit_return_type_list.append(target);677 try ira.src_implicit_return_type_list.append(target);
423 return ira.irb.buildConstVoid(self.base.scope, self.base.span, true);678 return ira.irb.buildConstVoid(self.base.scope, self.base.span, true);
424 }679 }
425 };680 };
681
682 pub const TestErr = struct {
683 base: Inst,
684 params: Params,
685
686 pub const Params = struct {
687 target: *Inst,
688 };
689
690 const ir_val_init = IrVal.Init.Unknown;
691
692 pub fn dump(inst: *const TestErr) void {
693 std.debug.warn("#{}", inst.params.target.debug_id);
694 }
695
696 pub fn hasSideEffects(inst: *const TestErr) bool {
697 return false;
698 }
699
700 pub fn analyze(self: *const TestErr, ira: *Analyze) !*Inst {
701 const target = try self.params.target.getAsParam();
702 const target_type = target.getKnownType();
703 switch (target_type.id) {
704 Type.Id.ErrorUnion => {
705 return error.Unimplemented;
706 // if (instr_is_comptime(value)) {
707 // ConstExprValue *err_union_val = ir_resolve_const(ira, value, UndefBad);
708 // if (!err_union_val)
709 // return ira->codegen->builtin_types.entry_invalid;
710
711 // if (err_union_val->special != ConstValSpecialRuntime) {
712 // ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
713 // out_val->data.x_bool = (err_union_val->data.x_err_union.err != nullptr);
714 // return ira->codegen->builtin_types.entry_bool;
715 // }
716 // }
717
718 // TypeTableEntry *err_set_type = type_entry->data.error_union.err_set_type;
719 // if (!resolve_inferred_error_set(ira->codegen, err_set_type, instruction->base.source_node)) {
720 // return ira->codegen->builtin_types.entry_invalid;
721 // }
722 // if (!type_is_global_error_set(err_set_type) &&
723 // err_set_type->data.error_set.err_count == 0)
724 // {
725 // assert(err_set_type->data.error_set.infer_fn == nullptr);
726 // ConstExprValue *out_val = ir_build_const_from(ira, &instruction->base);
727 // out_val->data.x_bool = false;
728 // return ira->codegen->builtin_types.entry_bool;
729 // }
730
731 // ir_build_test_err_from(&ira->new_irb, &instruction->base, value);
732 // return ira->codegen->builtin_types.entry_bool;
733 },
734 Type.Id.ErrorSet => {
735 return ira.irb.buildConstBool(self.base.scope, self.base.span, true);
736 },
737 else => {
738 return ira.irb.buildConstBool(self.base.scope, self.base.span, false);
739 },
740 }
741 }
742 };
743
744 pub const TestCompTime = struct {
745 base: Inst,
746 params: Params,
747
748 pub const Params = struct {
749 target: *Inst,
750 };
751
752 const ir_val_init = IrVal.Init.Unknown;
753
754 pub fn dump(inst: *const TestCompTime) void {
755 std.debug.warn("#{}", inst.params.target.debug_id);
756 }
757
758 pub fn hasSideEffects(inst: *const TestCompTime) bool {
759 return false;
760 }
761
762 pub fn analyze(self: *const TestCompTime, ira: *Analyze) !*Inst {
763 const target = try self.params.target.getAsParam();
764 return ira.irb.buildConstBool(self.base.scope, self.base.span, target.isCompTime());
765 }
766 };
767
768 pub const SaveErrRetAddr = struct {
769 base: Inst,
770 params: Params,
771
772 const Params = struct {};
773
774 const ir_val_init = IrVal.Init.Unknown;
775
776 pub fn dump(inst: *const SaveErrRetAddr) void {}
777
778 pub fn hasSideEffects(inst: *const SaveErrRetAddr) bool {
779 return true;
780 }
781
782 pub fn analyze(self: *const SaveErrRetAddr, ira: *Analyze) !*Inst {
783 return ira.irb.build(Inst.SaveErrRetAddr, self.base.scope, self.base.span, Params{});
784 }
785 };
426};786};
427787
428pub const Variable = struct {788pub const Variable = struct {
...@@ -434,8 +794,8 @@ pub const BasicBlock = struct {...@@ -434,8 +794,8 @@ pub const BasicBlock = struct {
434 name_hint: [*]const u8, // must be a C string literal794 name_hint: [*]const u8, // must be a C string literal
435 debug_id: usize,795 debug_id: usize,
436 scope: *Scope,796 scope: *Scope,
437 instruction_list: std.ArrayList(*Instruction),797 instruction_list: std.ArrayList(*Inst),
438 ref_instruction: ?*Instruction,798 ref_instruction: ?*Inst,
439799
440 /// for codegen800 /// for codegen
441 llvm_block: llvm.BasicBlockRef,801 llvm_block: llvm.BasicBlockRef,
...@@ -447,7 +807,7 @@ pub const BasicBlock = struct {...@@ -447,7 +807,7 @@ pub const BasicBlock = struct {
447 /// the basic block that this one derives from in analysis807 /// the basic block that this one derives from in analysis
448 parent: ?*BasicBlock,808 parent: ?*BasicBlock,
449809
450 pub fn ref(self: *BasicBlock) void {810 pub fn ref(self: *BasicBlock, builder: *Builder) void {
451 self.ref_count += 1;811 self.ref_count += 1;
452 }812 }
453813
...@@ -482,6 +842,33 @@ pub const Code = struct {...@@ -482,6 +842,33 @@ pub const Code = struct {
482 }842 }
483 }843 }
484 }844 }
845
846 /// returns a ref-incremented value, or adds a compile error
847 pub fn getCompTimeResult(self: *Code, comp: *Compilation) !*Value {
848 const bb = self.basic_block_list.at(0);
849 for (bb.instruction_list.toSliceConst()) |inst| {
850 if (inst.cast(Inst.Return)) |ret_inst| {
851 const ret_value = ret_inst.params.return_value;
852 if (ret_value.isCompTime()) {
853 return ret_value.val.KnownValue.getRef();
854 }
855 try comp.addCompileError(
856 ret_value.scope.findRoot(),
857 ret_value.span,
858 "unable to evaluate constant expression",
859 );
860 return error.SemanticAnalysisFailed;
861 } else if (inst.hasSideEffects()) {
862 try comp.addCompileError(
863 inst.scope.findRoot(),
864 inst.span,
865 "unable to evaluate constant expression",
866 );
867 return error.SemanticAnalysisFailed;
868 }
869 }
870 unreachable;
871 }
485};872};
486873
487pub const Builder = struct {874pub const Builder = struct {
...@@ -489,12 +876,14 @@ pub const Builder = struct {...@@ -489,12 +876,14 @@ pub const Builder = struct {
489 code: *Code,876 code: *Code,
490 current_basic_block: *BasicBlock,877 current_basic_block: *BasicBlock,
491 next_debug_id: usize,878 next_debug_id: usize,
492 parsed_file: *ParsedFile,879 root_scope: *Scope.Root,
493 is_comptime: bool,880 is_comptime: bool,
881 is_async: bool,
882 begin_scope: ?*Scope,
494883
495 pub const Error = Analyze.Error;884 pub const Error = Analyze.Error;
496885
497 pub fn init(comp: *Compilation, parsed_file: *ParsedFile) !Builder {886 pub fn init(comp: *Compilation, root_scope: *Scope.Root, begin_scope: ?*Scope) !Builder {
498 const code = try comp.gpa().create(Code{887 const code = try comp.gpa().create(Code{
499 .basic_block_list = undefined,888 .basic_block_list = undefined,
500 .arena = std.heap.ArenaAllocator.init(comp.gpa()),889 .arena = std.heap.ArenaAllocator.init(comp.gpa()),
...@@ -505,11 +894,13 @@ pub const Builder = struct {...@@ -505,11 +894,13 @@ pub const Builder = struct {
505894
506 return Builder{895 return Builder{
507 .comp = comp,896 .comp = comp,
508 .parsed_file = parsed_file,897 .root_scope = root_scope,
509 .current_basic_block = undefined,898 .current_basic_block = undefined,
510 .code = code,899 .code = code,
511 .next_debug_id = 0,900 .next_debug_id = 0,
512 .is_comptime = false,901 .is_comptime = false,
902 .is_async = false,
903 .begin_scope = begin_scope,
513 };904 };
514 }905 }
515906
...@@ -529,7 +920,7 @@ pub const Builder = struct {...@@ -529,7 +920,7 @@ pub const Builder = struct {
529 .name_hint = name_hint,920 .name_hint = name_hint,
530 .debug_id = self.next_debug_id,921 .debug_id = self.next_debug_id,
531 .scope = scope,922 .scope = scope,
532 .instruction_list = std.ArrayList(*Instruction).init(self.arena()),923 .instruction_list = std.ArrayList(*Inst).init(self.arena()),
533 .child = null,924 .child = null,
534 .parent = null,925 .parent = null,
535 .ref_instruction = null,926 .ref_instruction = null,
...@@ -549,69 +940,210 @@ pub const Builder = struct {...@@ -549,69 +940,210 @@ pub const Builder = struct {
549 self.current_basic_block = basic_block;940 self.current_basic_block = basic_block;
550 }941 }
551942
552 pub fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Instruction {943 pub async fn genNode(irb: *Builder, node: *ast.Node, scope: *Scope, lval: LVal) Error!*Inst {
553 switch (node.id) {944 switch (node.id) {
554 ast.Node.Id.Root => unreachable,945 ast.Node.Id.Root => unreachable,
555 ast.Node.Id.Use => unreachable,946 ast.Node.Id.Use => unreachable,
556 ast.Node.Id.TestDecl => unreachable,947 ast.Node.Id.TestDecl => unreachable,
557 ast.Node.Id.VarDecl => @panic("TODO"),948 ast.Node.Id.VarDecl => return error.Unimplemented,
558 ast.Node.Id.Defer => @panic("TODO"),949 ast.Node.Id.Defer => return error.Unimplemented,
559 ast.Node.Id.InfixOp => @panic("TODO"),950 ast.Node.Id.InfixOp => return error.Unimplemented,
560 ast.Node.Id.PrefixOp => @panic("TODO"),951 ast.Node.Id.PrefixOp => {
561 ast.Node.Id.SuffixOp => @panic("TODO"),952 const prefix_op = @fieldParentPtr(ast.Node.PrefixOp, "base", node);
562 ast.Node.Id.Switch => @panic("TODO"),953 switch (prefix_op.op) {
563 ast.Node.Id.While => @panic("TODO"),954 ast.Node.PrefixOp.Op.AddressOf => return error.Unimplemented,
564 ast.Node.Id.For => @panic("TODO"),955 ast.Node.PrefixOp.Op.ArrayType => |n| return error.Unimplemented,
565 ast.Node.Id.If => @panic("TODO"),956 ast.Node.PrefixOp.Op.Await => return error.Unimplemented,
566 ast.Node.Id.ControlFlowExpression => return error.Unimplemented,957 ast.Node.PrefixOp.Op.BitNot => return error.Unimplemented,
567 ast.Node.Id.Suspend => @panic("TODO"),958 ast.Node.PrefixOp.Op.BoolNot => return error.Unimplemented,
568 ast.Node.Id.VarType => @panic("TODO"),959 ast.Node.PrefixOp.Op.Cancel => return error.Unimplemented,
569 ast.Node.Id.ErrorType => @panic("TODO"),960 ast.Node.PrefixOp.Op.OptionalType => return error.Unimplemented,
570 ast.Node.Id.FnProto => @panic("TODO"),961 ast.Node.PrefixOp.Op.Negation => return error.Unimplemented,
571 ast.Node.Id.PromiseType => @panic("TODO"),962 ast.Node.PrefixOp.Op.NegationWrap => return error.Unimplemented,
572 ast.Node.Id.IntegerLiteral => @panic("TODO"),963 ast.Node.PrefixOp.Op.Resume => return error.Unimplemented,
573 ast.Node.Id.FloatLiteral => @panic("TODO"),964 ast.Node.PrefixOp.Op.PtrType => |ptr_info| {
574 ast.Node.Id.StringLiteral => @panic("TODO"),965 const inst = try await (async irb.genPtrType(prefix_op, ptr_info, scope) catch unreachable);
575 ast.Node.Id.MultilineStringLiteral => @panic("TODO"),966 return irb.lvalWrap(scope, inst, lval);
576 ast.Node.Id.CharLiteral => @panic("TODO"),967 },
577 ast.Node.Id.BoolLiteral => @panic("TODO"),968 ast.Node.PrefixOp.Op.SliceType => |ptr_info| return error.Unimplemented,
578 ast.Node.Id.NullLiteral => @panic("TODO"),969 ast.Node.PrefixOp.Op.Try => return error.Unimplemented,
579 ast.Node.Id.UndefinedLiteral => @panic("TODO"),970 }
580 ast.Node.Id.ThisLiteral => @panic("TODO"),971 },
581 ast.Node.Id.Unreachable => @panic("TODO"),972 ast.Node.Id.SuffixOp => {
582 ast.Node.Id.Identifier => @panic("TODO"),973 const suffix_op = @fieldParentPtr(ast.Node.SuffixOp, "base", node);
974 switch (suffix_op.op) {
975 @TagType(ast.Node.SuffixOp.Op).Call => |*call| {
976 const inst = try await (async irb.genCall(suffix_op, call, scope) catch unreachable);
977 return irb.lvalWrap(scope, inst, lval);
978 },
979 @TagType(ast.Node.SuffixOp.Op).ArrayAccess => |n| return error.Unimplemented,
980 @TagType(ast.Node.SuffixOp.Op).Slice => |slice| return error.Unimplemented,
981 @TagType(ast.Node.SuffixOp.Op).ArrayInitializer => |init_list| return error.Unimplemented,
982 @TagType(ast.Node.SuffixOp.Op).StructInitializer => |init_list| return error.Unimplemented,
983 @TagType(ast.Node.SuffixOp.Op).Deref => return error.Unimplemented,
984 @TagType(ast.Node.SuffixOp.Op).UnwrapOptional => return error.Unimplemented,
985 }
986 },
987 ast.Node.Id.Switch => return error.Unimplemented,
988 ast.Node.Id.While => return error.Unimplemented,
989 ast.Node.Id.For => return error.Unimplemented,
990 ast.Node.Id.If => return error.Unimplemented,
991 ast.Node.Id.ControlFlowExpression => {
992 const control_flow_expr = @fieldParentPtr(ast.Node.ControlFlowExpression, "base", node);
993 return await (async irb.genControlFlowExpr(control_flow_expr, scope, lval) catch unreachable);
994 },
995 ast.Node.Id.Suspend => return error.Unimplemented,
996 ast.Node.Id.VarType => return error.Unimplemented,
997 ast.Node.Id.ErrorType => return error.Unimplemented,
998 ast.Node.Id.FnProto => return error.Unimplemented,
999 ast.Node.Id.PromiseType => return error.Unimplemented,
1000 ast.Node.Id.IntegerLiteral => {
1001 const int_lit = @fieldParentPtr(ast.Node.IntegerLiteral, "base", node);
1002 return irb.lvalWrap(scope, try irb.genIntLit(int_lit, scope), lval);
1003 },
1004 ast.Node.Id.FloatLiteral => return error.Unimplemented,
1005 ast.Node.Id.StringLiteral => {
1006 const str_lit = @fieldParentPtr(ast.Node.StringLiteral, "base", node);
1007 const inst = try await (async irb.genStrLit(str_lit, scope) catch unreachable);
1008 return irb.lvalWrap(scope, inst, lval);
1009 },
1010 ast.Node.Id.MultilineStringLiteral => return error.Unimplemented,
1011 ast.Node.Id.CharLiteral => return error.Unimplemented,
1012 ast.Node.Id.BoolLiteral => return error.Unimplemented,
1013 ast.Node.Id.NullLiteral => return error.Unimplemented,
1014 ast.Node.Id.UndefinedLiteral => return error.Unimplemented,
1015 ast.Node.Id.ThisLiteral => return error.Unimplemented,
1016 ast.Node.Id.Unreachable => return error.Unimplemented,
1017 ast.Node.Id.Identifier => {
1018 const identifier = @fieldParentPtr(ast.Node.Identifier, "base", node);
1019 return await (async irb.genIdentifier(identifier, scope, lval) catch unreachable);
1020 },
583 ast.Node.Id.GroupedExpression => {1021 ast.Node.Id.GroupedExpression => {
584 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node);1022 const grouped_expr = @fieldParentPtr(ast.Node.GroupedExpression, "base", node);
585 return irb.genNode(grouped_expr.expr, scope, lval);1023 return await (async irb.genNode(grouped_expr.expr, scope, lval) catch unreachable);
586 },1024 },
587 ast.Node.Id.BuiltinCall => @panic("TODO"),1025 ast.Node.Id.BuiltinCall => return error.Unimplemented,
588 ast.Node.Id.ErrorSetDecl => @panic("TODO"),1026 ast.Node.Id.ErrorSetDecl => return error.Unimplemented,
589 ast.Node.Id.ContainerDecl => @panic("TODO"),1027 ast.Node.Id.ContainerDecl => return error.Unimplemented,
590 ast.Node.Id.Asm => @panic("TODO"),1028 ast.Node.Id.Asm => return error.Unimplemented,
591 ast.Node.Id.Comptime => @panic("TODO"),1029 ast.Node.Id.Comptime => return error.Unimplemented,
592 ast.Node.Id.Block => {1030 ast.Node.Id.Block => {
593 const block = @fieldParentPtr(ast.Node.Block, "base", node);1031 const block = @fieldParentPtr(ast.Node.Block, "base", node);
594 return irb.lvalWrap(scope, try irb.genBlock(block, scope), lval);1032 const inst = try await (async irb.genBlock(block, scope) catch unreachable);
1033 return irb.lvalWrap(scope, inst, lval);
595 },1034 },
596 ast.Node.Id.DocComment => @panic("TODO"),1035 ast.Node.Id.DocComment => return error.Unimplemented,
597 ast.Node.Id.SwitchCase => @panic("TODO"),1036 ast.Node.Id.SwitchCase => return error.Unimplemented,
598 ast.Node.Id.SwitchElse => @panic("TODO"),1037 ast.Node.Id.SwitchElse => return error.Unimplemented,
599 ast.Node.Id.Else => @panic("TODO"),1038 ast.Node.Id.Else => return error.Unimplemented,
600 ast.Node.Id.Payload => @panic("TODO"),1039 ast.Node.Id.Payload => return error.Unimplemented,
601 ast.Node.Id.PointerPayload => @panic("TODO"),1040 ast.Node.Id.PointerPayload => return error.Unimplemented,
602 ast.Node.Id.PointerIndexPayload => @panic("TODO"),1041 ast.Node.Id.PointerIndexPayload => return error.Unimplemented,
603 ast.Node.Id.StructField => @panic("TODO"),1042 ast.Node.Id.StructField => return error.Unimplemented,
604 ast.Node.Id.UnionTag => @panic("TODO"),1043 ast.Node.Id.UnionTag => return error.Unimplemented,
605 ast.Node.Id.EnumTag => @panic("TODO"),1044 ast.Node.Id.EnumTag => return error.Unimplemented,
606 ast.Node.Id.ErrorTag => @panic("TODO"),1045 ast.Node.Id.ErrorTag => return error.Unimplemented,
607 ast.Node.Id.AsmInput => @panic("TODO"),1046 ast.Node.Id.AsmInput => return error.Unimplemented,
608 ast.Node.Id.AsmOutput => @panic("TODO"),1047 ast.Node.Id.AsmOutput => return error.Unimplemented,
609 ast.Node.Id.AsyncAttribute => @panic("TODO"),1048 ast.Node.Id.AsyncAttribute => return error.Unimplemented,
610 ast.Node.Id.ParamDecl => @panic("TODO"),1049 ast.Node.Id.ParamDecl => return error.Unimplemented,
611 ast.Node.Id.FieldInitializer => @panic("TODO"),1050 ast.Node.Id.FieldInitializer => return error.Unimplemented,
612 }1051 }
613 }1052 }
6141053
1054 async fn genCall(irb: *Builder, suffix_op: *ast.Node.SuffixOp, call: *ast.Node.SuffixOp.Op.Call, scope: *Scope) !*Inst {
1055 const fn_ref = try await (async irb.genNode(suffix_op.lhs, scope, LVal.None) catch unreachable);
1056
1057 const args = try irb.arena().alloc(*Inst, call.params.len);
1058 var it = call.params.iterator(0);
1059 var i: usize = 0;
1060 while (it.next()) |arg_node_ptr| : (i += 1) {
1061 args[i] = try await (async irb.genNode(arg_node_ptr.*, scope, LVal.None) catch unreachable);
1062 }
1063
1064 //bool is_async = node->data.fn_call_expr.is_async;
1065 //IrInstruction *async_allocator = nullptr;
1066 //if (is_async) {
1067 // if (node->data.fn_call_expr.async_allocator) {
1068 // async_allocator = ir_gen_node(irb, node->data.fn_call_expr.async_allocator, scope);
1069 // if (async_allocator == irb->codegen->invalid_instruction)
1070 // return async_allocator;
1071 // }
1072 //}
1073
1074 return irb.build(Inst.Call, scope, Span.token(suffix_op.rtoken), Inst.Call.Params{
1075 .fn_ref = fn_ref,
1076 .args = args,
1077 });
1078 //IrInstruction *fn_call = ir_build_call(irb, scope, node, nullptr, fn_ref, arg_count, args, false, FnInlineAuto, is_async, async_allocator, nullptr);
1079 //return ir_lval_wrap(irb, scope, fn_call, lval);
1080 }
1081
1082 async fn genPtrType(
1083 irb: *Builder,
1084 prefix_op: *ast.Node.PrefixOp,
1085 ptr_info: ast.Node.PrefixOp.PtrInfo,
1086 scope: *Scope,
1087 ) !*Inst {
1088 // TODO port more logic
1089
1090 //assert(node->type == NodeTypePointerType);
1091 //PtrLen ptr_len = (node->data.pointer_type.star_token->id == TokenIdStar ||
1092 // node->data.pointer_type.star_token->id == TokenIdStarStar) ? PtrLenSingle : PtrLenUnknown;
1093 //bool is_const = node->data.pointer_type.is_const;
1094 //bool is_volatile = node->data.pointer_type.is_volatile;
1095 //AstNode *expr_node = node->data.pointer_type.op_expr;
1096 //AstNode *align_expr = node->data.pointer_type.align_expr;
1097
1098 //IrInstruction *align_value;
1099 //if (align_expr != nullptr) {
1100 // align_value = ir_gen_node(irb, align_expr, scope);
1101 // if (align_value == irb->codegen->invalid_instruction)
1102 // return align_value;
1103 //} else {
1104 // align_value = nullptr;
1105 //}
1106 const child_type = try await (async irb.genNode(prefix_op.rhs, scope, LVal.None) catch unreachable);
1107
1108 //uint32_t bit_offset_start = 0;
1109 //if (node->data.pointer_type.bit_offset_start != nullptr) {
1110 // if (!bigint_fits_in_bits(node->data.pointer_type.bit_offset_start, 32, false)) {
1111 // Buf *val_buf = buf_alloc();
1112 // bigint_append_buf(val_buf, node->data.pointer_type.bit_offset_start, 10);
1113 // exec_add_error_node(irb->codegen, irb->exec, node,
1114 // buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf)));
1115 // return irb->codegen->invalid_instruction;
1116 // }
1117 // bit_offset_start = bigint_as_unsigned(node->data.pointer_type.bit_offset_start);
1118 //}
1119
1120 //uint32_t bit_offset_end = 0;
1121 //if (node->data.pointer_type.bit_offset_end != nullptr) {
1122 // if (!bigint_fits_in_bits(node->data.pointer_type.bit_offset_end, 32, false)) {
1123 // Buf *val_buf = buf_alloc();
1124 // bigint_append_buf(val_buf, node->data.pointer_type.bit_offset_end, 10);
1125 // exec_add_error_node(irb->codegen, irb->exec, node,
1126 // buf_sprintf("value %s too large for u32 bit offset", buf_ptr(val_buf)));
1127 // return irb->codegen->invalid_instruction;
1128 // }
1129 // bit_offset_end = bigint_as_unsigned(node->data.pointer_type.bit_offset_end);
1130 //}
1131
1132 //if ((bit_offset_start != 0 || bit_offset_end != 0) && bit_offset_start >= bit_offset_end) {
1133 // exec_add_error_node(irb->codegen, irb->exec, node,
1134 // buf_sprintf("bit offset start must be less than bit offset end"));
1135 // return irb->codegen->invalid_instruction;
1136 //}
1137
1138 return irb.build(Inst.PtrType, scope, Span.node(&prefix_op.base), Inst.PtrType.Params{
1139 .child_type = child_type,
1140 .mut = Type.Pointer.Mut.Mut,
1141 .vol = Type.Pointer.Vol.Non,
1142 .size = Type.Pointer.Size.Many,
1143 .alignment = null,
1144 });
1145 }
1146
615 fn isCompTime(irb: *Builder, target_scope: *Scope) bool {1147 fn isCompTime(irb: *Builder, target_scope: *Scope) bool {
616 if (irb.is_comptime)1148 if (irb.is_comptime)
617 return true;1149 return true;
...@@ -622,15 +1154,105 @@ pub const Builder = struct {...@@ -622,15 +1154,105 @@ pub const Builder = struct {
622 Scope.Id.CompTime => return true,1154 Scope.Id.CompTime => return true,
623 Scope.Id.FnDef => return false,1155 Scope.Id.FnDef => return false,
624 Scope.Id.Decls => unreachable,1156 Scope.Id.Decls => unreachable,
1157 Scope.Id.Root => unreachable,
625 Scope.Id.Block,1158 Scope.Id.Block,
626 Scope.Id.Defer,1159 Scope.Id.Defer,
627 Scope.Id.DeferExpr,1160 Scope.Id.DeferExpr,
628 => scope = scope.parent orelse return false,1161 => scope = scope.parent.?,
629 }1162 }
630 }1163 }
631 }1164 }
6321165
633 pub fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Instruction {1166 pub fn genIntLit(irb: *Builder, int_lit: *ast.Node.IntegerLiteral, scope: *Scope) !*Inst {
1167 const int_token = irb.root_scope.tree.tokenSlice(int_lit.token);
1168
1169 var base: u8 = undefined;
1170 var rest: []const u8 = undefined;
1171 if (int_token.len >= 3 and int_token[0] == '0') {
1172 base = switch (int_token[1]) {
1173 'b' => u8(2),
1174 'o' => u8(8),
1175 'x' => u8(16),
1176 else => unreachable,
1177 };
1178 rest = int_token[2..];
1179 } else {
1180 base = 10;
1181 rest = int_token;
1182 }
1183
1184 const comptime_int_type = Type.ComptimeInt.get(irb.comp);
1185 defer comptime_int_type.base.base.deref(irb.comp);
1186
1187 const int_val = Value.Int.createFromString(
1188 irb.comp,
1189 &comptime_int_type.base,
1190 base,
1191 rest,
1192 ) catch |err| switch (err) {
1193 error.OutOfMemory => return error.OutOfMemory,
1194 error.InvalidBase => unreachable,
1195 error.InvalidCharForDigit => unreachable,
1196 error.DigitTooLargeForBase => unreachable,
1197 };
1198 errdefer int_val.base.deref(irb.comp);
1199
1200 const inst = try irb.build(Inst.Const, scope, Span.token(int_lit.token), Inst.Const.Params{});
1201 inst.val = IrVal{ .KnownValue = &int_val.base };
1202 return inst;
1203 }
1204
1205 pub async fn genStrLit(irb: *Builder, str_lit: *ast.Node.StringLiteral, scope: *Scope) !*Inst {
1206 const str_token = irb.root_scope.tree.tokenSlice(str_lit.token);
1207 const src_span = Span.token(str_lit.token);
1208
1209 var bad_index: usize = undefined;
1210 var buf = std.zig.parseStringLiteral(irb.comp.gpa(), str_token, &bad_index) catch |err| switch (err) {
1211 error.OutOfMemory => return error.OutOfMemory,
1212 error.InvalidCharacter => {
1213 try irb.comp.addCompileError(
1214 irb.root_scope,
1215 src_span,
1216 "invalid character in string literal: '{c}'",
1217 str_token[bad_index],
1218 );
1219 return error.SemanticAnalysisFailed;
1220 },
1221 };
1222 var buf_cleaned = false;
1223 errdefer if (!buf_cleaned) irb.comp.gpa().free(buf);
1224
1225 if (str_token[0] == 'c') {
1226 // first we add a null
1227 buf = try irb.comp.gpa().realloc(u8, buf, buf.len + 1);
1228 buf[buf.len - 1] = 0;
1229
1230 // next make an array value
1231 const array_val = try await (async Value.Array.createOwnedBuffer(irb.comp, buf) catch unreachable);
1232 buf_cleaned = true;
1233 defer array_val.base.deref(irb.comp);
1234
1235 // then make a pointer value pointing at the first element
1236 const ptr_val = try await (async Value.Ptr.createArrayElemPtr(
1237 irb.comp,
1238 array_val,
1239 Type.Pointer.Mut.Const,
1240 Type.Pointer.Size.Many,
1241 0,
1242 ) catch unreachable);
1243 defer ptr_val.base.deref(irb.comp);
1244
1245 return irb.buildConstValue(scope, src_span, &ptr_val.base);
1246 } else {
1247 const array_val = try await (async Value.Array.createOwnedBuffer(irb.comp, buf) catch unreachable);
1248 buf_cleaned = true;
1249 defer array_val.base.deref(irb.comp);
1250
1251 return irb.buildConstValue(scope, src_span, &array_val.base);
1252 }
1253 }
1254
1255 pub async fn genBlock(irb: *Builder, block: *ast.Node.Block, parent_scope: *Scope) !*Inst {
634 const block_scope = try Scope.Block.create(irb.comp, parent_scope);1256 const block_scope = try Scope.Block.create(irb.comp, parent_scope);
6351257
636 const outer_block_scope = &block_scope.base;1258 const outer_block_scope = &block_scope.base;
...@@ -648,7 +1270,7 @@ pub const Builder = struct {...@@ -648,7 +1270,7 @@ pub const Builder = struct {
648 }1270 }
6491271
650 if (block.label) |label| {1272 if (block.label) |label| {
651 block_scope.incoming_values = std.ArrayList(*Instruction).init(irb.arena());1273 block_scope.incoming_values = std.ArrayList(*Inst).init(irb.arena());
652 block_scope.incoming_blocks = std.ArrayList(*BasicBlock).init(irb.arena());1274 block_scope.incoming_blocks = std.ArrayList(*BasicBlock).init(irb.arena());
653 block_scope.end_block = try irb.createBasicBlock(parent_scope, c"BlockEnd");1275 block_scope.end_block = try irb.createBasicBlock(parent_scope, c"BlockEnd");
654 block_scope.is_comptime = try irb.buildConstBool(1276 block_scope.is_comptime = try irb.buildConstBool(
...@@ -659,7 +1281,7 @@ pub const Builder = struct {...@@ -659,7 +1281,7 @@ pub const Builder = struct {
659 }1281 }
6601282
661 var is_continuation_unreachable = false;1283 var is_continuation_unreachable = false;
662 var noreturn_return_value: ?*Instruction = null;1284 var noreturn_return_value: ?*Inst = null;
6631285
664 var stmt_it = block.statements.iterator(0);1286 var stmt_it = block.statements.iterator(0);
665 while (stmt_it.next()) |statement_node_ptr| {1287 while (stmt_it.next()) |statement_node_ptr| {
...@@ -667,7 +1289,7 @@ pub const Builder = struct {...@@ -667,7 +1289,7 @@ pub const Builder = struct {
6671289
668 if (statement_node.cast(ast.Node.Defer)) |defer_node| {1290 if (statement_node.cast(ast.Node.Defer)) |defer_node| {
669 // defer starts a new scope1291 // defer starts a new scope
670 const defer_token = irb.parsed_file.tree.tokens.at(defer_node.defer_token);1292 const defer_token = irb.root_scope.tree.tokens.at(defer_node.defer_token);
671 const kind = switch (defer_token.id) {1293 const kind = switch (defer_token.id) {
672 Token.Id.Keyword_defer => Scope.Defer.Kind.ScopeExit,1294 Token.Id.Keyword_defer => Scope.Defer.Kind.ScopeExit,
673 Token.Id.Keyword_errdefer => Scope.Defer.Kind.ErrorExit,1295 Token.Id.Keyword_errdefer => Scope.Defer.Kind.ErrorExit,
...@@ -678,7 +1300,7 @@ pub const Builder = struct {...@@ -678,7 +1300,7 @@ pub const Builder = struct {
678 child_scope = &defer_child_scope.base;1300 child_scope = &defer_child_scope.base;
679 continue;1301 continue;
680 }1302 }
681 const statement_value = try irb.genNode(statement_node, child_scope, LVal.None);1303 const statement_value = try await (async irb.genNode(statement_node, child_scope, LVal.None) catch unreachable);
6821304
683 is_continuation_unreachable = statement_value.isNoReturn();1305 is_continuation_unreachable = statement_value.isNoReturn();
684 if (is_continuation_unreachable) {1306 if (is_continuation_unreachable) {
...@@ -686,16 +1308,19 @@ pub const Builder = struct {...@@ -686,16 +1308,19 @@ pub const Builder = struct {
686 noreturn_return_value = statement_value;1308 noreturn_return_value = statement_value;
687 }1309 }
6881310
689 if (statement_value.cast(Instruction.DeclVar)) |decl_var| {1311 if (statement_value.cast(Inst.DeclVar)) |decl_var| {
690 // variable declarations start a new scope1312 // variable declarations start a new scope
691 child_scope = decl_var.params.variable.child_scope;1313 child_scope = decl_var.params.variable.child_scope;
692 } else if (!is_continuation_unreachable) {1314 } else if (!is_continuation_unreachable) {
693 // this statement's value must be void1315 // this statement's value must be void
694 _ = irb.build(1316 _ = irb.build(
695 Instruction.CheckVoidStmt,1317 Inst.CheckVoidStmt,
696 child_scope,1318 child_scope,
697 statement_value.span,1319 Span{
698 Instruction.CheckVoidStmt.Params{ .target = statement_value },1320 .first = statement_node.firstToken(),
1321 .last = statement_node.lastToken(),
1322 },
1323 Inst.CheckVoidStmt.Params{ .target = statement_value },
699 );1324 );
700 }1325 }
701 }1326 }
...@@ -707,7 +1332,7 @@ pub const Builder = struct {...@@ -707,7 +1332,7 @@ pub const Builder = struct {
707 }1332 }
7081333
709 try irb.setCursorAtEndAndAppendBlock(block_scope.end_block);1334 try irb.setCursorAtEndAndAppendBlock(block_scope.end_block);
710 return irb.build(Instruction.Phi, parent_scope, Span.token(block.rbrace), Instruction.Phi.Params{1335 return irb.build(Inst.Phi, parent_scope, Span.token(block.rbrace), Inst.Phi.Params{
711 .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(),1336 .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(),
712 .incoming_values = block_scope.incoming_values.toOwnedSlice(),1337 .incoming_values = block_scope.incoming_values.toOwnedSlice(),
713 });1338 });
...@@ -718,26 +1343,216 @@ pub const Builder = struct {...@@ -718,26 +1343,216 @@ pub const Builder = struct {
718 try block_scope.incoming_values.append(1343 try block_scope.incoming_values.append(
719 try irb.buildConstVoid(parent_scope, Span.token(block.rbrace), true),1344 try irb.buildConstVoid(parent_scope, Span.token(block.rbrace), true),
720 );1345 );
721 _ = try irb.genDefersForBlock(child_scope, outer_block_scope, Scope.Defer.Kind.ScopeExit);1346 _ = try await (async irb.genDefersForBlock(child_scope, outer_block_scope, Scope.Defer.Kind.ScopeExit) catch unreachable);
7221347
723 _ = try irb.buildGen(Instruction.Br, parent_scope, Span.token(block.rbrace), Instruction.Br.Params{1348 _ = try irb.buildGen(Inst.Br, parent_scope, Span.token(block.rbrace), Inst.Br.Params{
724 .dest_block = block_scope.end_block,1349 .dest_block = block_scope.end_block,
725 .is_comptime = block_scope.is_comptime,1350 .is_comptime = block_scope.is_comptime,
726 });1351 });
7271352
728 try irb.setCursorAtEndAndAppendBlock(block_scope.end_block);1353 try irb.setCursorAtEndAndAppendBlock(block_scope.end_block);
7291354
730 return irb.build(Instruction.Phi, parent_scope, Span.token(block.rbrace), Instruction.Phi.Params{1355 return irb.build(Inst.Phi, parent_scope, Span.token(block.rbrace), Inst.Phi.Params{
731 .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(),1356 .incoming_blocks = block_scope.incoming_blocks.toOwnedSlice(),
732 .incoming_values = block_scope.incoming_values.toOwnedSlice(),1357 .incoming_values = block_scope.incoming_values.toOwnedSlice(),
733 });1358 });
734 }1359 }
7351360
736 _ = try irb.genDefersForBlock(child_scope, outer_block_scope, Scope.Defer.Kind.ScopeExit);1361 _ = try await (async irb.genDefersForBlock(child_scope, outer_block_scope, Scope.Defer.Kind.ScopeExit) catch unreachable);
737 return irb.buildConstVoid(child_scope, Span.token(block.rbrace), true);1362 return irb.buildConstVoid(child_scope, Span.token(block.rbrace), true);
738 }1363 }
7391364
740 fn genDefersForBlock(1365 pub async fn genControlFlowExpr(
1366 irb: *Builder,
1367 control_flow_expr: *ast.Node.ControlFlowExpression,
1368 scope: *Scope,
1369 lval: LVal,
1370 ) !*Inst {
1371 switch (control_flow_expr.kind) {
1372 ast.Node.ControlFlowExpression.Kind.Break => |arg| return error.Unimplemented,
1373 ast.Node.ControlFlowExpression.Kind.Continue => |arg| return error.Unimplemented,
1374 ast.Node.ControlFlowExpression.Kind.Return => {
1375 const src_span = Span.token(control_flow_expr.ltoken);
1376 if (scope.findFnDef() == null) {
1377 try irb.comp.addCompileError(
1378 irb.root_scope,
1379 src_span,
1380 "return expression outside function definition",
1381 );
1382 return error.SemanticAnalysisFailed;
1383 }
1384
1385 if (scope.findDeferExpr()) |scope_defer_expr| {
1386 if (!scope_defer_expr.reported_err) {
1387 try irb.comp.addCompileError(
1388 irb.root_scope,
1389 src_span,
1390 "cannot return from defer expression",
1391 );
1392 scope_defer_expr.reported_err = true;
1393 }
1394 return error.SemanticAnalysisFailed;
1395 }
1396
1397 const outer_scope = irb.begin_scope.?;
1398 const return_value = if (control_flow_expr.rhs) |rhs| blk: {
1399 break :blk try await (async irb.genNode(rhs, scope, LVal.None) catch unreachable);
1400 } else blk: {
1401 break :blk try irb.buildConstVoid(scope, src_span, true);
1402 };
1403
1404 const defer_counts = irb.countDefers(scope, outer_scope);
1405 const have_err_defers = defer_counts.error_exit != 0;
1406 if (have_err_defers or irb.comp.have_err_ret_tracing) {
1407 const err_block = try irb.createBasicBlock(scope, c"ErrRetErr");
1408 const ok_block = try irb.createBasicBlock(scope, c"ErrRetOk");
1409 if (!have_err_defers) {
1410 _ = try await (async irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ScopeExit) catch unreachable);
1411 }
1412
1413 const is_err = try irb.build(
1414 Inst.TestErr,
1415 scope,
1416 src_span,
1417 Inst.TestErr.Params{ .target = return_value },
1418 );
1419
1420 const err_is_comptime = try irb.buildTestCompTime(scope, src_span, is_err);
1421
1422 _ = try irb.buildGen(Inst.CondBr, scope, src_span, Inst.CondBr.Params{
1423 .condition = is_err,
1424 .then_block = err_block,
1425 .else_block = ok_block,
1426 .is_comptime = err_is_comptime,
1427 });
1428
1429 const ret_stmt_block = try irb.createBasicBlock(scope, c"RetStmt");
1430
1431 try irb.setCursorAtEndAndAppendBlock(err_block);
1432 if (have_err_defers) {
1433 _ = try await (async irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ErrorExit) catch unreachable);
1434 }
1435 if (irb.comp.have_err_ret_tracing and !irb.isCompTime(scope)) {
1436 _ = try irb.build(Inst.SaveErrRetAddr, scope, src_span, Inst.SaveErrRetAddr.Params{});
1437 }
1438 _ = try irb.build(Inst.Br, scope, src_span, Inst.Br.Params{
1439 .dest_block = ret_stmt_block,
1440 .is_comptime = err_is_comptime,
1441 });
1442
1443 try irb.setCursorAtEndAndAppendBlock(ok_block);
1444 if (have_err_defers) {
1445 _ = try await (async irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ScopeExit) catch unreachable);
1446 }
1447 _ = try irb.build(Inst.Br, scope, src_span, Inst.Br.Params{
1448 .dest_block = ret_stmt_block,
1449 .is_comptime = err_is_comptime,
1450 });
1451
1452 try irb.setCursorAtEndAndAppendBlock(ret_stmt_block);
1453 return irb.genAsyncReturn(scope, src_span, return_value, false);
1454 } else {
1455 _ = try await (async irb.genDefersForBlock(scope, outer_scope, Scope.Defer.Kind.ScopeExit) catch unreachable);
1456 return irb.genAsyncReturn(scope, src_span, return_value, false);
1457 }
1458 },
1459 }
1460 }
1461
1462 pub async fn genIdentifier(irb: *Builder, identifier: *ast.Node.Identifier, scope: *Scope, lval: LVal) !*Inst {
1463 const src_span = Span.token(identifier.token);
1464 const name = irb.root_scope.tree.tokenSlice(identifier.token);
1465
1466 //if (buf_eql_str(variable_name, "_") && lval == LValPtr) {
1467 // IrInstructionConst *const_instruction = ir_build_instruction<IrInstructionConst>(irb, scope, node);
1468 // const_instruction->base.value.type = get_pointer_to_type(irb->codegen,
1469 // irb->codegen->builtin_types.entry_void, false);
1470 // const_instruction->base.value.special = ConstValSpecialStatic;
1471 // const_instruction->base.value.data.x_ptr.special = ConstPtrSpecialDiscard;
1472 // return &const_instruction->base;
1473 //}
1474
1475 if (await (async irb.comp.getPrimitiveType(name) catch unreachable)) |result| {
1476 if (result) |primitive_type| {
1477 defer primitive_type.base.deref(irb.comp);
1478 switch (lval) {
1479 // if (lval == LValPtr) {
1480 // return ir_build_ref(irb, scope, node, value, false, false);
1481 LVal.Ptr => return error.Unimplemented,
1482 LVal.None => return irb.buildConstValue(scope, src_span, &primitive_type.base),
1483 }
1484 }
1485 } else |err| switch (err) {
1486 error.Overflow => {
1487 try irb.comp.addCompileError(irb.root_scope, src_span, "integer too large");
1488 return error.SemanticAnalysisFailed;
1489 },
1490 error.OutOfMemory => return error.OutOfMemory,
1491 }
1492
1493 //VariableTableEntry *var = find_variable(irb->codegen, scope, variable_name);
1494 //if (var) {
1495 // IrInstruction *var_ptr = ir_build_var_ptr(irb, scope, node, var);
1496 // if (lval == LValPtr)
1497 // return var_ptr;
1498 // else
1499 // return ir_build_load_ptr(irb, scope, node, var_ptr);
1500 //}
1501
1502 if (await (async irb.findDecl(scope, name) catch unreachable)) |decl| {
1503 return irb.build(Inst.DeclRef, scope, src_span, Inst.DeclRef.Params{
1504 .decl = decl,
1505 .lval = lval,
1506 });
1507 }
1508
1509 //if (node->owner->any_imports_failed) {
1510 // // skip the error message since we had a failing import in this file
1511 // // if an import breaks we don't need redundant undeclared identifier errors
1512 // return irb->codegen->invalid_instruction;
1513 //}
1514
1515 // TODO put a variable of same name with invalid type in global scope
1516 // so that future references to this same name will find a variable with an invalid type
1517
1518 try irb.comp.addCompileError(irb.root_scope, src_span, "unknown identifier '{}'", name);
1519 return error.SemanticAnalysisFailed;
1520 }
1521
1522 const DeferCounts = struct {
1523 scope_exit: usize,
1524 error_exit: usize,
1525 };
1526
1527 fn countDefers(irb: *Builder, inner_scope: *Scope, outer_scope: *Scope) DeferCounts {
1528 var result = DeferCounts{ .scope_exit = 0, .error_exit = 0 };
1529
1530 var scope = inner_scope;
1531 while (scope != outer_scope) {
1532 switch (scope.id) {
1533 Scope.Id.Defer => {
1534 const defer_scope = @fieldParentPtr(Scope.Defer, "base", scope);
1535 switch (defer_scope.kind) {
1536 Scope.Defer.Kind.ScopeExit => result.scope_exit += 1,
1537 Scope.Defer.Kind.ErrorExit => result.error_exit += 1,
1538 }
1539 scope = scope.parent orelse break;
1540 },
1541 Scope.Id.FnDef => break,
1542
1543 Scope.Id.CompTime,
1544 Scope.Id.Block,
1545 Scope.Id.Decls,
1546 Scope.Id.Root,
1547 => scope = scope.parent orelse break,
1548
1549 Scope.Id.DeferExpr => unreachable,
1550 }
1551 }
1552 return result;
1553 }
1554
1555 async fn genDefersForBlock(
741 irb: *Builder,1556 irb: *Builder,
742 inner_scope: *Scope,1557 inner_scope: *Scope,
743 outer_scope: *Scope,1558 outer_scope: *Scope,
...@@ -755,25 +1570,26 @@ pub const Builder = struct {...@@ -755,25 +1570,26 @@ pub const Builder = struct {
755 };1570 };
756 if (generate) {1571 if (generate) {
757 const defer_expr_scope = defer_scope.defer_expr_scope;1572 const defer_expr_scope = defer_scope.defer_expr_scope;
758 const instruction = try irb.genNode(1573 const instruction = try await (async irb.genNode(
759 defer_expr_scope.expr_node,1574 defer_expr_scope.expr_node,
760 &defer_expr_scope.base,1575 &defer_expr_scope.base,
761 LVal.None,1576 LVal.None,
762 );1577 ) catch unreachable);
763 if (instruction.isNoReturn()) {1578 if (instruction.isNoReturn()) {
764 is_noreturn = true;1579 is_noreturn = true;
765 } else {1580 } else {
766 _ = try irb.build(1581 _ = try irb.build(
767 Instruction.CheckVoidStmt,1582 Inst.CheckVoidStmt,
768 &defer_expr_scope.base,1583 &defer_expr_scope.base,
769 Span.token(defer_expr_scope.expr_node.lastToken()),1584 Span.token(defer_expr_scope.expr_node.lastToken()),
770 Instruction.CheckVoidStmt.Params{ .target = instruction },1585 Inst.CheckVoidStmt.Params{ .target = instruction },
771 );1586 );
772 }1587 }
773 }1588 }
774 },1589 },
775 Scope.Id.FnDef,1590 Scope.Id.FnDef,
776 Scope.Id.Decls,1591 Scope.Id.Decls,
1592 Scope.Id.Root,
777 => return is_noreturn,1593 => return is_noreturn,
7781594
779 Scope.Id.CompTime,1595 Scope.Id.CompTime,
...@@ -785,13 +1601,13 @@ pub const Builder = struct {...@@ -785,13 +1601,13 @@ pub const Builder = struct {
785 }1601 }
786 }1602 }
7871603
788 pub fn lvalWrap(irb: *Builder, scope: *Scope, instruction: *Instruction, lval: LVal) !*Instruction {1604 pub fn lvalWrap(irb: *Builder, scope: *Scope, instruction: *Inst, lval: LVal) !*Inst {
789 switch (lval) {1605 switch (lval) {
790 LVal.None => return instruction,1606 LVal.None => return instruction,
791 LVal.Ptr => {1607 LVal.Ptr => {
792 // We needed a pointer to a value, but we got a value. So we create1608 // We needed a pointer to a value, but we got a value. So we create
793 // an instruction which just makes a const pointer of it.1609 // an instruction which just makes a const pointer of it.
794 return irb.build(Instruction.Ref, scope, instruction.span, Instruction.Ref.Params{1610 return irb.build(Inst.Ref, scope, instruction.span, Inst.Ref.Params{
795 .target = instruction,1611 .target = instruction,
796 .mut = Type.Pointer.Mut.Const,1612 .mut = Type.Pointer.Mut.Const,
797 .volatility = Type.Pointer.Vol.Non,1613 .volatility = Type.Pointer.Vol.Non,
...@@ -811,10 +1627,10 @@ pub const Builder = struct {...@@ -811,10 +1627,10 @@ pub const Builder = struct {
811 span: Span,1627 span: Span,
812 params: I.Params,1628 params: I.Params,
813 is_generated: bool,1629 is_generated: bool,
814 ) !*Instruction {1630 ) !*Inst {
815 const inst = try self.arena().create(I{1631 const inst = try self.arena().create(I{
816 .base = Instruction{1632 .base = Inst{
817 .id = Instruction.typeToId(I),1633 .id = Inst.typeToId(I),
818 .is_generated = is_generated,1634 .is_generated = is_generated,
819 .scope = scope,1635 .scope = scope,
820 .debug_id = self.next_debug_id,1636 .debug_id = self.next_debug_id,
...@@ -838,9 +1654,27 @@ pub const Builder = struct {...@@ -838,9 +1654,27 @@ pub const Builder = struct {
838 inline while (i < @memberCount(I.Params)) : (i += 1) {1654 inline while (i < @memberCount(I.Params)) : (i += 1) {
839 const FieldType = comptime @typeOf(@field(I.Params(undefined), @memberName(I.Params, i)));1655 const FieldType = comptime @typeOf(@field(I.Params(undefined), @memberName(I.Params, i)));
840 switch (FieldType) {1656 switch (FieldType) {
841 *Instruction => @field(inst.params, @memberName(I.Params, i)).ref(self),1657 *Inst => @field(inst.params, @memberName(I.Params, i)).ref(self),
842 ?*Instruction => if (@field(inst.params, @memberName(I.Params, i))) |other| other.ref(self),1658 *BasicBlock => @field(inst.params, @memberName(I.Params, i)).ref(self),
843 else => {},1659 ?*Inst => if (@field(inst.params, @memberName(I.Params, i))) |other| other.ref(self),
1660 []*Inst => {
1661 // TODO https://github.com/ziglang/zig/issues/1269
1662 for (@field(inst.params, @memberName(I.Params, i))) |other|
1663 other.ref(self);
1664 },
1665 []*BasicBlock => {
1666 // TODO https://github.com/ziglang/zig/issues/1269
1667 for (@field(inst.params, @memberName(I.Params, i))) |other|
1668 other.ref(self);
1669 },
1670 Type.Pointer.Mut,
1671 Type.Pointer.Vol,
1672 Type.Pointer.Size,
1673 LVal,
1674 *Decl,
1675 => {},
1676 // it's ok to add more types here, just make sure any instructions are ref'd appropriately
1677 else => @compileError("unrecognized type in Params: " ++ @typeName(FieldType)),
844 }1678 }
845 }1679 }
8461680
...@@ -855,7 +1689,7 @@ pub const Builder = struct {...@@ -855,7 +1689,7 @@ pub const Builder = struct {
855 scope: *Scope,1689 scope: *Scope,
856 span: Span,1690 span: Span,
857 params: I.Params,1691 params: I.Params,
858 ) !*Instruction {1692 ) !*Inst {
859 return self.buildExtra(I, scope, span, params, false);1693 return self.buildExtra(I, scope, span, params, false);
860 }1694 }
8611695
...@@ -865,21 +1699,95 @@ pub const Builder = struct {...@@ -865,21 +1699,95 @@ pub const Builder = struct {
865 scope: *Scope,1699 scope: *Scope,
866 span: Span,1700 span: Span,
867 params: I.Params,1701 params: I.Params,
868 ) !*Instruction {1702 ) !*Inst {
869 return self.buildExtra(I, scope, span, params, true);1703 return self.buildExtra(I, scope, span, params, true);
870 }1704 }
8711705
872 fn buildConstBool(self: *Builder, scope: *Scope, span: Span, x: bool) !*Instruction {1706 fn buildConstBool(self: *Builder, scope: *Scope, span: Span, x: bool) !*Inst {
873 const inst = try self.build(Instruction.Const, scope, span, Instruction.Const.Params{});1707 const inst = try self.build(Inst.Const, scope, span, Inst.Const.Params{});
874 inst.val = IrVal{ .KnownValue = &Value.Bool.get(self.comp, x).base };1708 inst.val = IrVal{ .KnownValue = &Value.Bool.get(self.comp, x).base };
875 return inst;1709 return inst;
876 }1710 }
8771711
878 fn buildConstVoid(self: *Builder, scope: *Scope, span: Span, is_generated: bool) !*Instruction {1712 fn buildConstVoid(self: *Builder, scope: *Scope, span: Span, is_generated: bool) !*Inst {
879 const inst = try self.buildExtra(Instruction.Const, scope, span, Instruction.Const.Params{}, is_generated);1713 const inst = try self.buildExtra(Inst.Const, scope, span, Inst.Const.Params{}, is_generated);
880 inst.val = IrVal{ .KnownValue = &Value.Void.get(self.comp).base };1714 inst.val = IrVal{ .KnownValue = &Value.Void.get(self.comp).base };
881 return inst;1715 return inst;
882 }1716 }
1717
1718 fn buildConstValue(self: *Builder, scope: *Scope, span: Span, v: *Value) !*Inst {
1719 const inst = try self.build(Inst.Const, scope, span, Inst.Const.Params{});
1720 inst.val = IrVal{ .KnownValue = v.getRef() };
1721 return inst;
1722 }
1723
1724 /// If the code is explicitly set to be comptime, then builds a const bool,
1725 /// otherwise builds a TestCompTime instruction.
1726 fn buildTestCompTime(self: *Builder, scope: *Scope, span: Span, target: *Inst) !*Inst {
1727 if (self.isCompTime(scope)) {
1728 return self.buildConstBool(scope, span, true);
1729 } else {
1730 return self.build(
1731 Inst.TestCompTime,
1732 scope,
1733 span,
1734 Inst.TestCompTime.Params{ .target = target },
1735 );
1736 }
1737 }
1738
1739 fn genAsyncReturn(irb: *Builder, scope: *Scope, span: Span, result: *Inst, is_gen: bool) !*Inst {
1740 _ = irb.buildGen(
1741 Inst.AddImplicitReturnType,
1742 scope,
1743 span,
1744 Inst.AddImplicitReturnType.Params{ .target = result },
1745 );
1746
1747 if (!irb.is_async) {
1748 return irb.buildExtra(
1749 Inst.Return,
1750 scope,
1751 span,
1752 Inst.Return.Params{ .return_value = result },
1753 is_gen,
1754 );
1755 }
1756 return error.Unimplemented;
1757
1758 //ir_build_store_ptr(irb, scope, node, irb->exec->coro_result_field_ptr, return_value);
1759 //IrInstruction *promise_type_val = ir_build_const_type(irb, scope, node,
1760 // get_optional_type(irb->codegen, irb->codegen->builtin_types.entry_promise));
1761 //// TODO replace replacement_value with @intToPtr(?promise, 0x1) when it doesn't crash zig
1762 //IrInstruction *replacement_value = irb->exec->coro_handle;
1763 //IrInstruction *maybe_await_handle = ir_build_atomic_rmw(irb, scope, node,
1764 // promise_type_val, irb->exec->coro_awaiter_field_ptr, nullptr, replacement_value, nullptr,
1765 // AtomicRmwOp_xchg, AtomicOrderSeqCst);
1766 //ir_build_store_ptr(irb, scope, node, irb->exec->await_handle_var_ptr, maybe_await_handle);
1767 //IrInstruction *is_non_null = ir_build_test_nonnull(irb, scope, node, maybe_await_handle);
1768 //IrInstruction *is_comptime = ir_build_const_bool(irb, scope, node, false);
1769 //return ir_build_cond_br(irb, scope, node, is_non_null, irb->exec->coro_normal_final, irb->exec->coro_early_final,
1770 // is_comptime);
1771 //// the above blocks are rendered by ir_gen after the rest of codegen
1772 }
1773
1774 async fn findDecl(irb: *Builder, scope: *Scope, name: []const u8) ?*Decl {
1775 var s = scope;
1776 while (true) {
1777 switch (s.id) {
1778 Scope.Id.Decls => {
1779 const decls = @fieldParentPtr(Scope.Decls, "base", s);
1780 const table = await (async decls.getTableReadOnly() catch unreachable);
1781 if (table.get(name)) |entry| {
1782 return entry.value;
1783 }
1784 },
1785 Scope.Id.Root => return null,
1786 else => {},
1787 }
1788 s = s.parent.?;
1789 }
1790 }
883};1791};
8841792
885const Analyze = struct {1793const Analyze = struct {
...@@ -888,7 +1796,7 @@ const Analyze = struct {...@@ -888,7 +1796,7 @@ const Analyze = struct {
888 const_predecessor_bb: ?*BasicBlock,1796 const_predecessor_bb: ?*BasicBlock,
889 parent_basic_block: *BasicBlock,1797 parent_basic_block: *BasicBlock,
890 instruction_index: usize,1798 instruction_index: usize,
891 src_implicit_return_type_list: std.ArrayList(*Instruction),1799 src_implicit_return_type_list: std.ArrayList(*Inst),
892 explicit_return_type: ?*Type,1800 explicit_return_type: ?*Type,
8931801
894 pub const Error = error{1802 pub const Error = error{
...@@ -902,8 +1810,8 @@ const Analyze = struct {...@@ -902,8 +1810,8 @@ const Analyze = struct {
902 OutOfMemory,1810 OutOfMemory,
903 };1811 };
9041812
905 pub fn init(comp: *Compilation, parsed_file: *ParsedFile, explicit_return_type: ?*Type) !Analyze {1813 pub fn init(comp: *Compilation, root_scope: *Scope.Root, explicit_return_type: ?*Type) !Analyze {
906 var irb = try Builder.init(comp, parsed_file);1814 var irb = try Builder.init(comp, root_scope, null);
907 errdefer irb.abort();1815 errdefer irb.abort();
9081816
909 return Analyze{1817 return Analyze{
...@@ -912,7 +1820,7 @@ const Analyze = struct {...@@ -912,7 +1820,7 @@ const Analyze = struct {
912 .const_predecessor_bb = null,1820 .const_predecessor_bb = null,
913 .parent_basic_block = undefined, // initialized with startBasicBlock1821 .parent_basic_block = undefined, // initialized with startBasicBlock
914 .instruction_index = undefined, // initialized with startBasicBlock1822 .instruction_index = undefined, // initialized with startBasicBlock
915 .src_implicit_return_type_list = std.ArrayList(*Instruction).init(irb.arena()),1823 .src_implicit_return_type_list = std.ArrayList(*Inst).init(irb.arena()),
916 .explicit_return_type = explicit_return_type,1824 .explicit_return_type = explicit_return_type,
917 };1825 };
918 }1826 }
...@@ -921,7 +1829,7 @@ const Analyze = struct {...@@ -921,7 +1829,7 @@ const Analyze = struct {
921 self.irb.abort();1829 self.irb.abort();
922 }1830 }
9231831
924 pub fn getNewBasicBlock(self: *Analyze, old_bb: *BasicBlock, ref_old_instruction: ?*Instruction) !*BasicBlock {1832 pub fn getNewBasicBlock(self: *Analyze, old_bb: *BasicBlock, ref_old_instruction: ?*Inst) !*BasicBlock {
925 if (old_bb.child) |child| {1833 if (old_bb.child) |child| {
926 if (ref_old_instruction == null or child.ref_instruction != ref_old_instruction)1834 if (ref_old_instruction == null or child.ref_instruction != ref_old_instruction)
927 return child;1835 return child;
...@@ -981,21 +1889,478 @@ const Analyze = struct {...@@ -981,21 +1889,478 @@ const Analyze = struct {
981 }1889 }
9821890
983 fn addCompileError(self: *Analyze, span: Span, comptime fmt: []const u8, args: ...) !void {1891 fn addCompileError(self: *Analyze, span: Span, comptime fmt: []const u8, args: ...) !void {
984 return self.irb.comp.addCompileError(self.irb.parsed_file, span, fmt, args);1892 return self.irb.comp.addCompileError(self.irb.root_scope, span, fmt, args);
985 }1893 }
9861894
987 fn resolvePeerTypes(self: *Analyze, expected_type: ?*Type, peers: []const *Instruction) Analyze.Error!*Type {1895 fn resolvePeerTypes(self: *Analyze, expected_type: ?*Type, peers: []const *Inst) Analyze.Error!*Type {
988 // TODO actual implementation1896 // TODO actual implementation
989 return &Type.Void.get(self.irb.comp).base;1897 return &Type.Void.get(self.irb.comp).base;
990 }1898 }
9911899
992 fn implicitCast(self: *Analyze, target: *Instruction, optional_dest_type: ?*Type) Analyze.Error!*Instruction {1900 fn implicitCast(self: *Analyze, target: *Inst, optional_dest_type: ?*Type) Analyze.Error!*Inst {
993 const dest_type = optional_dest_type orelse return target;1901 const dest_type = optional_dest_type orelse return target;
994 @panic("TODO implicitCast");1902 const from_type = target.getKnownType();
1903 if (from_type == dest_type or from_type.id == Type.Id.NoReturn) return target;
1904 return self.analyzeCast(target, target, dest_type);
1905 }
1906
1907 fn analyzeCast(ira: *Analyze, source_instr: *Inst, target: *Inst, dest_type: *Type) !*Inst {
1908 const from_type = target.getKnownType();
1909
1910 //if (type_is_invalid(wanted_type) || type_is_invalid(actual_type)) {
1911 // return ira->codegen->invalid_instruction;
1912 //}
1913
1914 //// perfect match or non-const to const
1915 //ConstCastOnly const_cast_result = types_match_const_cast_only(ira, wanted_type, actual_type,
1916 // source_node, false);
1917 //if (const_cast_result.id == ConstCastResultIdOk) {
1918 // return ir_resolve_cast(ira, source_instr, value, wanted_type, CastOpNoop, false);
1919 //}
1920
1921 //// widening conversion
1922 //if (wanted_type->id == TypeTableEntryIdInt &&
1923 // actual_type->id == TypeTableEntryIdInt &&
1924 // wanted_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
1925 // wanted_type->data.integral.bit_count >= actual_type->data.integral.bit_count)
1926 //{
1927 // return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
1928 //}
1929
1930 //// small enough unsigned ints can get casted to large enough signed ints
1931 //if (wanted_type->id == TypeTableEntryIdInt && wanted_type->data.integral.is_signed &&
1932 // actual_type->id == TypeTableEntryIdInt && !actual_type->data.integral.is_signed &&
1933 // wanted_type->data.integral.bit_count > actual_type->data.integral.bit_count)
1934 //{
1935 // return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
1936 //}
1937
1938 //// float widening conversion
1939 //if (wanted_type->id == TypeTableEntryIdFloat &&
1940 // actual_type->id == TypeTableEntryIdFloat &&
1941 // wanted_type->data.floating.bit_count >= actual_type->data.floating.bit_count)
1942 //{
1943 // return ir_analyze_widen_or_shorten(ira, source_instr, value, wanted_type);
1944 //}
1945
1946 //// cast from [N]T to []const T
1947 //if (is_slice(wanted_type) && actual_type->id == TypeTableEntryIdArray) {
1948 // TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
1949 // assert(ptr_type->id == TypeTableEntryIdPointer);
1950 // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
1951 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
1952 // source_node, false).id == ConstCastResultIdOk)
1953 // {
1954 // return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
1955 // }
1956 //}
1957
1958 //// cast from *const [N]T to []const T
1959 //if (is_slice(wanted_type) &&
1960 // actual_type->id == TypeTableEntryIdPointer &&
1961 // actual_type->data.pointer.is_const &&
1962 // actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
1963 //{
1964 // TypeTableEntry *ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
1965 // assert(ptr_type->id == TypeTableEntryIdPointer);
1966
1967 // TypeTableEntry *array_type = actual_type->data.pointer.child_type;
1968
1969 // if ((ptr_type->data.pointer.is_const || array_type->data.array.len == 0) &&
1970 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, array_type->data.array.child_type,
1971 // source_node, false).id == ConstCastResultIdOk)
1972 // {
1973 // return ir_analyze_array_to_slice(ira, source_instr, value, wanted_type);
1974 // }
1975 //}
1976
1977 //// cast from [N]T to *const []const T
1978 //if (wanted_type->id == TypeTableEntryIdPointer &&
1979 // wanted_type->data.pointer.is_const &&
1980 // is_slice(wanted_type->data.pointer.child_type) &&
1981 // actual_type->id == TypeTableEntryIdArray)
1982 //{
1983 // TypeTableEntry *ptr_type =
1984 // wanted_type->data.pointer.child_type->data.structure.fields[slice_ptr_index].type_entry;
1985 // assert(ptr_type->id == TypeTableEntryIdPointer);
1986 // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
1987 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
1988 // source_node, false).id == ConstCastResultIdOk)
1989 // {
1990 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
1991 // if (type_is_invalid(cast1->value.type))
1992 // return ira->codegen->invalid_instruction;
1993
1994 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
1995 // if (type_is_invalid(cast2->value.type))
1996 // return ira->codegen->invalid_instruction;
1997
1998 // return cast2;
1999 // }
2000 //}
2001
2002 //// cast from [N]T to ?[]const T
2003 //if (wanted_type->id == TypeTableEntryIdOptional &&
2004 // is_slice(wanted_type->data.maybe.child_type) &&
2005 // actual_type->id == TypeTableEntryIdArray)
2006 //{
2007 // TypeTableEntry *ptr_type =
2008 // wanted_type->data.maybe.child_type->data.structure.fields[slice_ptr_index].type_entry;
2009 // assert(ptr_type->id == TypeTableEntryIdPointer);
2010 // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
2011 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
2012 // source_node, false).id == ConstCastResultIdOk)
2013 // {
2014 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.maybe.child_type, value);
2015 // if (type_is_invalid(cast1->value.type))
2016 // return ira->codegen->invalid_instruction;
2017
2018 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2019 // if (type_is_invalid(cast2->value.type))
2020 // return ira->codegen->invalid_instruction;
2021
2022 // return cast2;
2023 // }
2024 //}
2025
2026 //// *[N]T to [*]T
2027 //if (wanted_type->id == TypeTableEntryIdPointer &&
2028 // wanted_type->data.pointer.ptr_len == PtrLenUnknown &&
2029 // actual_type->id == TypeTableEntryIdPointer &&
2030 // actual_type->data.pointer.ptr_len == PtrLenSingle &&
2031 // actual_type->data.pointer.child_type->id == TypeTableEntryIdArray &&
2032 // actual_type->data.pointer.alignment >= wanted_type->data.pointer.alignment &&
2033 // types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
2034 // actual_type->data.pointer.child_type->data.array.child_type, source_node,
2035 // !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
2036 //{
2037 // return ir_resolve_ptr_of_array_to_unknown_len_ptr(ira, source_instr, value, wanted_type);
2038 //}
2039
2040 //// *[N]T to []T
2041 //if (is_slice(wanted_type) &&
2042 // actual_type->id == TypeTableEntryIdPointer &&
2043 // actual_type->data.pointer.ptr_len == PtrLenSingle &&
2044 // actual_type->data.pointer.child_type->id == TypeTableEntryIdArray)
2045 //{
2046 // TypeTableEntry *slice_ptr_type = wanted_type->data.structure.fields[slice_ptr_index].type_entry;
2047 // assert(slice_ptr_type->id == TypeTableEntryIdPointer);
2048 // if (types_match_const_cast_only(ira, slice_ptr_type->data.pointer.child_type,
2049 // actual_type->data.pointer.child_type->data.array.child_type, source_node,
2050 // !slice_ptr_type->data.pointer.is_const).id == ConstCastResultIdOk)
2051 // {
2052 // return ir_resolve_ptr_of_array_to_slice(ira, source_instr, value, wanted_type);
2053 // }
2054 //}
2055
2056 //// cast from T to ?T
2057 //// note that the *T to ?*T case is handled via the "ConstCastOnly" mechanism
2058 //if (wanted_type->id == TypeTableEntryIdOptional) {
2059 // TypeTableEntry *wanted_child_type = wanted_type->data.maybe.child_type;
2060 // if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node,
2061 // false).id == ConstCastResultIdOk)
2062 // {
2063 // return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
2064 // } else if (actual_type->id == TypeTableEntryIdComptimeInt ||
2065 // actual_type->id == TypeTableEntryIdComptimeFloat)
2066 // {
2067 // if (ir_num_lit_fits_in_other_type(ira, value, wanted_child_type, true)) {
2068 // return ir_analyze_maybe_wrap(ira, source_instr, value, wanted_type);
2069 // } else {
2070 // return ira->codegen->invalid_instruction;
2071 // }
2072 // } else if (wanted_child_type->id == TypeTableEntryIdPointer &&
2073 // wanted_child_type->data.pointer.is_const &&
2074 // (actual_type->id == TypeTableEntryIdPointer || is_container(actual_type)))
2075 // {
2076 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_child_type, value);
2077 // if (type_is_invalid(cast1->value.type))
2078 // return ira->codegen->invalid_instruction;
2079
2080 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2081 // if (type_is_invalid(cast2->value.type))
2082 // return ira->codegen->invalid_instruction;
2083
2084 // return cast2;
2085 // }
2086 //}
2087
2088 //// cast from null literal to maybe type
2089 //if (wanted_type->id == TypeTableEntryIdOptional &&
2090 // actual_type->id == TypeTableEntryIdNull)
2091 //{
2092 // return ir_analyze_null_to_maybe(ira, source_instr, value, wanted_type);
2093 //}
2094
2095 //// cast from child type of error type to error type
2096 //if (wanted_type->id == TypeTableEntryIdErrorUnion) {
2097 // if (types_match_const_cast_only(ira, wanted_type->data.error_union.payload_type, actual_type,
2098 // source_node, false).id == ConstCastResultIdOk)
2099 // {
2100 // return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
2101 // } else if (actual_type->id == TypeTableEntryIdComptimeInt ||
2102 // actual_type->id == TypeTableEntryIdComptimeFloat)
2103 // {
2104 // if (ir_num_lit_fits_in_other_type(ira, value, wanted_type->data.error_union.payload_type, true)) {
2105 // return ir_analyze_err_wrap_payload(ira, source_instr, value, wanted_type);
2106 // } else {
2107 // return ira->codegen->invalid_instruction;
2108 // }
2109 // }
2110 //}
2111
2112 //// cast from [N]T to E![]const T
2113 //if (wanted_type->id == TypeTableEntryIdErrorUnion &&
2114 // is_slice(wanted_type->data.error_union.payload_type) &&
2115 // actual_type->id == TypeTableEntryIdArray)
2116 //{
2117 // TypeTableEntry *ptr_type =
2118 // wanted_type->data.error_union.payload_type->data.structure.fields[slice_ptr_index].type_entry;
2119 // assert(ptr_type->id == TypeTableEntryIdPointer);
2120 // if ((ptr_type->data.pointer.is_const || actual_type->data.array.len == 0) &&
2121 // types_match_const_cast_only(ira, ptr_type->data.pointer.child_type, actual_type->data.array.child_type,
2122 // source_node, false).id == ConstCastResultIdOk)
2123 // {
2124 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
2125 // if (type_is_invalid(cast1->value.type))
2126 // return ira->codegen->invalid_instruction;
2127
2128 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2129 // if (type_is_invalid(cast2->value.type))
2130 // return ira->codegen->invalid_instruction;
2131
2132 // return cast2;
2133 // }
2134 //}
2135
2136 //// cast from error set to error union type
2137 //if (wanted_type->id == TypeTableEntryIdErrorUnion &&
2138 // actual_type->id == TypeTableEntryIdErrorSet)
2139 //{
2140 // return ir_analyze_err_wrap_code(ira, source_instr, value, wanted_type);
2141 //}
2142
2143 //// cast from T to E!?T
2144 //if (wanted_type->id == TypeTableEntryIdErrorUnion &&
2145 // wanted_type->data.error_union.payload_type->id == TypeTableEntryIdOptional &&
2146 // actual_type->id != TypeTableEntryIdOptional)
2147 //{
2148 // TypeTableEntry *wanted_child_type = wanted_type->data.error_union.payload_type->data.maybe.child_type;
2149 // if (types_match_const_cast_only(ira, wanted_child_type, actual_type, source_node, false).id == ConstCastResultIdOk ||
2150 // actual_type->id == TypeTableEntryIdNull ||
2151 // actual_type->id == TypeTableEntryIdComptimeInt ||
2152 // actual_type->id == TypeTableEntryIdComptimeFloat)
2153 // {
2154 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.error_union.payload_type, value);
2155 // if (type_is_invalid(cast1->value.type))
2156 // return ira->codegen->invalid_instruction;
2157
2158 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2159 // if (type_is_invalid(cast2->value.type))
2160 // return ira->codegen->invalid_instruction;
2161
2162 // return cast2;
2163 // }
2164 //}
2165
2166 // cast from comptime-known integer to another integer where the value fits
2167 if (target.isCompTime() and (from_type.id == Type.Id.Int or from_type.id == Type.Id.ComptimeInt)) cast: {
2168 const target_val = target.val.KnownValue;
2169 const from_int = &target_val.cast(Value.Int).?.big_int;
2170 const fits = fits: {
2171 if (dest_type.cast(Type.ComptimeInt)) |ctint| {
2172 break :fits true;
2173 }
2174 if (dest_type.cast(Type.Int)) |int| {
2175 break :fits from_int.fitsInTwosComp(int.key.is_signed, int.key.bit_count);
2176 }
2177 break :cast;
2178 };
2179 if (!fits) {
2180 try ira.addCompileError(
2181 source_instr.span,
2182 "integer value '{}' cannot be stored in type '{}'",
2183 from_int,
2184 dest_type.name,
2185 );
2186 return error.SemanticAnalysisFailed;
2187 }
2188
2189 const new_val = try target.copyVal(ira.irb.comp);
2190 new_val.setType(dest_type, ira.irb.comp);
2191 return ira.irb.buildConstValue(source_instr.scope, source_instr.span, new_val);
2192 }
2193
2194 // cast from number literal to another type
2195 // cast from number literal to *const integer
2196 //if (actual_type->id == TypeTableEntryIdComptimeFloat ||
2197 // actual_type->id == TypeTableEntryIdComptimeInt)
2198 //{
2199 // ensure_complete_type(ira->codegen, wanted_type);
2200 // if (type_is_invalid(wanted_type))
2201 // return ira->codegen->invalid_instruction;
2202 // if (wanted_type->id == TypeTableEntryIdEnum) {
2203 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.enumeration.tag_int_type, value);
2204 // if (type_is_invalid(cast1->value.type))
2205 // return ira->codegen->invalid_instruction;
2206
2207 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2208 // if (type_is_invalid(cast2->value.type))
2209 // return ira->codegen->invalid_instruction;
2210
2211 // return cast2;
2212 // } else if (wanted_type->id == TypeTableEntryIdPointer &&
2213 // wanted_type->data.pointer.is_const)
2214 // {
2215 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, wanted_type->data.pointer.child_type, value);
2216 // if (type_is_invalid(cast1->value.type))
2217 // return ira->codegen->invalid_instruction;
2218
2219 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2220 // if (type_is_invalid(cast2->value.type))
2221 // return ira->codegen->invalid_instruction;
2222
2223 // return cast2;
2224 // } else if (ir_num_lit_fits_in_other_type(ira, value, wanted_type, true)) {
2225 // CastOp op;
2226 // if ((actual_type->id == TypeTableEntryIdComptimeFloat &&
2227 // wanted_type->id == TypeTableEntryIdFloat) ||
2228 // (actual_type->id == TypeTableEntryIdComptimeInt &&
2229 // wanted_type->id == TypeTableEntryIdInt))
2230 // {
2231 // op = CastOpNumLitToConcrete;
2232 // } else if (wanted_type->id == TypeTableEntryIdInt) {
2233 // op = CastOpFloatToInt;
2234 // } else if (wanted_type->id == TypeTableEntryIdFloat) {
2235 // op = CastOpIntToFloat;
2236 // } else {
2237 // zig_unreachable();
2238 // }
2239 // return ir_resolve_cast(ira, source_instr, value, wanted_type, op, false);
2240 // } else {
2241 // return ira->codegen->invalid_instruction;
2242 // }
2243 //}
2244
2245 //// cast from typed number to integer or float literal.
2246 //// works when the number is known at compile time
2247 //if (instr_is_comptime(value) &&
2248 // ((actual_type->id == TypeTableEntryIdInt && wanted_type->id == TypeTableEntryIdComptimeInt) ||
2249 // (actual_type->id == TypeTableEntryIdFloat && wanted_type->id == TypeTableEntryIdComptimeFloat)))
2250 //{
2251 // return ir_analyze_number_to_literal(ira, source_instr, value, wanted_type);
2252 //}
2253
2254 //// cast from union to the enum type of the union
2255 //if (actual_type->id == TypeTableEntryIdUnion && wanted_type->id == TypeTableEntryIdEnum) {
2256 // type_ensure_zero_bits_known(ira->codegen, actual_type);
2257 // if (type_is_invalid(actual_type))
2258 // return ira->codegen->invalid_instruction;
2259
2260 // if (actual_type->data.unionation.tag_type == wanted_type) {
2261 // return ir_analyze_union_to_tag(ira, source_instr, value, wanted_type);
2262 // }
2263 //}
2264
2265 //// enum to union which has the enum as the tag type
2266 //if (wanted_type->id == TypeTableEntryIdUnion && actual_type->id == TypeTableEntryIdEnum &&
2267 // (wanted_type->data.unionation.decl_node->data.container_decl.auto_enum ||
2268 // wanted_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr))
2269 //{
2270 // type_ensure_zero_bits_known(ira->codegen, wanted_type);
2271 // if (wanted_type->data.unionation.tag_type == actual_type) {
2272 // return ir_analyze_enum_to_union(ira, source_instr, value, wanted_type);
2273 // }
2274 //}
2275
2276 //// enum to &const union which has the enum as the tag type
2277 //if (actual_type->id == TypeTableEntryIdEnum && wanted_type->id == TypeTableEntryIdPointer) {
2278 // TypeTableEntry *union_type = wanted_type->data.pointer.child_type;
2279 // if (union_type->data.unionation.decl_node->data.container_decl.auto_enum ||
2280 // union_type->data.unionation.decl_node->data.container_decl.init_arg_expr != nullptr)
2281 // {
2282 // type_ensure_zero_bits_known(ira->codegen, union_type);
2283 // if (union_type->data.unionation.tag_type == actual_type) {
2284 // IrInstruction *cast1 = ir_analyze_cast(ira, source_instr, union_type, value);
2285 // if (type_is_invalid(cast1->value.type))
2286 // return ira->codegen->invalid_instruction;
2287
2288 // IrInstruction *cast2 = ir_analyze_cast(ira, source_instr, wanted_type, cast1);
2289 // if (type_is_invalid(cast2->value.type))
2290 // return ira->codegen->invalid_instruction;
2291
2292 // return cast2;
2293 // }
2294 // }
2295 //}
2296
2297 //// cast from *T to *[1]T
2298 //if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
2299 // actual_type->id == TypeTableEntryIdPointer && actual_type->data.pointer.ptr_len == PtrLenSingle)
2300 //{
2301 // TypeTableEntry *array_type = wanted_type->data.pointer.child_type;
2302 // if (array_type->id == TypeTableEntryIdArray && array_type->data.array.len == 1 &&
2303 // types_match_const_cast_only(ira, array_type->data.array.child_type,
2304 // actual_type->data.pointer.child_type, source_node,
2305 // !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
2306 // {
2307 // if (wanted_type->data.pointer.alignment > actual_type->data.pointer.alignment) {
2308 // ErrorMsg *msg = ir_add_error(ira, source_instr, buf_sprintf("cast increases pointer alignment"));
2309 // add_error_note(ira->codegen, msg, value->source_node,
2310 // buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&actual_type->name),
2311 // actual_type->data.pointer.alignment));
2312 // add_error_note(ira->codegen, msg, source_instr->source_node,
2313 // buf_sprintf("'%s' has alignment %" PRIu32, buf_ptr(&wanted_type->name),
2314 // wanted_type->data.pointer.alignment));
2315 // return ira->codegen->invalid_instruction;
2316 // }
2317 // return ir_analyze_ptr_to_array(ira, source_instr, value, wanted_type);
2318 // }
2319 //}
2320
2321 //// cast from T to *T where T is zero bits
2322 //if (wanted_type->id == TypeTableEntryIdPointer && wanted_type->data.pointer.ptr_len == PtrLenSingle &&
2323 // types_match_const_cast_only(ira, wanted_type->data.pointer.child_type,
2324 // actual_type, source_node, !wanted_type->data.pointer.is_const).id == ConstCastResultIdOk)
2325 //{
2326 // type_ensure_zero_bits_known(ira->codegen, actual_type);
2327 // if (type_is_invalid(actual_type)) {
2328 // return ira->codegen->invalid_instruction;
2329 // }
2330 // if (!type_has_bits(actual_type)) {
2331 // return ir_get_ref(ira, source_instr, value, false, false);
2332 // }
2333 //}
2334
2335 //// cast from undefined to anything
2336 //if (actual_type->id == TypeTableEntryIdUndefined) {
2337 // return ir_analyze_undefined_to_anything(ira, source_instr, value, wanted_type);
2338 //}
2339
2340 //// cast from something to const pointer of it
2341 //if (!type_requires_comptime(actual_type)) {
2342 // TypeTableEntry *const_ptr_actual = get_pointer_to_type(ira->codegen, actual_type, true);
2343 // if (types_match_const_cast_only(ira, wanted_type, const_ptr_actual, source_node, false).id == ConstCastResultIdOk) {
2344 // return ir_analyze_cast_ref(ira, source_instr, value, wanted_type);
2345 // }
2346 //}
2347
2348 try ira.addCompileError(
2349 source_instr.span,
2350 "expected type '{}', found '{}'",
2351 dest_type.name,
2352 from_type.name,
2353 );
2354 //ErrorMsg *parent_msg = ir_add_error_node(ira, source_instr->source_node,
2355 // buf_sprintf("expected type '%s', found '%s'",
2356 // buf_ptr(&wanted_type->name),
2357 // buf_ptr(&actual_type->name)));
2358 //report_recursive_error(ira, source_instr->source_node, &const_cast_result, parent_msg);
2359 return error.SemanticAnalysisFailed;
995 }2360 }
9962361
997 fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Instruction) ?*Value {2362 fn getCompTimeValOrNullUndefOk(self: *Analyze, target: *Inst) ?*Value {
998 @panic("TODO getCompTimeValOrNullUndefOk");2363 @panic("TODO");
999 }2364 }
10002365
1001 fn getCompTimeRef(2366 fn getCompTimeRef(
...@@ -1004,9 +2369,8 @@ const Analyze = struct {...@@ -1004,9 +2369,8 @@ const Analyze = struct {
1004 ptr_mut: Value.Ptr.Mut,2369 ptr_mut: Value.Ptr.Mut,
1005 mut: Type.Pointer.Mut,2370 mut: Type.Pointer.Mut,
1006 volatility: Type.Pointer.Vol,2371 volatility: Type.Pointer.Vol,
1007 ptr_align: u32,2372 ) Analyze.Error!*Inst {
1008 ) Analyze.Error!*Instruction {2373 return error.Unimplemented;
1009 @panic("TODO getCompTimeRef");
1010 }2374 }
1011};2375};
10122376
...@@ -1014,43 +2378,32 @@ pub async fn gen(...@@ -1014,43 +2378,32 @@ pub async fn gen(
1014 comp: *Compilation,2378 comp: *Compilation,
1015 body_node: *ast.Node,2379 body_node: *ast.Node,
1016 scope: *Scope,2380 scope: *Scope,
1017 end_span: Span,
1018 parsed_file: *ParsedFile,
1019) !*Code {2381) !*Code {
1020 var irb = try Builder.init(comp, parsed_file);2382 var irb = try Builder.init(comp, scope.findRoot(), scope);
1021 errdefer irb.abort();2383 errdefer irb.abort();
10222384
1023 const entry_block = try irb.createBasicBlock(scope, c"Entry");2385 const entry_block = try irb.createBasicBlock(scope, c"Entry");
1024 entry_block.ref(); // Entry block gets a reference because we enter it to begin.2386 entry_block.ref(&irb); // Entry block gets a reference because we enter it to begin.
1025 try irb.setCursorAtEndAndAppendBlock(entry_block);2387 try irb.setCursorAtEndAndAppendBlock(entry_block);
10262388
1027 const result = try irb.genNode(body_node, scope, LVal.None);2389 const result = try await (async irb.genNode(body_node, scope, LVal.None) catch unreachable);
1028 if (!result.isNoReturn()) {2390 if (!result.isNoReturn()) {
1029 _ = irb.buildGen(2391 // no need for save_err_ret_addr because this cannot return error
1030 Instruction.AddImplicitReturnType,2392 _ = try irb.genAsyncReturn(scope, Span.token(body_node.lastToken()), result, true);
1031 scope,
1032 end_span,
1033 Instruction.AddImplicitReturnType.Params{ .target = result },
1034 );
1035 _ = irb.buildGen(
1036 Instruction.Return,
1037 scope,
1038 end_span,
1039 Instruction.Return.Params{ .return_value = result },
1040 );
1041 }2393 }
10422394
1043 return irb.finish();2395 return irb.finish();
1044}2396}
10452397
1046pub async fn analyze(comp: *Compilation, parsed_file: *ParsedFile, old_code: *Code, expected_type: ?*Type) !*Code {2398pub async fn analyze(comp: *Compilation, old_code: *Code, expected_type: ?*Type) !*Code {
1047 var ira = try Analyze.init(comp, parsed_file, expected_type);
1048 errdefer ira.abort();
1049
1050 const old_entry_bb = old_code.basic_block_list.at(0);2399 const old_entry_bb = old_code.basic_block_list.at(0);
2400 const root_scope = old_entry_bb.scope.findRoot();
2401
2402 var ira = try Analyze.init(comp, root_scope, expected_type);
2403 errdefer ira.abort();
10512404
1052 const new_entry_bb = try ira.getNewBasicBlock(old_entry_bb, null);2405 const new_entry_bb = try ira.getNewBasicBlock(old_entry_bb, null);
1053 new_entry_bb.ref();2406 new_entry_bb.ref(&ira.irb);
10542407
1055 ira.irb.current_basic_block = new_entry_bb;2408 ira.irb.current_basic_block = new_entry_bb;
10562409
...@@ -1064,7 +2417,8 @@ pub async fn analyze(comp: *Compilation, parsed_file: *ParsedFile, old_code: *Co...@@ -1064,7 +2417,8 @@ pub async fn analyze(comp: *Compilation, parsed_file: *ParsedFile, old_code: *Co
1064 continue;2417 continue;
1065 }2418 }
10662419
1067 const return_inst = try old_instruction.analyze(&ira);2420 const return_inst = try await (async old_instruction.analyze(&ira) catch unreachable);
2421 assert(return_inst.val != IrVal.Unknown); // at least the type should be known at this point
1068 return_inst.linkToParent(old_instruction);2422 return_inst.linkToParent(old_instruction);
1069 // Note: if we ever modify the above to handle error.CompileError by continuing analysis,2423 // Note: if we ever modify the above to handle error.CompileError by continuing analysis,
1070 // then here we want to check if ira.isCompTime() and return early if true2424 // then here we want to check if ira.isCompTime() and return early if true
src-self-hosted/libc_installation.zig created+462
...@@ -0,0 +1,462 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const event = std.event;
4const Target = @import("target.zig").Target;
5const c = @import("c.zig");
6
7/// See the render function implementation for documentation of the fields.
8pub const LibCInstallation = struct {
9 include_dir: []const u8,
10 lib_dir: ?[]const u8,
11 static_lib_dir: ?[]const u8,
12 msvc_lib_dir: ?[]const u8,
13 kernel32_lib_dir: ?[]const u8,
14 dynamic_linker_path: ?[]const u8,
15
16 pub const FindError = error{
17 OutOfMemory,
18 FileSystem,
19 UnableToSpawnCCompiler,
20 CCompilerExitCode,
21 CCompilerCrashed,
22 CCompilerCannotFindHeaders,
23 LibCRuntimeNotFound,
24 LibCStdLibHeaderNotFound,
25 LibCKernel32LibNotFound,
26 UnsupportedArchitecture,
27 };
28
29 pub fn parse(
30 self: *LibCInstallation,
31 allocator: *std.mem.Allocator,
32 libc_file: []const u8,
33 stderr: *std.io.OutStream(std.io.FileOutStream.Error),
34 ) !void {
35 self.initEmpty();
36
37 const keys = []const []const u8{
38 "include_dir",
39 "lib_dir",
40 "static_lib_dir",
41 "msvc_lib_dir",
42 "kernel32_lib_dir",
43 "dynamic_linker_path",
44 };
45 const FoundKey = struct {
46 found: bool,
47 allocated: ?[]u8,
48 };
49 var found_keys = [1]FoundKey{FoundKey{ .found = false, .allocated = null }} ** keys.len;
50 errdefer {
51 self.initEmpty();
52 for (found_keys) |found_key| {
53 if (found_key.allocated) |s| allocator.free(s);
54 }
55 }
56
57 const contents = try std.io.readFileAlloc(allocator, libc_file);
58 defer allocator.free(contents);
59
60 var it = std.mem.split(contents, "\n");
61 while (it.next()) |line| {
62 if (line.len == 0 or line[0] == '#') continue;
63 var line_it = std.mem.split(line, "=");
64 const name = line_it.next() orelse {
65 try stderr.print("missing equal sign after field name\n");
66 return error.ParseError;
67 };
68 const value = line_it.rest();
69 inline for (keys) |key, i| {
70 if (std.mem.eql(u8, name, key)) {
71 found_keys[i].found = true;
72 switch (@typeInfo(@typeOf(@field(self, key)))) {
73 builtin.TypeId.Optional => {
74 if (value.len == 0) {
75 @field(self, key) = null;
76 } else {
77 found_keys[i].allocated = try std.mem.dupe(allocator, u8, value);
78 @field(self, key) = found_keys[i].allocated;
79 }
80 },
81 else => {
82 if (value.len == 0) {
83 try stderr.print("field cannot be empty: {}\n", key);
84 return error.ParseError;
85 }
86 const dupe = try std.mem.dupe(allocator, u8, value);
87 found_keys[i].allocated = dupe;
88 @field(self, key) = dupe;
89 },
90 }
91 break;
92 }
93 }
94 }
95 for (found_keys) |found_key, i| {
96 if (!found_key.found) {
97 try stderr.print("missing field: {}\n", keys[i]);
98 return error.ParseError;
99 }
100 }
101 }
102
103 pub fn render(self: *const LibCInstallation, out: *std.io.OutStream(std.io.FileOutStream.Error)) !void {
104 @setEvalBranchQuota(4000);
105 try out.print(
106 \\# The directory that contains `stdlib.h`.
107 \\# On Linux, can be found with: `cc -E -Wp,-v -xc /dev/null`
108 \\include_dir={}
109 \\
110 \\# The directory that contains `crt1.o`.
111 \\# On Linux, can be found with `cc -print-file-name=crt1.o`.
112 \\# Not needed when targeting MacOS.
113 \\lib_dir={}
114 \\
115 \\# The directory that contains `crtbegin.o`.
116 \\# On Linux, can be found with `cc -print-file-name=crtbegin.o`.
117 \\# Not needed when targeting MacOS or Windows.
118 \\static_lib_dir={}
119 \\
120 \\# The directory that contains `vcruntime.lib`.
121 \\# Only needed when targeting Windows.
122 \\msvc_lib_dir={}
123 \\
124 \\# The directory that contains `kernel32.lib`.
125 \\# Only needed when targeting Windows.
126 \\kernel32_lib_dir={}
127 \\
128 \\# The full path to the dynamic linker, on the target system.
129 \\# Only needed when targeting Linux.
130 \\dynamic_linker_path={}
131 \\
132 ,
133 self.include_dir,
134 self.lib_dir orelse "",
135 self.static_lib_dir orelse "",
136 self.msvc_lib_dir orelse "",
137 self.kernel32_lib_dir orelse "",
138 self.dynamic_linker_path orelse Target(Target.Native).getDynamicLinkerPath(),
139 );
140 }
141
142 /// Finds the default, native libc.
143 pub async fn findNative(self: *LibCInstallation, loop: *event.Loop) !void {
144 self.initEmpty();
145 var group = event.Group(FindError!void).init(loop);
146 errdefer group.cancelAll();
147 var windows_sdk: ?*c.ZigWindowsSDK = null;
148 errdefer if (windows_sdk) |sdk| c.zig_free_windows_sdk(@ptrCast(?[*]c.ZigWindowsSDK, sdk));
149
150 switch (builtin.os) {
151 builtin.Os.windows => {
152 var sdk: *c.ZigWindowsSDK = undefined;
153 switch (c.zig_find_windows_sdk(@ptrCast(?[*]?[*]c.ZigWindowsSDK, &sdk))) {
154 c.ZigFindWindowsSdkError.None => {
155 windows_sdk = sdk;
156
157 if (sdk.msvc_lib_dir_ptr) |ptr| {
158 self.msvc_lib_dir = try std.mem.dupe(loop.allocator, u8, ptr[0..sdk.msvc_lib_dir_len]);
159 }
160 try group.call(findNativeKernel32LibDir, self, loop, sdk);
161 try group.call(findNativeIncludeDirWindows, self, loop, sdk);
162 try group.call(findNativeLibDirWindows, self, loop, sdk);
163 },
164 c.ZigFindWindowsSdkError.OutOfMemory => return error.OutOfMemory,
165 c.ZigFindWindowsSdkError.NotFound => return error.NotFound,
166 c.ZigFindWindowsSdkError.PathTooLong => return error.NotFound,
167 }
168 },
169 builtin.Os.linux => {
170 try group.call(findNativeIncludeDirLinux, self, loop);
171 try group.call(findNativeLibDirLinux, self, loop);
172 try group.call(findNativeStaticLibDir, self, loop);
173 try group.call(findNativeDynamicLinker, self, loop);
174 },
175 builtin.Os.macosx => {
176 self.include_dir = try std.mem.dupe(loop.allocator, u8, "/usr/include");
177 },
178 else => @compileError("unimplemented: find libc for this OS"),
179 }
180 return await (async group.wait() catch unreachable);
181 }
182
183 async fn findNativeIncludeDirLinux(self: *LibCInstallation, loop: *event.Loop) !void {
184 const cc_exe = std.os.getEnvPosix("CC") orelse "cc";
185 const argv = []const []const u8{
186 cc_exe,
187 "-E",
188 "-Wp,-v",
189 "-xc",
190 "/dev/null",
191 };
192 // TODO make this use event loop
193 const errorable_result = std.os.ChildProcess.exec(loop.allocator, argv, null, null, 1024 * 1024);
194 const exec_result = if (std.debug.runtime_safety) blk: {
195 break :blk errorable_result catch unreachable;
196 } else blk: {
197 break :blk errorable_result catch |err| switch (err) {
198 error.OutOfMemory => return error.OutOfMemory,
199 else => return error.UnableToSpawnCCompiler,
200 };
201 };
202 defer {
203 loop.allocator.free(exec_result.stdout);
204 loop.allocator.free(exec_result.stderr);
205 }
206
207 switch (exec_result.term) {
208 std.os.ChildProcess.Term.Exited => |code| {
209 if (code != 0) return error.CCompilerExitCode;
210 },
211 else => {
212 return error.CCompilerCrashed;
213 },
214 }
215
216 var it = std.mem.split(exec_result.stderr, "\n\r");
217 var search_paths = std.ArrayList([]const u8).init(loop.allocator);
218 defer search_paths.deinit();
219 while (it.next()) |line| {
220 if (line.len != 0 and line[0] == ' ') {
221 try search_paths.append(line);
222 }
223 }
224 if (search_paths.len == 0) {
225 return error.CCompilerCannotFindHeaders;
226 }
227
228 // search in reverse order
229 var path_i: usize = 0;
230 while (path_i < search_paths.len) : (path_i += 1) {
231 const search_path_untrimmed = search_paths.at(search_paths.len - path_i - 1);
232 const search_path = std.mem.trimLeft(u8, search_path_untrimmed, " ");
233 const stdlib_path = try std.os.path.join(loop.allocator, search_path, "stdlib.h");
234 defer loop.allocator.free(stdlib_path);
235
236 if (try fileExists(loop.allocator, stdlib_path)) {
237 self.include_dir = try std.mem.dupe(loop.allocator, u8, search_path);
238 return;
239 }
240 }
241
242 return error.LibCStdLibHeaderNotFound;
243 }
244
245 async fn findNativeIncludeDirWindows(self: *LibCInstallation, loop: *event.Loop, sdk: *c.ZigWindowsSDK) !void {
246 var search_buf: [2]Search = undefined;
247 const searches = fillSearch(&search_buf, sdk);
248
249 var result_buf = try std.Buffer.initSize(loop.allocator, 0);
250 defer result_buf.deinit();
251
252 for (searches) |search| {
253 result_buf.shrink(0);
254 const stream = &std.io.BufferOutStream.init(&result_buf).stream;
255 try stream.print("{}\\Include\\{}\\ucrt", search.path, search.version);
256
257 const stdlib_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "stdlib.h");
258 defer loop.allocator.free(stdlib_path);
259
260 if (try fileExists(loop.allocator, stdlib_path)) {
261 self.include_dir = result_buf.toOwnedSlice();
262 return;
263 }
264 }
265
266 return error.LibCStdLibHeaderNotFound;
267 }
268
269 async fn findNativeLibDirWindows(self: *LibCInstallation, loop: *event.Loop, sdk: *c.ZigWindowsSDK) FindError!void {
270 var search_buf: [2]Search = undefined;
271 const searches = fillSearch(&search_buf, sdk);
272
273 var result_buf = try std.Buffer.initSize(loop.allocator, 0);
274 defer result_buf.deinit();
275
276 for (searches) |search| {
277 result_buf.shrink(0);
278 const stream = &std.io.BufferOutStream.init(&result_buf).stream;
279 try stream.print("{}\\Lib\\{}\\ucrt\\", search.path, search.version);
280 switch (builtin.arch) {
281 builtin.Arch.i386 => try stream.write("x86"),
282 builtin.Arch.x86_64 => try stream.write("x64"),
283 builtin.Arch.aarch64 => try stream.write("arm"),
284 else => return error.UnsupportedArchitecture,
285 }
286 const ucrt_lib_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "ucrt.lib");
287 defer loop.allocator.free(ucrt_lib_path);
288 if (try fileExists(loop.allocator, ucrt_lib_path)) {
289 self.lib_dir = result_buf.toOwnedSlice();
290 return;
291 }
292 }
293 return error.LibCRuntimeNotFound;
294 }
295
296 async fn findNativeLibDirLinux(self: *LibCInstallation, loop: *event.Loop) FindError!void {
297 self.lib_dir = try await (async ccPrintFileName(loop, "crt1.o", true) catch unreachable);
298 }
299
300 async fn findNativeStaticLibDir(self: *LibCInstallation, loop: *event.Loop) FindError!void {
301 self.static_lib_dir = try await (async ccPrintFileName(loop, "crtbegin.o", true) catch unreachable);
302 }
303
304 async fn findNativeDynamicLinker(self: *LibCInstallation, loop: *event.Loop) FindError!void {
305 var dyn_tests = []DynTest{
306 DynTest{
307 .name = "ld-linux-x86-64.so.2",
308 .result = null,
309 },
310 DynTest{
311 .name = "ld-musl-x86_64.so.1",
312 .result = null,
313 },
314 };
315 var group = event.Group(FindError!void).init(loop);
316 errdefer group.cancelAll();
317 for (dyn_tests) |*dyn_test| {
318 try group.call(testNativeDynamicLinker, self, loop, dyn_test);
319 }
320 try await (async group.wait() catch unreachable);
321 for (dyn_tests) |*dyn_test| {
322 if (dyn_test.result) |result| {
323 self.dynamic_linker_path = result;
324 return;
325 }
326 }
327 }
328
329 const DynTest = struct {
330 name: []const u8,
331 result: ?[]const u8,
332 };
333
334 async fn testNativeDynamicLinker(self: *LibCInstallation, loop: *event.Loop, dyn_test: *DynTest) FindError!void {
335 if (await (async ccPrintFileName(loop, dyn_test.name, false) catch unreachable)) |result| {
336 dyn_test.result = result;
337 return;
338 } else |err| switch (err) {
339 error.LibCRuntimeNotFound => return,
340 else => return err,
341 }
342 }
343
344
345 async fn findNativeKernel32LibDir(self: *LibCInstallation, loop: *event.Loop, sdk: *c.ZigWindowsSDK) FindError!void {
346 var search_buf: [2]Search = undefined;
347 const searches = fillSearch(&search_buf, sdk);
348
349 var result_buf = try std.Buffer.initSize(loop.allocator, 0);
350 defer result_buf.deinit();
351
352 for (searches) |search| {
353 result_buf.shrink(0);
354 const stream = &std.io.BufferOutStream.init(&result_buf).stream;
355 try stream.print("{}\\Lib\\{}\\um\\", search.path, search.version);
356 switch (builtin.arch) {
357 builtin.Arch.i386 => try stream.write("x86\\"),
358 builtin.Arch.x86_64 => try stream.write("x64\\"),
359 builtin.Arch.aarch64 => try stream.write("arm\\"),
360 else => return error.UnsupportedArchitecture,
361 }
362 const kernel32_path = try std.os.path.join(loop.allocator, result_buf.toSliceConst(), "kernel32.lib");
363 defer loop.allocator.free(kernel32_path);
364 if (try fileExists(loop.allocator, kernel32_path)) {
365 self.kernel32_lib_dir = result_buf.toOwnedSlice();
366 return;
367 }
368 }
369 return error.LibCKernel32LibNotFound;
370 }
371
372 fn initEmpty(self: *LibCInstallation) void {
373 self.* = LibCInstallation{
374 .include_dir = ([*]const u8)(undefined)[0..0],
375 .lib_dir = null,
376 .static_lib_dir = null,
377 .msvc_lib_dir = null,
378 .kernel32_lib_dir = null,
379 .dynamic_linker_path = null,
380 };
381 }
382};
383
384/// caller owns returned memory
385async fn ccPrintFileName(loop: *event.Loop, o_file: []const u8, want_dirname: bool) ![]u8 {
386 const cc_exe = std.os.getEnvPosix("CC") orelse "cc";
387 const arg1 = try std.fmt.allocPrint(loop.allocator, "-print-file-name={}", o_file);
388 defer loop.allocator.free(arg1);
389 const argv = []const []const u8{ cc_exe, arg1 };
390
391 // TODO This simulates evented I/O for the child process exec
392 await (async loop.yield() catch unreachable);
393 const errorable_result = std.os.ChildProcess.exec(loop.allocator, argv, null, null, 1024 * 1024);
394 const exec_result = if (std.debug.runtime_safety) blk: {
395 break :blk errorable_result catch unreachable;
396 } else blk: {
397 break :blk errorable_result catch |err| switch (err) {
398 error.OutOfMemory => return error.OutOfMemory,
399 else => return error.UnableToSpawnCCompiler,
400 };
401 };
402 defer {
403 loop.allocator.free(exec_result.stdout);
404 loop.allocator.free(exec_result.stderr);
405 }
406 switch (exec_result.term) {
407 std.os.ChildProcess.Term.Exited => |code| {
408 if (code != 0) return error.CCompilerExitCode;
409 },
410 else => {
411 return error.CCompilerCrashed;
412 },
413 }
414 var it = std.mem.split(exec_result.stdout, "\n\r");
415 const line = it.next() orelse return error.LibCRuntimeNotFound;
416 const dirname = std.os.path.dirname(line) orelse return error.LibCRuntimeNotFound;
417
418 if (want_dirname) {
419 return std.mem.dupe(loop.allocator, u8, dirname);
420 } else {
421 return std.mem.dupe(loop.allocator, u8, line);
422 }
423}
424
425const Search = struct {
426 path: []const u8,
427 version: []const u8,
428};
429
430fn fillSearch(search_buf: *[2]Search, sdk: *c.ZigWindowsSDK) []Search {
431 var search_end: usize = 0;
432 if (sdk.path10_ptr) |path10_ptr| {
433 if (sdk.version10_ptr) |ver10_ptr| {
434 search_buf[search_end] = Search{
435 .path = path10_ptr[0..sdk.path10_len],
436 .version = ver10_ptr[0..sdk.version10_len],
437 };
438 search_end += 1;
439 }
440 }
441 if (sdk.path81_ptr) |path81_ptr| {
442 if (sdk.version81_ptr) |ver81_ptr| {
443 search_buf[search_end] = Search{
444 .path = path81_ptr[0..sdk.path81_len],
445 .version = ver81_ptr[0..sdk.version81_len],
446 };
447 search_end += 1;
448 }
449 }
450 return search_buf[0..search_end];
451}
452
453
454fn fileExists(allocator: *std.mem.Allocator, path: []const u8) !bool {
455 if (std.os.File.access(allocator, path)) |_| {
456 return true;
457 } else |err| switch (err) {
458 error.NotFound, error.PermissionDenied => return false,
459 error.OutOfMemory => return error.OutOfMemory,
460 else => return error.FileSystem,
461 }
462}
src-self-hosted/link.zig+494-84
...@@ -1,8 +1,12 @@...@@ -1,8 +1,12 @@
1const std = @import("std");1const std = @import("std");
2const mem = std.mem;
2const c = @import("c.zig");3const c = @import("c.zig");
3const builtin = @import("builtin");4const builtin = @import("builtin");
4const ObjectFormat = builtin.ObjectFormat;5const ObjectFormat = builtin.ObjectFormat;
5const Compilation = @import("compilation.zig").Compilation;6const Compilation = @import("compilation.zig").Compilation;
7const Target = @import("target.zig").Target;
8const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
9const assert = std.debug.assert;
610
7const Context = struct {11const Context = struct {
8 comp: *Compilation,12 comp: *Compilation,
...@@ -12,9 +16,12 @@ const Context = struct {...@@ -12,9 +16,12 @@ const Context = struct {
1216
13 link_err: error{OutOfMemory}!void,17 link_err: error{OutOfMemory}!void,
14 link_msg: std.Buffer,18 link_msg: std.Buffer,
19
20 libc: *LibCInstallation,
21 out_file_path: std.Buffer,
15};22};
1623
17pub fn link(comp: *Compilation) !void {24pub async fn link(comp: *Compilation) !void {
18 var ctx = Context{25 var ctx = Context{
19 .comp = comp,26 .comp = comp,
20 .arena = std.heap.ArenaAllocator.init(comp.gpa()),27 .arena = std.heap.ArenaAllocator.init(comp.gpa()),
...@@ -22,15 +29,45 @@ pub fn link(comp: *Compilation) !void {...@@ -22,15 +29,45 @@ pub fn link(comp: *Compilation) !void {
22 .link_in_crt = comp.haveLibC() and comp.kind == Compilation.Kind.Exe,29 .link_in_crt = comp.haveLibC() and comp.kind == Compilation.Kind.Exe,
23 .link_err = {},30 .link_err = {},
24 .link_msg = undefined,31 .link_msg = undefined,
32 .libc = undefined,
33 .out_file_path = undefined,
25 };34 };
26 defer ctx.arena.deinit();35 defer ctx.arena.deinit();
27 ctx.args = std.ArrayList([*]const u8).init(&ctx.arena.allocator);36 ctx.args = std.ArrayList([*]const u8).init(&ctx.arena.allocator);
28 ctx.link_msg = std.Buffer.initNull(&ctx.arena.allocator);37 ctx.link_msg = std.Buffer.initNull(&ctx.arena.allocator);
2938
39 if (comp.link_out_file) |out_file| {
40 ctx.out_file_path = try std.Buffer.init(&ctx.arena.allocator, out_file);
41 } else {
42 ctx.out_file_path = try std.Buffer.init(&ctx.arena.allocator, comp.name.toSliceConst());
43 switch (comp.kind) {
44 Compilation.Kind.Exe => {
45 try ctx.out_file_path.append(comp.target.exeFileExt());
46 },
47 Compilation.Kind.Lib => {
48 try ctx.out_file_path.append(comp.target.libFileExt(comp.is_static));
49 },
50 Compilation.Kind.Obj => {
51 try ctx.out_file_path.append(comp.target.objFileExt());
52 },
53 }
54 }
55
30 // even though we're calling LLD as a library it thinks the first56 // even though we're calling LLD as a library it thinks the first
31 // argument is its own exe name57 // argument is its own exe name
32 try ctx.args.append(c"lld");58 try ctx.args.append(c"lld");
3359
60 if (comp.haveLibC()) {
61 ctx.libc = ctx.comp.override_libc orelse blk: {
62 switch (comp.target) {
63 Target.Native => {
64 break :blk (await (async comp.event_loop_local.getNativeLibC() catch unreachable)) catch return error.LibCRequiredButNotProvidedOrFound;
65 },
66 else => return error.LibCRequiredButNotProvidedOrFound,
67 }
68 };
69 }
70
34 try constructLinkerArgs(&ctx);71 try constructLinkerArgs(&ctx);
3572
36 if (comp.verbose_link) {73 if (comp.verbose_link) {
...@@ -43,6 +80,7 @@ pub fn link(comp: *Compilation) !void {...@@ -43,6 +80,7 @@ pub fn link(comp: *Compilation) !void {
4380
44 const extern_ofmt = toExternObjectFormatType(comp.target.getObjectFormat());81 const extern_ofmt = toExternObjectFormatType(comp.target.getObjectFormat());
45 const args_slice = ctx.args.toSlice();82 const args_slice = ctx.args.toSlice();
83 // Not evented I/O. LLD does its own multithreading internally.
46 if (!ZigLLDLink(extern_ofmt, args_slice.ptr, args_slice.len, linkDiagCallback, @ptrCast(*c_void, &ctx))) {84 if (!ZigLLDLink(extern_ofmt, args_slice.ptr, args_slice.len, linkDiagCallback, @ptrCast(*c_void, &ctx))) {
47 if (!ctx.link_msg.isNull()) {85 if (!ctx.link_msg.isNull()) {
48 // TODO capture these messages and pass them through the system, reporting them through the86 // TODO capture these messages and pass them through the system, reporting them through the
...@@ -95,10 +133,7 @@ fn constructLinkerArgs(ctx: *Context) !void {...@@ -95,10 +133,7 @@ fn constructLinkerArgs(ctx: *Context) !void {
95}133}
96134
97fn constructLinkerArgsElf(ctx: *Context) !void {135fn constructLinkerArgsElf(ctx: *Context) !void {
98 //if (g->libc_link_lib != nullptr) {136 // TODO commented out code in this function
99 // find_libc_lib_path(g);
100 //}
101
102 //if (g->linker_script) {137 //if (g->linker_script) {
103 // lj->args.append("-T");138 // lj->args.append("-T");
104 // lj->args.append(g->linker_script);139 // lj->args.append(g->linker_script);
...@@ -107,7 +142,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -107,7 +142,7 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
107 //if (g->no_rosegment_workaround) {142 //if (g->no_rosegment_workaround) {
108 // lj->args.append("--no-rosegment");143 // lj->args.append("--no-rosegment");
109 //}144 //}
110 //lj->args.append("--gc-sections");145 try ctx.args.append(c"--gc-sections");
111146
112 //lj->args.append("-m");147 //lj->args.append("-m");
113 //lj->args.append(getLDMOption(&g->zig_target));148 //lj->args.append(getLDMOption(&g->zig_target));
...@@ -115,14 +150,13 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -115,14 +150,13 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
115 //bool is_lib = g->out_type == OutTypeLib;150 //bool is_lib = g->out_type == OutTypeLib;
116 //bool shared = !g->is_static && is_lib;151 //bool shared = !g->is_static && is_lib;
117 //Buf *soname = nullptr;152 //Buf *soname = nullptr;
118 //if (g->is_static) {153 if (ctx.comp.is_static) {
119 // if (g->zig_target.arch.arch == ZigLLVM_arm || g->zig_target.arch.arch == ZigLLVM_armeb ||154 if (ctx.comp.target.isArmOrThumb()) {
120 // g->zig_target.arch.arch == ZigLLVM_thumb || g->zig_target.arch.arch == ZigLLVM_thumbeb)155 try ctx.args.append(c"-Bstatic");
121 // {156 } else {
122 // lj->args.append("-Bstatic");157 try ctx.args.append(c"-static");
123 // } else {158 }
124 // lj->args.append("-static");159 }
125 // }
126 //} else if (shared) {160 //} else if (shared) {
127 // lj->args.append("-shared");161 // lj->args.append("-shared");
128162
...@@ -133,23 +167,16 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -133,23 +167,16 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
133 // soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize "", buf_ptr(g->root_out_name), g->version_major);167 // soname = buf_sprintf("lib%s.so.%" ZIG_PRI_usize "", buf_ptr(g->root_out_name), g->version_major);
134 //}168 //}
135169
136 //lj->args.append("-o");170 try ctx.args.append(c"-o");
137 //lj->args.append(buf_ptr(&lj->out_file));171 try ctx.args.append(ctx.out_file_path.ptr());
138172
139 //if (lj->link_in_crt) {173 if (ctx.link_in_crt) {
140 // const char *crt1o;174 const crt1o = if (ctx.comp.is_static) "crt1.o" else "Scrt1.o";
141 // const char *crtbegino;175 const crtbegino = if (ctx.comp.is_static) "crtbeginT.o" else "crtbegin.o";
142 // if (g->is_static) {176 try addPathJoin(ctx, ctx.libc.lib_dir.?, crt1o);
143 // crt1o = "crt1.o";177 try addPathJoin(ctx, ctx.libc.lib_dir.?, "crti.o");
144 // crtbegino = "crtbeginT.o";178 try addPathJoin(ctx, ctx.libc.static_lib_dir.?, crtbegino);
145 // } else {179 }
146 // crt1o = "Scrt1.o";
147 // crtbegino = "crtbegin.o";
148 // }
149 // lj->args.append(get_libc_file(g, crt1o));
150 // lj->args.append(get_libc_file(g, "crti.o"));
151 // lj->args.append(get_libc_static_file(g, crtbegino));
152 //}
153180
154 //for (size_t i = 0; i < g->rpath_list.length; i += 1) {181 //for (size_t i = 0; i < g->rpath_list.length; i += 1) {
155 // Buf *rpath = g->rpath_list.at(i);182 // Buf *rpath = g->rpath_list.at(i);
...@@ -182,25 +209,23 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -182,25 +209,23 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
182 // lj->args.append(lib_dir);209 // lj->args.append(lib_dir);
183 //}210 //}
184211
185 //if (g->libc_link_lib != nullptr) {212 if (ctx.comp.haveLibC()) {
186 // lj->args.append("-L");213 try ctx.args.append(c"-L");
187 // lj->args.append(buf_ptr(g->libc_lib_dir));214 try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.lib_dir.?)).ptr);
188215
189 // lj->args.append("-L");216 try ctx.args.append(c"-L");
190 // lj->args.append(buf_ptr(g->libc_static_lib_dir));217 try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, ctx.libc.static_lib_dir.?)).ptr);
191 //}218
192219 if (!ctx.comp.is_static) {
193 //if (!g->is_static) {220 const dl = blk: {
194 // if (g->dynamic_linker != nullptr) {221 if (ctx.libc.dynamic_linker_path) |dl| break :blk dl;
195 // assert(buf_len(g->dynamic_linker) != 0);222 if (ctx.comp.target.getDynamicLinkerPath()) |dl| break :blk dl;
196 // lj->args.append("-dynamic-linker");223 return error.LibCMissingDynamicLinker;
197 // lj->args.append(buf_ptr(g->dynamic_linker));224 };
198 // } else {225 try ctx.args.append(c"-dynamic-linker");
199 // Buf *resolved_dynamic_linker = get_dynamic_linker_path(g);226 try ctx.args.append((try std.cstr.addNullByte(&ctx.arena.allocator, dl)).ptr);
200 // lj->args.append("-dynamic-linker");227 }
201 // lj->args.append(buf_ptr(resolved_dynamic_linker));228 }
202 // }
203 //}
204229
205 //if (shared) {230 //if (shared) {
206 // lj->args.append("-soname");231 // lj->args.append("-soname");
...@@ -241,53 +266,356 @@ fn constructLinkerArgsElf(ctx: *Context) !void {...@@ -241,53 +266,356 @@ fn constructLinkerArgsElf(ctx: *Context) !void {
241 // lj->args.append(buf_ptr(arg));266 // lj->args.append(buf_ptr(arg));
242 //}267 //}
243268
244 //// libc dep269 // libc dep
245 //if (g->libc_link_lib != nullptr) {270 if (ctx.comp.haveLibC()) {
246 // if (g->is_static) {271 if (ctx.comp.is_static) {
247 // lj->args.append("--start-group");272 try ctx.args.append(c"--start-group");
248 // lj->args.append("-lgcc");273 try ctx.args.append(c"-lgcc");
249 // lj->args.append("-lgcc_eh");274 try ctx.args.append(c"-lgcc_eh");
250 // lj->args.append("-lc");275 try ctx.args.append(c"-lc");
251 // lj->args.append("-lm");276 try ctx.args.append(c"-lm");
252 // lj->args.append("--end-group");277 try ctx.args.append(c"--end-group");
278 } else {
279 try ctx.args.append(c"-lgcc");
280 try ctx.args.append(c"--as-needed");
281 try ctx.args.append(c"-lgcc_s");
282 try ctx.args.append(c"--no-as-needed");
283 try ctx.args.append(c"-lc");
284 try ctx.args.append(c"-lm");
285 try ctx.args.append(c"-lgcc");
286 try ctx.args.append(c"--as-needed");
287 try ctx.args.append(c"-lgcc_s");
288 try ctx.args.append(c"--no-as-needed");
289 }
290 }
291
292 // crt end
293 if (ctx.link_in_crt) {
294 try addPathJoin(ctx, ctx.libc.static_lib_dir.?, "crtend.o");
295 try addPathJoin(ctx, ctx.libc.lib_dir.?, "crtn.o");
296 }
297
298 if (ctx.comp.target != Target.Native) {
299 try ctx.args.append(c"--allow-shlib-undefined");
300 }
301
302 if (ctx.comp.target.getOs() == builtin.Os.zen) {
303 try ctx.args.append(c"-e");
304 try ctx.args.append(c"_start");
305
306 try ctx.args.append(c"--image-base=0x10000000");
307 }
308}
309
310fn addPathJoin(ctx: *Context, dirname: []const u8, basename: []const u8) !void {
311 const full_path = try std.os.path.join(&ctx.arena.allocator, dirname, basename);
312 const full_path_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, full_path);
313 try ctx.args.append(full_path_with_null.ptr);
314}
315
316fn constructLinkerArgsCoff(ctx: *Context) !void {
317 try ctx.args.append(c"-NOLOGO");
318
319 if (!ctx.comp.strip) {
320 try ctx.args.append(c"-DEBUG");
321 }
322
323 switch (ctx.comp.target.getArch()) {
324 builtin.Arch.i386 => try ctx.args.append(c"-MACHINE:X86"),
325 builtin.Arch.x86_64 => try ctx.args.append(c"-MACHINE:X64"),
326 builtin.Arch.aarch64 => try ctx.args.append(c"-MACHINE:ARM"),
327 else => return error.UnsupportedLinkArchitecture,
328 }
329
330 if (ctx.comp.windows_subsystem_windows) {
331 try ctx.args.append(c"/SUBSYSTEM:windows");
332 } else if (ctx.comp.windows_subsystem_console) {
333 try ctx.args.append(c"/SUBSYSTEM:console");
334 }
335
336 const is_library = ctx.comp.kind == Compilation.Kind.Lib;
337
338 const out_arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-OUT:{}\x00", ctx.out_file_path.toSliceConst());
339 try ctx.args.append(out_arg.ptr);
340
341 if (ctx.comp.haveLibC()) {
342 try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.msvc_lib_dir.?)).ptr);
343 try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.kernel32_lib_dir.?)).ptr);
344 try ctx.args.append((try std.fmt.allocPrint(&ctx.arena.allocator, "-LIBPATH:{}\x00", ctx.libc.lib_dir.?)).ptr);
345 }
346
347 if (ctx.link_in_crt) {
348 const lib_str = if (ctx.comp.is_static) "lib" else "";
349 const d_str = if (ctx.comp.build_mode == builtin.Mode.Debug) "d" else "";
350
351 if (ctx.comp.is_static) {
352 const cmt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "libcmt{}.lib\x00", d_str);
353 try ctx.args.append(cmt_lib_name.ptr);
354 } else {
355 const msvcrt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "msvcrt{}.lib\x00", d_str);
356 try ctx.args.append(msvcrt_lib_name.ptr);
357 }
358
359 const vcruntime_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}vcruntime{}.lib\x00", lib_str, d_str);
360 try ctx.args.append(vcruntime_lib_name.ptr);
361
362 const crt_lib_name = try std.fmt.allocPrint(&ctx.arena.allocator, "{}ucrt{}.lib\x00", lib_str, d_str);
363 try ctx.args.append(crt_lib_name.ptr);
364
365 // Visual C++ 2015 Conformance Changes
366 // https://msdn.microsoft.com/en-us/library/bb531344.aspx
367 try ctx.args.append(c"legacy_stdio_definitions.lib");
368
369 // msvcrt depends on kernel32
370 try ctx.args.append(c"kernel32.lib");
371 } else {
372 try ctx.args.append(c"-NODEFAULTLIB");
373 if (!is_library) {
374 try ctx.args.append(c"-ENTRY:WinMainCRTStartup");
375 // TODO
376 //if (g->have_winmain) {
377 // lj->args.append("-ENTRY:WinMain");
378 //} else {
379 // lj->args.append("-ENTRY:WinMainCRTStartup");
380 //}
381 }
382 }
383
384 if (is_library and !ctx.comp.is_static) {
385 try ctx.args.append(c"-DLL");
386 }
387
388 //for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
389 // const char *lib_dir = g->lib_dirs.at(i);
390 // lj->args.append(buf_ptr(buf_sprintf("-LIBPATH:%s", lib_dir)));
391 //}
392
393 for (ctx.comp.link_objects) |link_object| {
394 const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object);
395 try ctx.args.append(link_obj_with_null.ptr);
396 }
397 try addFnObjects(ctx);
398
399 switch (ctx.comp.kind) {
400 Compilation.Kind.Exe, Compilation.Kind.Lib => {
401 if (!ctx.comp.haveLibC()) {
402 @panic("TODO");
403 //Buf *builtin_o_path = build_o(g, "builtin");
404 //lj->args.append(buf_ptr(builtin_o_path));
405 }
406
407 // msvc compiler_rt is missing some stuff, so we still build it and rely on weak linkage
408 // TODO
409 //Buf *compiler_rt_o_path = build_compiler_rt(g);
410 //lj->args.append(buf_ptr(compiler_rt_o_path));
411 },
412 Compilation.Kind.Obj => {},
413 }
414
415 //Buf *def_contents = buf_alloc();
416 //ZigList<const char *> gen_lib_args = {0};
417 //for (size_t lib_i = 0; lib_i < g->link_libs_list.length; lib_i += 1) {
418 // LinkLib *link_lib = g->link_libs_list.at(lib_i);
419 // if (buf_eql_str(link_lib->name, "c")) {
420 // continue;
421 // }
422 // if (link_lib->provided_explicitly) {
423 // if (lj->codegen->zig_target.env_type == ZigLLVM_GNU) {
424 // Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
425 // lj->args.append(buf_ptr(arg));
426 // }
427 // else {
428 // lj->args.append(buf_ptr(link_lib->name));
429 // }
253 // } else {430 // } else {
254 // lj->args.append("-lgcc");431 // buf_resize(def_contents, 0);
255 // lj->args.append("--as-needed");432 // buf_appendf(def_contents, "LIBRARY %s\nEXPORTS\n", buf_ptr(link_lib->name));
256 // lj->args.append("-lgcc_s");433 // for (size_t exp_i = 0; exp_i < link_lib->symbols.length; exp_i += 1) {
257 // lj->args.append("--no-as-needed");434 // Buf *symbol_name = link_lib->symbols.at(exp_i);
258 // lj->args.append("-lc");435 // buf_appendf(def_contents, "%s\n", buf_ptr(symbol_name));
259 // lj->args.append("-lm");436 // }
260 // lj->args.append("-lgcc");437 // buf_appendf(def_contents, "\n");
261 // lj->args.append("--as-needed");438
262 // lj->args.append("-lgcc_s");439 // Buf *def_path = buf_alloc();
263 // lj->args.append("--no-as-needed");440 // os_path_join(g->cache_dir, buf_sprintf("%s.def", buf_ptr(link_lib->name)), def_path);
441 // os_write_file(def_path, def_contents);
442
443 // Buf *generated_lib_path = buf_alloc();
444 // os_path_join(g->cache_dir, buf_sprintf("%s.lib", buf_ptr(link_lib->name)), generated_lib_path);
445
446 // gen_lib_args.resize(0);
447 // gen_lib_args.append("link");
448
449 // coff_append_machine_arg(g, &gen_lib_args);
450 // gen_lib_args.append(buf_ptr(buf_sprintf("-DEF:%s", buf_ptr(def_path))));
451 // gen_lib_args.append(buf_ptr(buf_sprintf("-OUT:%s", buf_ptr(generated_lib_path))));
452 // Buf diag = BUF_INIT;
453 // if (!zig_lld_link(g->zig_target.oformat, gen_lib_args.items, gen_lib_args.length, &diag)) {
454 // fprintf(stderr, "%s\n", buf_ptr(&diag));
455 // exit(1);
456 // }
457 // lj->args.append(buf_ptr(generated_lib_path));
264 // }458 // }
265 //}459 //}
460}
461
462fn constructLinkerArgsMachO(ctx: *Context) !void {
463 try ctx.args.append(c"-demangle");
464
465 if (ctx.comp.linker_rdynamic) {
466 try ctx.args.append(c"-export_dynamic");
467 }
468
469 const is_lib = ctx.comp.kind == Compilation.Kind.Lib;
470 const shared = !ctx.comp.is_static and is_lib;
471 if (ctx.comp.is_static) {
472 try ctx.args.append(c"-static");
473 } else {
474 try ctx.args.append(c"-dynamic");
475 }
476
477 //if (is_lib) {
478 // if (!g->is_static) {
479 // lj->args.append("-dylib");
480
481 // Buf *compat_vers = buf_sprintf("%" ZIG_PRI_usize ".0.0", g->version_major);
482 // lj->args.append("-compatibility_version");
483 // lj->args.append(buf_ptr(compat_vers));
484
485 // Buf *cur_vers = buf_sprintf("%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize,
486 // g->version_major, g->version_minor, g->version_patch);
487 // lj->args.append("-current_version");
488 // lj->args.append(buf_ptr(cur_vers));
266489
267 //// crt end490 // // TODO getting an error when running an executable when doing this rpath thing
268 //if (lj->link_in_crt) {491 // //Buf *dylib_install_name = buf_sprintf("@rpath/lib%s.%" ZIG_PRI_usize ".dylib",
269 // lj->args.append(get_libc_static_file(g, "crtend.o"));492 // // buf_ptr(g->root_out_name), g->version_major);
270 // lj->args.append(get_libc_file(g, "crtn.o"));493 // //lj->args.append("-install_name");
494 // //lj->args.append(buf_ptr(dylib_install_name));
495
496 // if (buf_len(&lj->out_file) == 0) {
497 // buf_appendf(&lj->out_file, "lib%s.%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".%" ZIG_PRI_usize ".dylib",
498 // buf_ptr(g->root_out_name), g->version_major, g->version_minor, g->version_patch);
499 // }
500 // }
271 //}501 //}
272502
273 //if (!g->is_native_target) {503 try ctx.args.append(c"-arch");
274 // lj->args.append("--allow-shlib-undefined");504 const darwin_arch_str = try std.cstr.addNullByte(
505 &ctx.arena.allocator,
506 ctx.comp.target.getDarwinArchString(),
507 );
508 try ctx.args.append(darwin_arch_str.ptr);
509
510 const platform = try DarwinPlatform.get(ctx.comp);
511 switch (platform.kind) {
512 DarwinPlatform.Kind.MacOS => try ctx.args.append(c"-macosx_version_min"),
513 DarwinPlatform.Kind.IPhoneOS => try ctx.args.append(c"-iphoneos_version_min"),
514 DarwinPlatform.Kind.IPhoneOSSimulator => try ctx.args.append(c"-ios_simulator_version_min"),
515 }
516 const ver_str = try std.fmt.allocPrint(&ctx.arena.allocator, "{}.{}.{}\x00", platform.major, platform.minor, platform.micro);
517 try ctx.args.append(ver_str.ptr);
518
519 if (ctx.comp.kind == Compilation.Kind.Exe) {
520 if (ctx.comp.is_static) {
521 try ctx.args.append(c"-no_pie");
522 } else {
523 try ctx.args.append(c"-pie");
524 }
525 }
526
527 try ctx.args.append(c"-o");
528 try ctx.args.append(ctx.out_file_path.ptr());
529
530 //for (size_t i = 0; i < g->rpath_list.length; i += 1) {
531 // Buf *rpath = g->rpath_list.at(i);
532 // add_rpath(lj, rpath);
275 //}533 //}
534 //add_rpath(lj, &lj->out_file);
535
536 if (shared) {
537 try ctx.args.append(c"-headerpad_max_install_names");
538 } else if (ctx.comp.is_static) {
539 try ctx.args.append(c"-lcrt0.o");
540 } else {
541 switch (platform.kind) {
542 DarwinPlatform.Kind.MacOS => {
543 if (platform.versionLessThan(10, 5)) {
544 try ctx.args.append(c"-lcrt1.o");
545 } else if (platform.versionLessThan(10, 6)) {
546 try ctx.args.append(c"-lcrt1.10.5.o");
547 } else if (platform.versionLessThan(10, 8)) {
548 try ctx.args.append(c"-lcrt1.10.6.o");
549 }
550 },
551 DarwinPlatform.Kind.IPhoneOS => {
552 if (ctx.comp.target.getArch() == builtin.Arch.aarch64) {
553 // iOS does not need any crt1 files for arm64
554 } else if (platform.versionLessThan(3, 1)) {
555 try ctx.args.append(c"-lcrt1.o");
556 } else if (platform.versionLessThan(6, 0)) {
557 try ctx.args.append(c"-lcrt1.3.1.o");
558 }
559 },
560 DarwinPlatform.Kind.IPhoneOSSimulator => {}, // no crt1.o needed
561 }
562 }
276563
277 //if (g->zig_target.os == OsZen) {564 //for (size_t i = 0; i < g->lib_dirs.length; i += 1) {
278 // lj->args.append("-e");565 // const char *lib_dir = g->lib_dirs.at(i);
279 // lj->args.append("_start");566 // lj->args.append("-L");
567 // lj->args.append(lib_dir);
568 //}
280569
281 // lj->args.append("--image-base=0x10000000");570 for (ctx.comp.link_objects) |link_object| {
571 const link_obj_with_null = try std.cstr.addNullByte(&ctx.arena.allocator, link_object);
572 try ctx.args.append(link_obj_with_null.ptr);
573 }
574 try addFnObjects(ctx);
575
576 //// compiler_rt on darwin is missing some stuff, so we still build it and rely on LinkOnce
577 //if (g->out_type == OutTypeExe || g->out_type == OutTypeLib) {
578 // Buf *compiler_rt_o_path = build_compiler_rt(g);
579 // lj->args.append(buf_ptr(compiler_rt_o_path));
282 //}580 //}
283}
284581
285fn constructLinkerArgsCoff(ctx: *Context) void {582 if (ctx.comp.target == Target.Native) {
286 @panic("TODO");583 for (ctx.comp.link_libs_list.toSliceConst()) |lib| {
287}584 if (mem.eql(u8, lib.name, "c")) {
585 // on Darwin, libSystem has libc in it, but also you have to use it
586 // to make syscalls because the syscall numbers are not documented
587 // and change between versions.
588 // so we always link against libSystem
589 try ctx.args.append(c"-lSystem");
590 } else {
591 if (mem.indexOfScalar(u8, lib.name, '/') == null) {
592 const arg = try std.fmt.allocPrint(&ctx.arena.allocator, "-l{}\x00", lib.name);
593 try ctx.args.append(arg.ptr);
594 } else {
595 const arg = try std.cstr.addNullByte(&ctx.arena.allocator, lib.name);
596 try ctx.args.append(arg.ptr);
597 }
598 }
599 }
600 } else {
601 try ctx.args.append(c"-undefined");
602 try ctx.args.append(c"dynamic_lookup");
603 }
288604
289fn constructLinkerArgsMachO(ctx: *Context) void {605 if (platform.kind == DarwinPlatform.Kind.MacOS) {
290 @panic("TODO");606 if (platform.versionLessThan(10, 5)) {
607 try ctx.args.append(c"-lgcc_s.10.4");
608 } else if (platform.versionLessThan(10, 6)) {
609 try ctx.args.append(c"-lgcc_s.10.5");
610 }
611 } else {
612 @panic("TODO");
613 }
614
615 //for (size_t i = 0; i < g->darwin_frameworks.length; i += 1) {
616 // lj->args.append("-framework");
617 // lj->args.append(buf_ptr(g->darwin_frameworks.at(i)));
618 //}
291}619}
292620
293fn constructLinkerArgsWasm(ctx: *Context) void {621fn constructLinkerArgsWasm(ctx: *Context) void {
...@@ -312,3 +640,85 @@ fn addFnObjects(ctx: *Context) !void {...@@ -312,3 +640,85 @@ fn addFnObjects(ctx: *Context) !void {
312 it = node.next;640 it = node.next;
313 }641 }
314}642}
643
644const DarwinPlatform = struct {
645 kind: Kind,
646 major: u32,
647 minor: u32,
648 micro: u32,
649
650 const Kind = enum {
651 MacOS,
652 IPhoneOS,
653 IPhoneOSSimulator,
654 };
655
656 fn get(comp: *Compilation) !DarwinPlatform {
657 var result: DarwinPlatform = undefined;
658 const ver_str = switch (comp.darwin_version_min) {
659 Compilation.DarwinVersionMin.MacOS => |ver| blk: {
660 result.kind = Kind.MacOS;
661 break :blk ver;
662 },
663 Compilation.DarwinVersionMin.Ios => |ver| blk: {
664 result.kind = Kind.IPhoneOS;
665 break :blk ver;
666 },
667 Compilation.DarwinVersionMin.None => blk: {
668 assert(comp.target.getOs() == builtin.Os.macosx);
669 result.kind = Kind.MacOS;
670 break :blk "10.10";
671 },
672 };
673
674 var had_extra: bool = undefined;
675 try darwinGetReleaseVersion(ver_str, &result.major, &result.minor, &result.micro, &had_extra,);
676 if (had_extra or result.major != 10 or result.minor >= 100 or result.micro >= 100) {
677 return error.InvalidDarwinVersionString;
678 }
679
680 if (result.kind == Kind.IPhoneOS) {
681 switch (comp.target.getArch()) {
682 builtin.Arch.i386,
683 builtin.Arch.x86_64,
684 => result.kind = Kind.IPhoneOSSimulator,
685 else => {},
686 }
687 }
688 return result;
689 }
690
691 fn versionLessThan(self: DarwinPlatform, major: u32, minor: u32) bool {
692 if (self.major < major)
693 return true;
694 if (self.major > major)
695 return false;
696 if (self.minor < minor)
697 return true;
698 return false;
699 }
700};
701
702/// Parse (([0-9]+)(.([0-9]+)(.([0-9]+)?))?)? and return the
703/// grouped values as integers. Numbers which are not provided are set to 0.
704/// return true if the entire string was parsed (9.2), or all groups were
705/// parsed (10.3.5extrastuff).
706fn darwinGetReleaseVersion(str: []const u8, major: *u32, minor: *u32, micro: *u32, had_extra: *bool) !void {
707 major.* = 0;
708 minor.* = 0;
709 micro.* = 0;
710 had_extra.* = false;
711
712 if (str.len == 0)
713 return error.InvalidDarwinVersionString;
714
715 var start_pos: usize = 0;
716 for ([]*u32{major, minor, micro}) |v| {
717 const dot_pos = mem.indexOfScalarPos(u8, str, start_pos, '.');
718 const end_pos = dot_pos orelse str.len;
719 v.* = std.fmt.parseUnsigned(u32, str[start_pos..end_pos], 10) catch return error.InvalidDarwinVersionString;
720 start_pos = (dot_pos orelse return) + 1;
721 if (start_pos == str.len) return;
722 }
723 had_extra.* = true;
724}
src-self-hosted/llvm.zig+39-1
...@@ -23,13 +23,20 @@ pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef);...@@ -23,13 +23,20 @@ pub const TargetMachineRef = removeNullability(c.LLVMTargetMachineRef);
23pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef);23pub const TargetDataRef = removeNullability(c.LLVMTargetDataRef);
24pub const DIBuilder = c.ZigLLVMDIBuilder;24pub const DIBuilder = c.ZigLLVMDIBuilder;
2525
26pub const ABIAlignmentOfType = c.LLVMABIAlignmentOfType;
26pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;27pub const AddAttributeAtIndex = c.LLVMAddAttributeAtIndex;
27pub const AddFunction = c.LLVMAddFunction;28pub const AddFunction = c.LLVMAddFunction;
29pub const AddGlobal = c.LLVMAddGlobal;
28pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;30pub const AddModuleCodeViewFlag = c.ZigLLVMAddModuleCodeViewFlag;
29pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;31pub const AddModuleDebugInfoFlag = c.ZigLLVMAddModuleDebugInfoFlag;
32pub const ArrayType = c.LLVMArrayType;
30pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;33pub const ClearCurrentDebugLocation = c.ZigLLVMClearCurrentDebugLocation;
31pub const ConstAllOnes = c.LLVMConstAllOnes;34pub const ConstAllOnes = c.LLVMConstAllOnes;
35pub const ConstArray = c.LLVMConstArray;
36pub const ConstBitCast = c.LLVMConstBitCast;
32pub const ConstInt = c.LLVMConstInt;37pub const ConstInt = c.LLVMConstInt;
38pub const ConstIntOfArbitraryPrecision = c.LLVMConstIntOfArbitraryPrecision;
39pub const ConstNeg = c.LLVMConstNeg;
33pub const ConstNull = c.LLVMConstNull;40pub const ConstNull = c.LLVMConstNull;
34pub const ConstStringInContext = c.LLVMConstStringInContext;41pub const ConstStringInContext = c.LLVMConstStringInContext;
35pub const ConstStructInContext = c.LLVMConstStructInContext;42pub const ConstStructInContext = c.LLVMConstStructInContext;
...@@ -57,6 +64,7 @@ pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;...@@ -57,6 +64,7 @@ pub const GetEnumAttributeKindForName = c.LLVMGetEnumAttributeKindForName;
57pub const GetHostCPUName = c.ZigLLVMGetHostCPUName;64pub const GetHostCPUName = c.ZigLLVMGetHostCPUName;
58pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;65pub const GetMDKindIDInContext = c.LLVMGetMDKindIDInContext;
59pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures;66pub const GetNativeFeatures = c.ZigLLVMGetNativeFeatures;
67pub const GetUndef = c.LLVMGetUndef;
60pub const HalfTypeInContext = c.LLVMHalfTypeInContext;68pub const HalfTypeInContext = c.LLVMHalfTypeInContext;
61pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;69pub const InitializeAllAsmParsers = c.LLVMInitializeAllAsmParsers;
62pub const InitializeAllAsmPrinters = c.LLVMInitializeAllAsmPrinters;70pub const InitializeAllAsmPrinters = c.LLVMInitializeAllAsmPrinters;
...@@ -79,14 +87,24 @@ pub const MDStringInContext = c.LLVMMDStringInContext;...@@ -79,14 +87,24 @@ pub const MDStringInContext = c.LLVMMDStringInContext;
79pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;87pub const MetadataTypeInContext = c.LLVMMetadataTypeInContext;
80pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;88pub const ModuleCreateWithNameInContext = c.LLVMModuleCreateWithNameInContext;
81pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;89pub const PPCFP128TypeInContext = c.LLVMPPCFP128TypeInContext;
90pub const PointerType = c.LLVMPointerType;
91pub const SetAlignment = c.LLVMSetAlignment;
82pub const SetDataLayout = c.LLVMSetDataLayout;92pub const SetDataLayout = c.LLVMSetDataLayout;
93pub const SetGlobalConstant = c.LLVMSetGlobalConstant;
94pub const SetInitializer = c.LLVMSetInitializer;
95pub const SetLinkage = c.LLVMSetLinkage;
83pub const SetTarget = c.LLVMSetTarget;96pub const SetTarget = c.LLVMSetTarget;
97pub const SetUnnamedAddr = c.LLVMSetUnnamedAddr;
84pub const StructTypeInContext = c.LLVMStructTypeInContext;98pub const StructTypeInContext = c.LLVMStructTypeInContext;
85pub const TokenTypeInContext = c.LLVMTokenTypeInContext;99pub const TokenTypeInContext = c.LLVMTokenTypeInContext;
100pub const TypeOf = c.LLVMTypeOf;
86pub const VoidTypeInContext = c.LLVMVoidTypeInContext;101pub const VoidTypeInContext = c.LLVMVoidTypeInContext;
87pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;102pub const X86FP80TypeInContext = c.LLVMX86FP80TypeInContext;
88pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;103pub const X86MMXTypeInContext = c.LLVMX86MMXTypeInContext;
89104
105pub const ConstInBoundsGEP = LLVMConstInBoundsGEP;
106pub extern fn LLVMConstInBoundsGEP(ConstantVal: ValueRef, ConstantIndices: [*]ValueRef, NumIndices: c_uint) ?ValueRef;
107
90pub const GetTargetFromTriple = LLVMGetTargetFromTriple;108pub const GetTargetFromTriple = LLVMGetTargetFromTriple;
91extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool;109extern fn LLVMGetTargetFromTriple(Triple: [*]const u8, T: *TargetRef, ErrorMessage: ?*[*]u8) Bool;
92110
...@@ -143,13 +161,28 @@ pub const EmitBinary = EmitOutputType.ZigLLVM_EmitBinary;...@@ -143,13 +161,28 @@ pub const EmitBinary = EmitOutputType.ZigLLVM_EmitBinary;
143pub const EmitLLVMIr = EmitOutputType.ZigLLVM_EmitLLVMIr;161pub const EmitLLVMIr = EmitOutputType.ZigLLVM_EmitLLVMIr;
144pub const EmitOutputType = c.ZigLLVM_EmitOutputType;162pub const EmitOutputType = c.ZigLLVM_EmitOutputType;
145163
164pub const CCallConv = c.LLVMCCallConv;
165pub const FastCallConv = c.LLVMFastCallConv;
166pub const ColdCallConv = c.LLVMColdCallConv;
167pub const WebKitJSCallConv = c.LLVMWebKitJSCallConv;
168pub const AnyRegCallConv = c.LLVMAnyRegCallConv;
169pub const X86StdcallCallConv = c.LLVMX86StdcallCallConv;
170pub const X86FastcallCallConv = c.LLVMX86FastcallCallConv;
171pub const CallConv = c.LLVMCallConv;
172
173pub const FnInline = extern enum {
174 Auto,
175 Always,
176 Never,
177};
178
146fn removeNullability(comptime T: type) type {179fn removeNullability(comptime T: type) type {
147 comptime assert(@typeId(T) == builtin.TypeId.Optional);180 comptime assert(@typeId(T) == builtin.TypeId.Optional);
148 return T.Child;181 return T.Child;
149}182}
150183
151pub const BuildRet = LLVMBuildRet;184pub const BuildRet = LLVMBuildRet;
152extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ValueRef;185extern fn LLVMBuildRet(arg0: BuilderRef, V: ?ValueRef) ?ValueRef;
153186
154pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;187pub const TargetMachineEmitToFile = ZigLLVMTargetMachineEmitToFile;
155extern fn ZigLLVMTargetMachineEmitToFile(188extern fn ZigLLVMTargetMachineEmitToFile(
...@@ -161,3 +194,8 @@ extern fn ZigLLVMTargetMachineEmitToFile(...@@ -161,3 +194,8 @@ extern fn ZigLLVMTargetMachineEmitToFile(
161 is_debug: bool,194 is_debug: bool,
162 is_small: bool,195 is_small: bool,
163) bool;196) bool;
197
198pub const BuildCall = ZigLLVMBuildCall;
199extern fn ZigLLVMBuildCall(B: BuilderRef, Fn: ValueRef, Args: [*]ValueRef, NumArgs: c_uint, CC: c_uint, fn_inline: FnInline, Name: [*]const u8) ?ValueRef;
200
201pub const PrivateLinkage = c.LLVMLinkage.LLVMPrivateLinkage;
src-self-hosted/main.zig+82-57
...@@ -18,6 +18,7 @@ const EventLoopLocal = @import("compilation.zig").EventLoopLocal;...@@ -18,6 +18,7 @@ const EventLoopLocal = @import("compilation.zig").EventLoopLocal;
18const Compilation = @import("compilation.zig").Compilation;18const Compilation = @import("compilation.zig").Compilation;
19const Target = @import("target.zig").Target;19const Target = @import("target.zig").Target;
20const errmsg = @import("errmsg.zig");20const errmsg = @import("errmsg.zig");
21const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
2122
22var stderr_file: os.File = undefined;23var stderr_file: os.File = undefined;
23var stderr: *io.OutStream(io.FileOutStream.Error) = undefined;24var stderr: *io.OutStream(io.FileOutStream.Error) = undefined;
...@@ -28,13 +29,14 @@ const usage =...@@ -28,13 +29,14 @@ const usage =
28 \\29 \\
29 \\Commands:30 \\Commands:
30 \\31 \\
31 \\ build-exe [source] Create executable from source or object files32 \\ build-exe [source] Create executable from source or object files
32 \\ build-lib [source] Create library from source or object files33 \\ build-lib [source] Create library from source or object files
33 \\ build-obj [source] Create object from source or assembly34 \\ build-obj [source] Create object from source or assembly
34 \\ fmt [source] Parse file and render in canonical zig format35 \\ fmt [source] Parse file and render in canonical zig format
35 \\ targets List available compilation targets36 \\ libc [paths_file] Display native libc paths file or validate one
36 \\ version Print version number and exit37 \\ targets List available compilation targets
37 \\ zen Print zen of zig and exit38 \\ version Print version number and exit
39 \\ zen Print zen of zig and exit
38 \\40 \\
39 \\41 \\
40;42;
...@@ -85,6 +87,10 @@ pub fn main() !void {...@@ -85,6 +87,10 @@ pub fn main() !void {
85 .name = "fmt",87 .name = "fmt",
86 .exec = cmdFmt,88 .exec = cmdFmt,
87 },89 },
90 Command{
91 .name = "libc",
92 .exec = cmdLibC,
93 },
88 Command{94 Command{
89 .name = "targets",95 .name = "targets",
90 .exec = cmdTargets,96 .exec = cmdTargets,
...@@ -130,11 +136,10 @@ const usage_build_generic =...@@ -130,11 +136,10 @@ const usage_build_generic =
130 \\ --color [auto|off|on] Enable or disable colored error messages136 \\ --color [auto|off|on] Enable or disable colored error messages
131 \\137 \\
132 \\Compile Options:138 \\Compile Options:
139 \\ --libc [file] Provide a file which specifies libc paths
133 \\ --assembly [source] Add assembly file to build140 \\ --assembly [source] Add assembly file to build
134 \\ --cache-dir [path] Override the cache directory
135 \\ --emit [filetype] Emit a specific file format as compilation output141 \\ --emit [filetype] Emit a specific file format as compilation output
136 \\ --enable-timing-info Print timing diagnostics142 \\ --enable-timing-info Print timing diagnostics
137 \\ --libc-include-dir [path] Directory where libc stdlib.h resides
138 \\ --name [name] Override output name143 \\ --name [name] Override output name
139 \\ --output [file] Override destination path144 \\ --output [file] Override destination path
140 \\ --output-h [file] Override generated header file path145 \\ --output-h [file] Override generated header file path
...@@ -163,12 +168,7 @@ const usage_build_generic =...@@ -163,12 +168,7 @@ const usage_build_generic =
163 \\168 \\
164 \\Link Options:169 \\Link Options:
165 \\ --ar-path [path] Set the path to ar170 \\ --ar-path [path] Set the path to ar
166 \\ --dynamic-linker [path] Set the path to ld.so
167 \\ --each-lib-rpath Add rpath for each used dynamic library171 \\ --each-lib-rpath Add rpath for each used dynamic library
168 \\ --libc-lib-dir [path] Directory where libc crt1.o resides
169 \\ --libc-static-lib-dir [path] Directory where libc crtbegin.o resides
170 \\ --msvc-lib-dir [path] (windows) directory where vcruntime.lib resides
171 \\ --kernel32-lib-dir [path] (windows) directory where kernel32.lib resides
172 \\ --library [lib] Link against lib172 \\ --library [lib] Link against lib
173 \\ --forbid-library [lib] Make it an error to link against lib173 \\ --forbid-library [lib] Make it an error to link against lib
174 \\ --library-path [dir] Add a directory to the library search path174 \\ --library-path [dir] Add a directory to the library search path
...@@ -203,14 +203,13 @@ const args_build_generic = []Flag{...@@ -203,14 +203,13 @@ const args_build_generic = []Flag{
203 }),203 }),
204204
205 Flag.ArgMergeN("--assembly", 1),205 Flag.ArgMergeN("--assembly", 1),
206 Flag.Arg1("--cache-dir"),
207 Flag.Option("--emit", []const []const u8{206 Flag.Option("--emit", []const []const u8{
208 "asm",207 "asm",
209 "bin",208 "bin",
210 "llvm-ir",209 "llvm-ir",
211 }),210 }),
212 Flag.Bool("--enable-timing-info"),211 Flag.Bool("--enable-timing-info"),
213 Flag.Arg1("--libc-include-dir"),212 Flag.Arg1("--libc"),
214 Flag.Arg1("--name"),213 Flag.Arg1("--name"),
215 Flag.Arg1("--output"),214 Flag.Arg1("--output"),
216 Flag.Arg1("--output-h"),215 Flag.Arg1("--output-h"),
...@@ -234,12 +233,7 @@ const args_build_generic = []Flag{...@@ -234,12 +233,7 @@ const args_build_generic = []Flag{
234 Flag.Arg1("-mllvm"),233 Flag.Arg1("-mllvm"),
235234
236 Flag.Arg1("--ar-path"),235 Flag.Arg1("--ar-path"),
237 Flag.Arg1("--dynamic-linker"),
238 Flag.Bool("--each-lib-rpath"),236 Flag.Bool("--each-lib-rpath"),
239 Flag.Arg1("--libc-lib-dir"),
240 Flag.Arg1("--libc-static-lib-dir"),
241 Flag.Arg1("--msvc-lib-dir"),
242 Flag.Arg1("--kernel32-lib-dir"),
243 Flag.ArgMergeN("--library", 1),237 Flag.ArgMergeN("--library", 1),
244 Flag.ArgMergeN("--forbid-library", 1),238 Flag.ArgMergeN("--forbid-library", 1),
245 Flag.ArgMergeN("--library-path", 1),239 Flag.ArgMergeN("--library-path", 1),
...@@ -377,16 +371,11 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -377,16 +371,11 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
377 os.exit(1);371 os.exit(1);
378 }372 }
379373
380 const rel_cache_dir = flags.single("cache-dir") orelse "zig-cache"[0..];
381 const full_cache_dir = os.path.resolve(allocator, ".", rel_cache_dir) catch {
382 try stderr.print("invalid cache dir: {}\n", rel_cache_dir);
383 os.exit(1);
384 };
385 defer allocator.free(full_cache_dir);
386
387 const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch os.exit(1);374 const zig_lib_dir = introspect.resolveZigLibDir(allocator) catch os.exit(1);
388 defer allocator.free(zig_lib_dir);375 defer allocator.free(zig_lib_dir);
389376
377 var override_libc: LibCInstallation = undefined;
378
390 var loop: event.Loop = undefined;379 var loop: event.Loop = undefined;
391 try loop.initMultiThreaded(allocator);380 try loop.initMultiThreaded(allocator);
392 defer loop.deinit();381 defer loop.deinit();
...@@ -403,10 +392,18 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -403,10 +392,18 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
403 build_mode,392 build_mode,
404 is_static,393 is_static,
405 zig_lib_dir,394 zig_lib_dir,
406 full_cache_dir,
407 );395 );
408 defer comp.destroy();396 defer comp.destroy();
409397
398 if (flags.single("libc")) |libc_path| {
399 parseLibcPaths(loop.allocator, &override_libc, libc_path);
400 comp.override_libc = &override_libc;
401 }
402
403 for (flags.many("library")) |lib| {
404 _ = try comp.addLinkLib(lib, true);
405 }
406
410 comp.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") orelse "0", 10);407 comp.version_major = try std.fmt.parseUnsigned(u32, flags.single("ver-major") orelse "0", 10);
411 comp.version_minor = try std.fmt.parseUnsigned(u32, flags.single("ver-minor") orelse "0", 10);408 comp.version_minor = try std.fmt.parseUnsigned(u32, flags.single("ver-minor") orelse "0", 10);
412 comp.version_patch = try std.fmt.parseUnsigned(u32, flags.single("ver-patch") orelse "0", 10);409 comp.version_patch = try std.fmt.parseUnsigned(u32, flags.single("ver-patch") orelse "0", 10);
...@@ -430,25 +427,6 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -430,25 +427,6 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
430427
431 comp.strip = flags.present("strip");428 comp.strip = flags.present("strip");
432429
433 if (flags.single("libc-lib-dir")) |libc_lib_dir| {
434 comp.libc_lib_dir = libc_lib_dir;
435 }
436 if (flags.single("libc-static-lib-dir")) |libc_static_lib_dir| {
437 comp.libc_static_lib_dir = libc_static_lib_dir;
438 }
439 if (flags.single("libc-include-dir")) |libc_include_dir| {
440 comp.libc_include_dir = libc_include_dir;
441 }
442 if (flags.single("msvc-lib-dir")) |msvc_lib_dir| {
443 comp.msvc_lib_dir = msvc_lib_dir;
444 }
445 if (flags.single("kernel32-lib-dir")) |kernel32_lib_dir| {
446 comp.kernel32_lib_dir = kernel32_lib_dir;
447 }
448 if (flags.single("dynamic-linker")) |dynamic_linker| {
449 comp.dynamic_linker = dynamic_linker;
450 }
451
452 comp.verbose_tokenize = flags.present("verbose-tokenize");430 comp.verbose_tokenize = flags.present("verbose-tokenize");
453 comp.verbose_ast_tree = flags.present("verbose-ast-tree");431 comp.verbose_ast_tree = flags.present("verbose-ast-tree");
454 comp.verbose_ast_fmt = flags.present("verbose-ast-fmt");432 comp.verbose_ast_fmt = flags.present("verbose-ast-fmt");
...@@ -484,7 +462,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co...@@ -484,7 +462,7 @@ fn buildOutputType(allocator: *Allocator, args: []const []const u8, out_type: Co
484462
485 comp.emit_file_type = emit_type;463 comp.emit_file_type = emit_type;
486 comp.assembly_files = assembly_files;464 comp.assembly_files = assembly_files;
487 comp.link_out_file = flags.single("out-file");465 comp.link_out_file = flags.single("output");
488 comp.link_objects = link_objects;466 comp.link_objects = link_objects;
489467
490 try comp.build();468 try comp.build();
...@@ -499,7 +477,6 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {...@@ -499,7 +477,6 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
499477
500 switch (build_event) {478 switch (build_event) {
501 Compilation.Event.Ok => {479 Compilation.Event.Ok => {
502 std.debug.warn("Build succeeded\n");
503 return;480 return;
504 },481 },
505 Compilation.Event.Error => |err| {482 Compilation.Event.Error => |err| {
...@@ -508,7 +485,8 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {...@@ -508,7 +485,8 @@ async fn processBuildEvents(comp: *Compilation, color: errmsg.Color) void {
508 },485 },
509 Compilation.Event.Fail => |msgs| {486 Compilation.Event.Fail => |msgs| {
510 for (msgs) |msg| {487 for (msgs) |msg| {
511 errmsg.printToFile(&stderr_file, msg, color) catch os.exit(1);488 defer msg.destroy();
489 msg.printToFile(&stderr_file, color) catch os.exit(1);
512 }490 }
513 },491 },
514 }492 }
...@@ -579,6 +557,53 @@ const Fmt = struct {...@@ -579,6 +557,53 @@ const Fmt = struct {
579 }557 }
580};558};
581559
560fn parseLibcPaths(allocator: *Allocator, libc: *LibCInstallation, libc_paths_file: []const u8) void {
561 libc.parse(allocator, libc_paths_file, stderr) catch |err| {
562 stderr.print(
563 "Unable to parse libc path file '{}': {}.\n" ++
564 "Try running `zig libc` to see an example for the native target.\n",
565 libc_paths_file,
566 @errorName(err),
567 ) catch os.exit(1);
568 os.exit(1);
569 };
570}
571
572fn cmdLibC(allocator: *Allocator, args: []const []const u8) !void {
573 switch (args.len) {
574 0 => {},
575 1 => {
576 var libc_installation: LibCInstallation = undefined;
577 parseLibcPaths(allocator, &libc_installation, args[0]);
578 return;
579 },
580 else => {
581 try stderr.print("unexpected extra parameter: {}\n", args[1]);
582 os.exit(1);
583 },
584 }
585
586 var loop: event.Loop = undefined;
587 try loop.initMultiThreaded(allocator);
588 defer loop.deinit();
589
590 var event_loop_local = try EventLoopLocal.init(&loop);
591 defer event_loop_local.deinit();
592
593 const handle = try async<loop.allocator> findLibCAsync(&event_loop_local);
594 defer cancel handle;
595
596 loop.run();
597}
598
599async fn findLibCAsync(event_loop_local: *EventLoopLocal) void {
600 const libc = (await (async event_loop_local.getNativeLibC() catch unreachable)) catch |err| {
601 stderr.print("unable to find libc: {}\n", @errorName(err)) catch os.exit(1);
602 os.exit(1);
603 };
604 libc.render(stdout) catch os.exit(1);
605}
606
582fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {607fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
583 var flags = try Args.parse(allocator, args_fmt_spec, args);608 var flags = try Args.parse(allocator, args_fmt_spec, args);
584 defer flags.deinit();609 defer flags.deinit();
...@@ -622,10 +647,10 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -622,10 +647,10 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
622647
623 var error_it = tree.errors.iterator(0);648 var error_it = tree.errors.iterator(0);
624 while (error_it.next()) |parse_error| {649 while (error_it.next()) |parse_error| {
625 const msg = try errmsg.createFromParseError(allocator, parse_error, &tree, "<stdin>");650 const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, "<stdin>");
626 defer allocator.destroy(msg);651 defer msg.destroy();
627652
628 try errmsg.printToFile(&stderr_file, msg, color);653 try msg.printToFile(&stderr_file, color);
629 }654 }
630 if (tree.errors.len != 0) {655 if (tree.errors.len != 0) {
631 os.exit(1);656 os.exit(1);
...@@ -678,10 +703,10 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {...@@ -678,10 +703,10 @@ fn cmdFmt(allocator: *Allocator, args: []const []const u8) !void {
678703
679 var error_it = tree.errors.iterator(0);704 var error_it = tree.errors.iterator(0);
680 while (error_it.next()) |parse_error| {705 while (error_it.next()) |parse_error| {
681 const msg = try errmsg.createFromParseError(allocator, parse_error, &tree, file_path);706 const msg = try errmsg.Msg.createFromParseError(allocator, parse_error, &tree, file_path);
682 defer allocator.destroy(msg);707 defer msg.destroy();
683708
684 try errmsg.printToFile(&stderr_file, msg, color);709 try msg.printToFile(&stderr_file, color);
685 }710 }
686 if (tree.errors.len != 0) {711 if (tree.errors.len != 0) {
687 fmt.any_error = true;712 fmt.any_error = true;
src-self-hosted/parsed_file.zig deleted-6
...@@ -1,6 +0,0 @@
1const ast = @import("std").zig.ast;
2
3pub const ParsedFile = struct {
4 tree: ast.Tree,
5 realpath: []const u8,
6};
src-self-hosted/scope.zig+100-25
...@@ -8,6 +8,8 @@ const ast = std.zig.ast;...@@ -8,6 +8,8 @@ const ast = std.zig.ast;
8const Value = @import("value.zig").Value;8const Value = @import("value.zig").Value;
9const ir = @import("ir.zig");9const ir = @import("ir.zig");
10const Span = @import("errmsg.zig").Span;10const Span = @import("errmsg.zig").Span;
11const assert = std.debug.assert;
12const event = std.event;
1113
12pub const Scope = struct {14pub const Scope = struct {
13 id: Id,15 id: Id,
...@@ -23,7 +25,8 @@ pub const Scope = struct {...@@ -23,7 +25,8 @@ pub const Scope = struct {
23 if (base.ref_count == 0) {25 if (base.ref_count == 0) {
24 if (base.parent) |parent| parent.deref(comp);26 if (base.parent) |parent| parent.deref(comp);
25 switch (base.id) {27 switch (base.id) {
26 Id.Decls => @fieldParentPtr(Decls, "base", base).destroy(),28 Id.Root => @fieldParentPtr(Root, "base", base).destroy(comp),
29 Id.Decls => @fieldParentPtr(Decls, "base", base).destroy(comp),
27 Id.Block => @fieldParentPtr(Block, "base", base).destroy(comp),30 Id.Block => @fieldParentPtr(Block, "base", base).destroy(comp),
28 Id.FnDef => @fieldParentPtr(FnDef, "base", base).destroy(comp),31 Id.FnDef => @fieldParentPtr(FnDef, "base", base).destroy(comp),
29 Id.CompTime => @fieldParentPtr(CompTime, "base", base).destroy(comp),32 Id.CompTime => @fieldParentPtr(CompTime, "base", base).destroy(comp),
...@@ -33,6 +36,15 @@ pub const Scope = struct {...@@ -33,6 +36,15 @@ pub const Scope = struct {
33 }36 }
34 }37 }
3538
39 pub fn findRoot(base: *Scope) *Root {
40 var scope = base;
41 while (scope.parent) |parent| {
42 scope = parent;
43 }
44 assert(scope.id == Id.Root);
45 return @fieldParentPtr(Root, "base", scope);
46 }
47
36 pub fn findFnDef(base: *Scope) ?*FnDef {48 pub fn findFnDef(base: *Scope) ?*FnDef {
37 var scope = base;49 var scope = base;
38 while (true) {50 while (true) {
...@@ -44,12 +56,33 @@ pub const Scope = struct {...@@ -44,12 +56,33 @@ pub const Scope = struct {
44 Id.Defer,56 Id.Defer,
45 Id.DeferExpr,57 Id.DeferExpr,
46 Id.CompTime,58 Id.CompTime,
59 Id.Root,
60 => scope = scope.parent orelse return null,
61 }
62 }
63 }
64
65 pub fn findDeferExpr(base: *Scope) ?*DeferExpr {
66 var scope = base;
67 while (true) {
68 switch (scope.id) {
69 Id.DeferExpr => return @fieldParentPtr(DeferExpr, "base", base),
70
71 Id.FnDef,
72 Id.Decls,
73 => return null,
74
75 Id.Block,
76 Id.Defer,
77 Id.CompTime,
78 Id.Root,
47 => scope = scope.parent orelse return null,79 => scope = scope.parent orelse return null,
48 }80 }
49 }81 }
50 }82 }
5183
52 pub const Id = enum {84 pub const Id = enum {
85 Root,
53 Decls,86 Decls,
54 Block,87 Block,
55 FnDef,88 FnDef,
...@@ -58,42 +91,82 @@ pub const Scope = struct {...@@ -58,42 +91,82 @@ pub const Scope = struct {
58 DeferExpr,91 DeferExpr,
59 };92 };
6093
94 pub const Root = struct {
95 base: Scope,
96 tree: *ast.Tree,
97 realpath: []const u8,
98
99 /// Creates a Root scope with 1 reference
100 /// Takes ownership of realpath
101 /// Takes ownership of tree, will deinit and destroy when done.
102 pub fn create(comp: *Compilation, tree: *ast.Tree, realpath: []u8) !*Root {
103 const self = try comp.gpa().create(Root{
104 .base = Scope{
105 .id = Id.Root,
106 .parent = null,
107 .ref_count = 1,
108 },
109 .tree = tree,
110 .realpath = realpath,
111 });
112 errdefer comp.gpa().destroy(self);
113
114 return self;
115 }
116
117 pub fn destroy(self: *Root, comp: *Compilation) void {
118 comp.gpa().free(self.tree.source);
119 self.tree.deinit();
120 comp.gpa().destroy(self.tree);
121 comp.gpa().free(self.realpath);
122 comp.gpa().destroy(self);
123 }
124 };
125
61 pub const Decls = struct {126 pub const Decls = struct {
62 base: Scope,127 base: Scope,
63 table: Decl.Table,128
129 /// The lock must be respected for writing. However once name_future resolves,
130 /// readers can freely access it.
131 table: event.Locked(Decl.Table),
132
133 /// Once this future is resolved, the table is complete and available for unlocked
134 /// read-only access. It does not mean all the decls are resolved; it means only that
135 /// the table has all the names. Each decl in the table has its own resolution state.
136 name_future: event.Future(void),
64137
65 /// Creates a Decls scope with 1 reference138 /// Creates a Decls scope with 1 reference
66 pub fn create(comp: *Compilation, parent: ?*Scope) !*Decls {139 pub fn create(comp: *Compilation, parent: *Scope) !*Decls {
67 const self = try comp.gpa().create(Decls{140 const self = try comp.gpa().create(Decls{
68 .base = Scope{141 .base = Scope{
69 .id = Id.Decls,142 .id = Id.Decls,
70 .parent = parent,143 .parent = parent,
71 .ref_count = 1,144 .ref_count = 1,
72 },145 },
73 .table = undefined,146 .table = event.Locked(Decl.Table).init(comp.loop, Decl.Table.init(comp.gpa())),
147 .name_future = event.Future(void).init(comp.loop),
74 });148 });
75 errdefer comp.gpa().destroy(self);149 parent.ref();
76
77 self.table = Decl.Table.init(comp.gpa());
78 errdefer self.table.deinit();
79
80 if (parent) |p| p.ref();
81
82 return self;150 return self;
83 }151 }
84152
85 pub fn destroy(self: *Decls) void {153 pub fn destroy(self: *Decls, comp: *Compilation) void {
86 self.table.deinit();154 self.table.deinit();
87 self.table.allocator.destroy(self);155 comp.gpa().destroy(self);
156 }
157
158 pub async fn getTableReadOnly(self: *Decls) *Decl.Table {
159 _ = await (async self.name_future.get() catch unreachable);
160 return &self.table.private_data;
88 }161 }
89 };162 };
90163
91 pub const Block = struct {164 pub const Block = struct {
92 base: Scope,165 base: Scope,
93 incoming_values: std.ArrayList(*ir.Instruction),166 incoming_values: std.ArrayList(*ir.Inst),
94 incoming_blocks: std.ArrayList(*ir.BasicBlock),167 incoming_blocks: std.ArrayList(*ir.BasicBlock),
95 end_block: *ir.BasicBlock,168 end_block: *ir.BasicBlock,
96 is_comptime: *ir.Instruction,169 is_comptime: *ir.Inst,
97170
98 safety: Safety,171 safety: Safety,
99172
...@@ -125,7 +198,7 @@ pub const Scope = struct {...@@ -125,7 +198,7 @@ pub const Scope = struct {
125 };198 };
126199
127 /// Creates a Block scope with 1 reference200 /// Creates a Block scope with 1 reference
128 pub fn create(comp: *Compilation, parent: ?*Scope) !*Block {201 pub fn create(comp: *Compilation, parent: *Scope) !*Block {
129 const self = try comp.gpa().create(Block{202 const self = try comp.gpa().create(Block{
130 .base = Scope{203 .base = Scope{
131 .id = Id.Block,204 .id = Id.Block,
...@@ -140,7 +213,7 @@ pub const Scope = struct {...@@ -140,7 +213,7 @@ pub const Scope = struct {
140 });213 });
141 errdefer comp.gpa().destroy(self);214 errdefer comp.gpa().destroy(self);
142215
143 if (parent) |p| p.ref();216 parent.ref();
144 return self;217 return self;
145 }218 }
146219
...@@ -157,7 +230,7 @@ pub const Scope = struct {...@@ -157,7 +230,7 @@ pub const Scope = struct {
157230
158 /// Creates a FnDef scope with 1 reference231 /// Creates a FnDef scope with 1 reference
159 /// Must set the fn_val later232 /// Must set the fn_val later
160 pub fn create(comp: *Compilation, parent: ?*Scope) !*FnDef {233 pub fn create(comp: *Compilation, parent: *Scope) !*FnDef {
161 const self = try comp.gpa().create(FnDef{234 const self = try comp.gpa().create(FnDef{
162 .base = Scope{235 .base = Scope{
163 .id = Id.FnDef,236 .id = Id.FnDef,
...@@ -167,7 +240,7 @@ pub const Scope = struct {...@@ -167,7 +240,7 @@ pub const Scope = struct {
167 .fn_val = undefined,240 .fn_val = undefined,
168 });241 });
169242
170 if (parent) |p| p.ref();243 parent.ref();
171244
172 return self;245 return self;
173 }246 }
...@@ -181,7 +254,7 @@ pub const Scope = struct {...@@ -181,7 +254,7 @@ pub const Scope = struct {
181 base: Scope,254 base: Scope,
182255
183 /// Creates a CompTime scope with 1 reference256 /// Creates a CompTime scope with 1 reference
184 pub fn create(comp: *Compilation, parent: ?*Scope) !*CompTime {257 pub fn create(comp: *Compilation, parent: *Scope) !*CompTime {
185 const self = try comp.gpa().create(CompTime{258 const self = try comp.gpa().create(CompTime{
186 .base = Scope{259 .base = Scope{
187 .id = Id.CompTime,260 .id = Id.CompTime,
...@@ -190,7 +263,7 @@ pub const Scope = struct {...@@ -190,7 +263,7 @@ pub const Scope = struct {
190 },263 },
191 });264 });
192265
193 if (parent) |p| p.ref();266 parent.ref();
194 return self;267 return self;
195 }268 }
196269
...@@ -212,7 +285,7 @@ pub const Scope = struct {...@@ -212,7 +285,7 @@ pub const Scope = struct {
212 /// Creates a Defer scope with 1 reference285 /// Creates a Defer scope with 1 reference
213 pub fn create(286 pub fn create(
214 comp: *Compilation,287 comp: *Compilation,
215 parent: ?*Scope,288 parent: *Scope,
216 kind: Kind,289 kind: Kind,
217 defer_expr_scope: *DeferExpr,290 defer_expr_scope: *DeferExpr,
218 ) !*Defer {291 ) !*Defer {
...@@ -229,7 +302,7 @@ pub const Scope = struct {...@@ -229,7 +302,7 @@ pub const Scope = struct {
229302
230 defer_expr_scope.base.ref();303 defer_expr_scope.base.ref();
231304
232 if (parent) |p| p.ref();305 parent.ref();
233 return self;306 return self;
234 }307 }
235308
...@@ -242,9 +315,10 @@ pub const Scope = struct {...@@ -242,9 +315,10 @@ pub const Scope = struct {
242 pub const DeferExpr = struct {315 pub const DeferExpr = struct {
243 base: Scope,316 base: Scope,
244 expr_node: *ast.Node,317 expr_node: *ast.Node,
318 reported_err: bool,
245319
246 /// Creates a DeferExpr scope with 1 reference320 /// Creates a DeferExpr scope with 1 reference
247 pub fn create(comp: *Compilation, parent: ?*Scope, expr_node: *ast.Node) !*DeferExpr {321 pub fn create(comp: *Compilation, parent: *Scope, expr_node: *ast.Node) !*DeferExpr {
248 const self = try comp.gpa().create(DeferExpr{322 const self = try comp.gpa().create(DeferExpr{
249 .base = Scope{323 .base = Scope{
250 .id = Id.DeferExpr,324 .id = Id.DeferExpr,
...@@ -252,10 +326,11 @@ pub const Scope = struct {...@@ -252,10 +326,11 @@ pub const Scope = struct {
252 .ref_count = 1,326 .ref_count = 1,
253 },327 },
254 .expr_node = expr_node,328 .expr_node = expr_node,
329 .reported_err = false,
255 });330 });
256 errdefer comp.gpa().destroy(self);331 errdefer comp.gpa().destroy(self);
257332
258 if (parent) |p| p.ref();333 parent.ref();
259 return self;334 return self;
260 }335 }
261336
src-self-hosted/target.zig+445-1
...@@ -1,6 +1,13 @@...@@ -1,6 +1,13 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const llvm = @import("llvm.zig");3const llvm = @import("llvm.zig");
4const CInt = @import("c_int.zig").CInt;
5
6pub const FloatAbi = enum {
7 Hard,
8 Soft,
9 SoftFp,
10};
411
5pub const Target = union(enum) {12pub const Target = union(enum) {
6 Native,13 Native,
...@@ -13,7 +20,7 @@ pub const Target = union(enum) {...@@ -13,7 +20,7 @@ pub const Target = union(enum) {
13 object_format: builtin.ObjectFormat,20 object_format: builtin.ObjectFormat,
14 };21 };
1522
16 pub fn oFileExt(self: Target) []const u8 {23 pub fn objFileExt(self: Target) []const u8 {
17 return switch (self.getObjectFormat()) {24 return switch (self.getObjectFormat()) {
18 builtin.ObjectFormat.coff => ".obj",25 builtin.ObjectFormat.coff => ".obj",
19 else => ".o",26 else => ".o",
...@@ -27,6 +34,13 @@ pub const Target = union(enum) {...@@ -27,6 +34,13 @@ pub const Target = union(enum) {
27 };34 };
28 }35 }
2936
37 pub fn libFileExt(self: Target, is_static: bool) []const u8 {
38 return switch (self.getOs()) {
39 builtin.Os.windows => if (is_static) ".lib" else ".dll",
40 else => if (is_static) ".a" else ".so",
41 };
42 }
43
30 pub fn getOs(self: Target) builtin.Os {44 pub fn getOs(self: Target) builtin.Os {
31 return switch (self) {45 return switch (self) {
32 Target.Native => builtin.os,46 Target.Native => builtin.os,
...@@ -76,6 +90,56 @@ pub const Target = union(enum) {...@@ -76,6 +90,56 @@ pub const Target = union(enum) {
76 };90 };
77 }91 }
7892
93 /// TODO expose the arch and subarch separately
94 pub fn isArmOrThumb(self: Target) bool {
95 return switch (self.getArch()) {
96 builtin.Arch.armv8_3a,
97 builtin.Arch.armv8_2a,
98 builtin.Arch.armv8_1a,
99 builtin.Arch.armv8,
100 builtin.Arch.armv8r,
101 builtin.Arch.armv8m_baseline,
102 builtin.Arch.armv8m_mainline,
103 builtin.Arch.armv7,
104 builtin.Arch.armv7em,
105 builtin.Arch.armv7m,
106 builtin.Arch.armv7s,
107 builtin.Arch.armv7k,
108 builtin.Arch.armv7ve,
109 builtin.Arch.armv6,
110 builtin.Arch.armv6m,
111 builtin.Arch.armv6k,
112 builtin.Arch.armv6t2,
113 builtin.Arch.armv5,
114 builtin.Arch.armv5te,
115 builtin.Arch.armv4t,
116 builtin.Arch.armebv8_3a,
117 builtin.Arch.armebv8_2a,
118 builtin.Arch.armebv8_1a,
119 builtin.Arch.armebv8,
120 builtin.Arch.armebv8r,
121 builtin.Arch.armebv8m_baseline,
122 builtin.Arch.armebv8m_mainline,
123 builtin.Arch.armebv7,
124 builtin.Arch.armebv7em,
125 builtin.Arch.armebv7m,
126 builtin.Arch.armebv7s,
127 builtin.Arch.armebv7k,
128 builtin.Arch.armebv7ve,
129 builtin.Arch.armebv6,
130 builtin.Arch.armebv6m,
131 builtin.Arch.armebv6k,
132 builtin.Arch.armebv6t2,
133 builtin.Arch.armebv5,
134 builtin.Arch.armebv5te,
135 builtin.Arch.armebv4t,
136 builtin.Arch.thumb,
137 builtin.Arch.thumbeb,
138 => true,
139 else => false,
140 };
141 }
142
79 pub fn initializeAll() void {143 pub fn initializeAll() void {
80 llvm.InitializeAllTargets();144 llvm.InitializeAllTargets();
81 llvm.InitializeAllTargetInfos();145 llvm.InitializeAllTargetInfos();
...@@ -106,6 +170,257 @@ pub const Target = union(enum) {...@@ -106,6 +170,257 @@ pub const Target = union(enum) {
106 return result;170 return result;
107 }171 }
108172
173 pub fn is64bit(self: Target) bool {
174 return self.getArchPtrBitWidth() == 64;
175 }
176
177 pub fn getArchPtrBitWidth(self: Target) u32 {
178 switch (self.getArch()) {
179 builtin.Arch.avr,
180 builtin.Arch.msp430,
181 => return 16,
182
183 builtin.Arch.arc,
184 builtin.Arch.armv8_3a,
185 builtin.Arch.armv8_2a,
186 builtin.Arch.armv8_1a,
187 builtin.Arch.armv8,
188 builtin.Arch.armv8r,
189 builtin.Arch.armv8m_baseline,
190 builtin.Arch.armv8m_mainline,
191 builtin.Arch.armv7,
192 builtin.Arch.armv7em,
193 builtin.Arch.armv7m,
194 builtin.Arch.armv7s,
195 builtin.Arch.armv7k,
196 builtin.Arch.armv7ve,
197 builtin.Arch.armv6,
198 builtin.Arch.armv6m,
199 builtin.Arch.armv6k,
200 builtin.Arch.armv6t2,
201 builtin.Arch.armv5,
202 builtin.Arch.armv5te,
203 builtin.Arch.armv4t,
204 builtin.Arch.armebv8_3a,
205 builtin.Arch.armebv8_2a,
206 builtin.Arch.armebv8_1a,
207 builtin.Arch.armebv8,
208 builtin.Arch.armebv8r,
209 builtin.Arch.armebv8m_baseline,
210 builtin.Arch.armebv8m_mainline,
211 builtin.Arch.armebv7,
212 builtin.Arch.armebv7em,
213 builtin.Arch.armebv7m,
214 builtin.Arch.armebv7s,
215 builtin.Arch.armebv7k,
216 builtin.Arch.armebv7ve,
217 builtin.Arch.armebv6,
218 builtin.Arch.armebv6m,
219 builtin.Arch.armebv6k,
220 builtin.Arch.armebv6t2,
221 builtin.Arch.armebv5,
222 builtin.Arch.armebv5te,
223 builtin.Arch.armebv4t,
224 builtin.Arch.hexagon,
225 builtin.Arch.le32,
226 builtin.Arch.mips,
227 builtin.Arch.mipsel,
228 builtin.Arch.nios2,
229 builtin.Arch.powerpc,
230 builtin.Arch.r600,
231 builtin.Arch.riscv32,
232 builtin.Arch.sparc,
233 builtin.Arch.sparcel,
234 builtin.Arch.tce,
235 builtin.Arch.tcele,
236 builtin.Arch.thumb,
237 builtin.Arch.thumbeb,
238 builtin.Arch.i386,
239 builtin.Arch.xcore,
240 builtin.Arch.nvptx,
241 builtin.Arch.amdil,
242 builtin.Arch.hsail,
243 builtin.Arch.spir,
244 builtin.Arch.kalimbav3,
245 builtin.Arch.kalimbav4,
246 builtin.Arch.kalimbav5,
247 builtin.Arch.shave,
248 builtin.Arch.lanai,
249 builtin.Arch.wasm32,
250 builtin.Arch.renderscript32,
251 => return 32,
252
253 builtin.Arch.aarch64,
254 builtin.Arch.aarch64_be,
255 builtin.Arch.mips64,
256 builtin.Arch.mips64el,
257 builtin.Arch.powerpc64,
258 builtin.Arch.powerpc64le,
259 builtin.Arch.riscv64,
260 builtin.Arch.x86_64,
261 builtin.Arch.nvptx64,
262 builtin.Arch.le64,
263 builtin.Arch.amdil64,
264 builtin.Arch.hsail64,
265 builtin.Arch.spir64,
266 builtin.Arch.wasm64,
267 builtin.Arch.renderscript64,
268 builtin.Arch.amdgcn,
269 builtin.Arch.bpfel,
270 builtin.Arch.bpfeb,
271 builtin.Arch.sparcv9,
272 builtin.Arch.s390x,
273 => return 64,
274 }
275 }
276
277 pub fn getFloatAbi(self: Target) FloatAbi {
278 return switch (self.getEnviron()) {
279 builtin.Environ.gnueabihf,
280 builtin.Environ.eabihf,
281 builtin.Environ.musleabihf,
282 => FloatAbi.Hard,
283 else => FloatAbi.Soft,
284 };
285 }
286
287 pub fn getDynamicLinkerPath(self: Target) ?[]const u8 {
288 const env = self.getEnviron();
289 const arch = self.getArch();
290 switch (env) {
291 builtin.Environ.android => {
292 if (self.is64bit()) {
293 return "/system/bin/linker64";
294 } else {
295 return "/system/bin/linker";
296 }
297 },
298 builtin.Environ.gnux32 => {
299 if (arch == builtin.Arch.x86_64) {
300 return "/libx32/ld-linux-x32.so.2";
301 }
302 },
303 builtin.Environ.musl,
304 builtin.Environ.musleabi,
305 builtin.Environ.musleabihf,
306 => {
307 if (arch == builtin.Arch.x86_64) {
308 return "/lib/ld-musl-x86_64.so.1";
309 }
310 },
311 else => {},
312 }
313 switch (arch) {
314 builtin.Arch.i386,
315 builtin.Arch.sparc,
316 builtin.Arch.sparcel,
317 => return "/lib/ld-linux.so.2",
318
319 builtin.Arch.aarch64 => return "/lib/ld-linux-aarch64.so.1",
320 builtin.Arch.aarch64_be => return "/lib/ld-linux-aarch64_be.so.1",
321
322 builtin.Arch.armv8_3a,
323 builtin.Arch.armv8_2a,
324 builtin.Arch.armv8_1a,
325 builtin.Arch.armv8,
326 builtin.Arch.armv8r,
327 builtin.Arch.armv8m_baseline,
328 builtin.Arch.armv8m_mainline,
329 builtin.Arch.armv7,
330 builtin.Arch.armv7em,
331 builtin.Arch.armv7m,
332 builtin.Arch.armv7s,
333 builtin.Arch.armv7k,
334 builtin.Arch.armv7ve,
335 builtin.Arch.armv6,
336 builtin.Arch.armv6m,
337 builtin.Arch.armv6k,
338 builtin.Arch.armv6t2,
339 builtin.Arch.armv5,
340 builtin.Arch.armv5te,
341 builtin.Arch.armv4t,
342 builtin.Arch.thumb,
343 => return switch (self.getFloatAbi()) {
344 FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
345 else => return "/lib/ld-linux.so.3",
346 },
347
348 builtin.Arch.armebv8_3a,
349 builtin.Arch.armebv8_2a,
350 builtin.Arch.armebv8_1a,
351 builtin.Arch.armebv8,
352 builtin.Arch.armebv8r,
353 builtin.Arch.armebv8m_baseline,
354 builtin.Arch.armebv8m_mainline,
355 builtin.Arch.armebv7,
356 builtin.Arch.armebv7em,
357 builtin.Arch.armebv7m,
358 builtin.Arch.armebv7s,
359 builtin.Arch.armebv7k,
360 builtin.Arch.armebv7ve,
361 builtin.Arch.armebv6,
362 builtin.Arch.armebv6m,
363 builtin.Arch.armebv6k,
364 builtin.Arch.armebv6t2,
365 builtin.Arch.armebv5,
366 builtin.Arch.armebv5te,
367 builtin.Arch.armebv4t,
368 builtin.Arch.thumbeb,
369 => return switch (self.getFloatAbi()) {
370 FloatAbi.Hard => return "/lib/ld-linux-armhf.so.3",
371 else => return "/lib/ld-linux.so.3",
372 },
373
374 builtin.Arch.mips,
375 builtin.Arch.mipsel,
376 builtin.Arch.mips64,
377 builtin.Arch.mips64el,
378 => return null,
379
380 builtin.Arch.powerpc => return "/lib/ld.so.1",
381 builtin.Arch.powerpc64 => return "/lib64/ld64.so.2",
382 builtin.Arch.powerpc64le => return "/lib64/ld64.so.2",
383 builtin.Arch.s390x => return "/lib64/ld64.so.1",
384 builtin.Arch.sparcv9 => return "/lib64/ld-linux.so.2",
385 builtin.Arch.x86_64 => return "/lib64/ld-linux-x86-64.so.2",
386
387 builtin.Arch.arc,
388 builtin.Arch.avr,
389 builtin.Arch.bpfel,
390 builtin.Arch.bpfeb,
391 builtin.Arch.hexagon,
392 builtin.Arch.msp430,
393 builtin.Arch.nios2,
394 builtin.Arch.r600,
395 builtin.Arch.amdgcn,
396 builtin.Arch.riscv32,
397 builtin.Arch.riscv64,
398 builtin.Arch.tce,
399 builtin.Arch.tcele,
400 builtin.Arch.xcore,
401 builtin.Arch.nvptx,
402 builtin.Arch.nvptx64,
403 builtin.Arch.le32,
404 builtin.Arch.le64,
405 builtin.Arch.amdil,
406 builtin.Arch.amdil64,
407 builtin.Arch.hsail,
408 builtin.Arch.hsail64,
409 builtin.Arch.spir,
410 builtin.Arch.spir64,
411 builtin.Arch.kalimbav3,
412 builtin.Arch.kalimbav4,
413 builtin.Arch.kalimbav5,
414 builtin.Arch.shave,
415 builtin.Arch.lanai,
416 builtin.Arch.wasm32,
417 builtin.Arch.wasm64,
418 builtin.Arch.renderscript32,
419 builtin.Arch.renderscript64,
420 => return null,
421 }
422 }
423
109 pub fn llvmTargetFromTriple(triple: std.Buffer) !llvm.TargetRef {424 pub fn llvmTargetFromTriple(triple: std.Buffer) !llvm.TargetRef {
110 var result: llvm.TargetRef = undefined;425 var result: llvm.TargetRef = undefined;
111 var err_msg: [*]u8 = undefined;426 var err_msg: [*]u8 = undefined;
...@@ -115,4 +430,133 @@ pub const Target = union(enum) {...@@ -115,4 +430,133 @@ pub const Target = union(enum) {
115 }430 }
116 return result;431 return result;
117 }432 }
433
434 pub fn cIntTypeSizeInBits(self: Target, id: CInt.Id) u32 {
435 const arch = self.getArch();
436 switch (self.getOs()) {
437 builtin.Os.freestanding => switch (self.getArch()) {
438 builtin.Arch.msp430 => switch (id) {
439 CInt.Id.Short,
440 CInt.Id.UShort,
441 CInt.Id.Int,
442 CInt.Id.UInt,
443 => return 16,
444 CInt.Id.Long,
445 CInt.Id.ULong,
446 => return 32,
447 CInt.Id.LongLong,
448 CInt.Id.ULongLong,
449 => return 64,
450 },
451 else => switch (id) {
452 CInt.Id.Short,
453 CInt.Id.UShort,
454 => return 16,
455 CInt.Id.Int,
456 CInt.Id.UInt,
457 => return 32,
458 CInt.Id.Long,
459 CInt.Id.ULong,
460 => return self.getArchPtrBitWidth(),
461 CInt.Id.LongLong,
462 CInt.Id.ULongLong,
463 => return 64,
464 },
465 },
466
467 builtin.Os.linux,
468 builtin.Os.macosx,
469 builtin.Os.openbsd,
470 builtin.Os.zen,
471 => switch (id) {
472 CInt.Id.Short,
473 CInt.Id.UShort,
474 => return 16,
475 CInt.Id.Int,
476 CInt.Id.UInt,
477 => return 32,
478 CInt.Id.Long,
479 CInt.Id.ULong,
480 => return self.getArchPtrBitWidth(),
481 CInt.Id.LongLong,
482 CInt.Id.ULongLong,
483 => return 64,
484 },
485
486 builtin.Os.windows => switch (id) {
487 CInt.Id.Short,
488 CInt.Id.UShort,
489 => return 16,
490 CInt.Id.Int,
491 CInt.Id.UInt,
492 => return 32,
493 CInt.Id.Long,
494 CInt.Id.ULong,
495 CInt.Id.LongLong,
496 CInt.Id.ULongLong,
497 => return 64,
498 },
499
500 builtin.Os.ananas,
501 builtin.Os.cloudabi,
502 builtin.Os.dragonfly,
503 builtin.Os.freebsd,
504 builtin.Os.fuchsia,
505 builtin.Os.ios,
506 builtin.Os.kfreebsd,
507 builtin.Os.lv2,
508 builtin.Os.netbsd,
509 builtin.Os.solaris,
510 builtin.Os.haiku,
511 builtin.Os.minix,
512 builtin.Os.rtems,
513 builtin.Os.nacl,
514 builtin.Os.cnk,
515 builtin.Os.aix,
516 builtin.Os.cuda,
517 builtin.Os.nvcl,
518 builtin.Os.amdhsa,
519 builtin.Os.ps4,
520 builtin.Os.elfiamcu,
521 builtin.Os.tvos,
522 builtin.Os.watchos,
523 builtin.Os.mesa3d,
524 builtin.Os.contiki,
525 builtin.Os.amdpal,
526 => @panic("TODO specify the C integer type sizes for this OS"),
527 }
528 }
529
530 pub fn getDarwinArchString(self: Target) []const u8 {
531 const arch = self.getArch();
532 switch (arch) {
533 builtin.Arch.aarch64 => return "arm64",
534 builtin.Arch.thumb,
535 builtin.Arch.armv8_3a,
536 builtin.Arch.armv8_2a,
537 builtin.Arch.armv8_1a,
538 builtin.Arch.armv8,
539 builtin.Arch.armv8r,
540 builtin.Arch.armv8m_baseline,
541 builtin.Arch.armv8m_mainline,
542 builtin.Arch.armv7,
543 builtin.Arch.armv7em,
544 builtin.Arch.armv7m,
545 builtin.Arch.armv7s,
546 builtin.Arch.armv7k,
547 builtin.Arch.armv7ve,
548 builtin.Arch.armv6,
549 builtin.Arch.armv6m,
550 builtin.Arch.armv6k,
551 builtin.Arch.armv6t2,
552 builtin.Arch.armv5,
553 builtin.Arch.armv5te,
554 builtin.Arch.armv4t,
555 => return "arm",
556 builtin.Arch.powerpc => return "ppc",
557 builtin.Arch.powerpc64 => return "ppc64",
558 builtin.Arch.powerpc64le => return "ppc64le",
559 else => return @tagName(arch),
560 }
561 }
118};562};
src-self-hosted/test.zig+88-14
...@@ -8,12 +8,14 @@ const assertOrPanic = std.debug.assertOrPanic;...@@ -8,12 +8,14 @@ const assertOrPanic = std.debug.assertOrPanic;
8const errmsg = @import("errmsg.zig");8const errmsg = @import("errmsg.zig");
9const EventLoopLocal = @import("compilation.zig").EventLoopLocal;9const EventLoopLocal = @import("compilation.zig").EventLoopLocal;
1010
11test "compile errors" {11var ctx: TestContext = undefined;
12 var ctx: TestContext = undefined;12
13test "stage2" {
13 try ctx.init();14 try ctx.init();
14 defer ctx.deinit();15 defer ctx.deinit();
1516
16 try @import("../test/stage2/compile_errors.zig").addCases(&ctx);17 try @import("../test/stage2/compile_errors.zig").addCases(&ctx);
18 try @import("../test/stage2/compare_output.zig").addCases(&ctx);
1719
18 try ctx.run();20 try ctx.run();
19}21}
...@@ -25,7 +27,6 @@ pub const TestContext = struct {...@@ -25,7 +27,6 @@ pub const TestContext = struct {
25 loop: std.event.Loop,27 loop: std.event.Loop,
26 event_loop_local: EventLoopLocal,28 event_loop_local: EventLoopLocal,
27 zig_lib_dir: []u8,29 zig_lib_dir: []u8,
28 zig_cache_dir: []u8,
29 file_index: std.atomic.Int(usize),30 file_index: std.atomic.Int(usize),
30 group: std.event.Group(error!void),31 group: std.event.Group(error!void),
31 any_err: error!void,32 any_err: error!void,
...@@ -38,7 +39,6 @@ pub const TestContext = struct {...@@ -38,7 +39,6 @@ pub const TestContext = struct {
38 .loop = undefined,39 .loop = undefined,
39 .event_loop_local = undefined,40 .event_loop_local = undefined,
40 .zig_lib_dir = undefined,41 .zig_lib_dir = undefined,
41 .zig_cache_dir = undefined,
42 .group = undefined,42 .group = undefined,
43 .file_index = std.atomic.Int(usize).init(0),43 .file_index = std.atomic.Int(usize).init(0),
44 };44 };
...@@ -55,16 +55,12 @@ pub const TestContext = struct {...@@ -55,16 +55,12 @@ pub const TestContext = struct {
55 self.zig_lib_dir = try introspect.resolveZigLibDir(allocator);55 self.zig_lib_dir = try introspect.resolveZigLibDir(allocator);
56 errdefer allocator.free(self.zig_lib_dir);56 errdefer allocator.free(self.zig_lib_dir);
5757
58 self.zig_cache_dir = try introspect.resolveZigCacheDir(allocator);
59 errdefer allocator.free(self.zig_cache_dir);
60
61 try std.os.makePath(allocator, tmp_dir_name);58 try std.os.makePath(allocator, tmp_dir_name);
62 errdefer std.os.deleteTree(allocator, tmp_dir_name) catch {};59 errdefer std.os.deleteTree(allocator, tmp_dir_name) catch {};
63 }60 }
6461
65 fn deinit(self: *TestContext) void {62 fn deinit(self: *TestContext) void {
66 std.os.deleteTree(allocator, tmp_dir_name) catch {};63 std.os.deleteTree(allocator, tmp_dir_name) catch {};
67 allocator.free(self.zig_cache_dir);
68 allocator.free(self.zig_lib_dir);64 allocator.free(self.zig_lib_dir);
69 self.event_loop_local.deinit();65 self.event_loop_local.deinit();
70 self.loop.deinit();66 self.loop.deinit();
...@@ -109,7 +105,6 @@ pub const TestContext = struct {...@@ -109,7 +105,6 @@ pub const TestContext = struct {
109 builtin.Mode.Debug,105 builtin.Mode.Debug,
110 true, // is_static106 true, // is_static
111 self.zig_lib_dir,107 self.zig_lib_dir,
112 self.zig_cache_dir,
113 );108 );
114 errdefer comp.destroy();109 errdefer comp.destroy();
115110
...@@ -118,6 +113,84 @@ pub const TestContext = struct {...@@ -118,6 +113,84 @@ pub const TestContext = struct {
118 try self.group.call(getModuleEvent, comp, source, path, line, column, msg);113 try self.group.call(getModuleEvent, comp, source, path, line, column, msg);
119 }114 }
120115
116 fn testCompareOutputLibC(
117 self: *TestContext,
118 source: []const u8,
119 expected_output: []const u8,
120 ) !void {
121 var file_index_buf: [20]u8 = undefined;
122 const file_index = try std.fmt.bufPrint(file_index_buf[0..], "{}", self.file_index.incr());
123 const file1_path = try std.os.path.join(allocator, tmp_dir_name, file_index, file1);
124
125 const output_file = try std.fmt.allocPrint(allocator, "{}-out{}", file1_path, Target(Target.Native).exeFileExt());
126 if (std.os.path.dirname(file1_path)) |dirname| {
127 try std.os.makePath(allocator, dirname);
128 }
129
130 // TODO async I/O
131 try std.io.writeFile(allocator, file1_path, source);
132
133 var comp = try Compilation.create(
134 &self.event_loop_local,
135 "test",
136 file1_path,
137 Target.Native,
138 Compilation.Kind.Exe,
139 builtin.Mode.Debug,
140 false,
141 self.zig_lib_dir,
142 );
143 errdefer comp.destroy();
144
145 _ = try comp.addLinkLib("c", true);
146 comp.link_out_file = output_file;
147 try comp.build();
148
149 try self.group.call(getModuleEventSuccess, comp, output_file, expected_output);
150 }
151
152 async fn getModuleEventSuccess(
153 comp: *Compilation,
154 exe_file: []const u8,
155 expected_output: []const u8,
156 ) !void {
157 // TODO this should not be necessary
158 const exe_file_2 = try std.mem.dupe(allocator, u8, exe_file);
159
160 defer comp.destroy();
161 const build_event = await (async comp.events.get() catch unreachable);
162
163 switch (build_event) {
164 Compilation.Event.Ok => {
165 const argv = []const []const u8{exe_file_2};
166 // TODO use event loop
167 const child = try std.os.ChildProcess.exec(allocator, argv, null, null, 1024 * 1024);
168 switch (child.term) {
169 std.os.ChildProcess.Term.Exited => |code| {
170 if (code != 0) {
171 return error.BadReturnCode;
172 }
173 },
174 else => {
175 return error.Crashed;
176 },
177 }
178 if (!mem.eql(u8, child.stdout, expected_output)) {
179 return error.OutputMismatch;
180 }
181 },
182 Compilation.Event.Error => |err| return err,
183 Compilation.Event.Fail => |msgs| {
184 var stderr = try std.io.getStdErr();
185 try stderr.write("build incorrectly failed:\n");
186 for (msgs) |msg| {
187 defer msg.destroy();
188 try msg.printToFile(&stderr, errmsg.Color.Auto);
189 }
190 },
191 }
192 }
193
121 async fn getModuleEvent(194 async fn getModuleEvent(
122 comp: *Compilation,195 comp: *Compilation,
123 source: []const u8,196 source: []const u8,
...@@ -139,10 +212,10 @@ pub const TestContext = struct {...@@ -139,10 +212,10 @@ pub const TestContext = struct {
139 Compilation.Event.Fail => |msgs| {212 Compilation.Event.Fail => |msgs| {
140 assertOrPanic(msgs.len != 0);213 assertOrPanic(msgs.len != 0);
141 for (msgs) |msg| {214 for (msgs) |msg| {
142 if (mem.endsWith(u8, msg.path, path) and mem.eql(u8, msg.text, text)) {215 if (mem.endsWith(u8, msg.getRealPath(), path) and mem.eql(u8, msg.text, text)) {
143 const first_token = msg.tree.tokens.at(msg.span.first);216 const first_token = msg.getTree().tokens.at(msg.span.first);
144 const last_token = msg.tree.tokens.at(msg.span.first);217 const last_token = msg.getTree().tokens.at(msg.span.first);
145 const start_loc = msg.tree.tokenLocationPtr(0, first_token);218 const start_loc = msg.getTree().tokenLocationPtr(0, first_token);
146 if (start_loc.line + 1 == line and start_loc.column + 1 == column) {219 if (start_loc.line + 1 == line and start_loc.column + 1 == column) {
147 return;220 return;
148 }221 }
...@@ -159,7 +232,8 @@ pub const TestContext = struct {...@@ -159,7 +232,8 @@ pub const TestContext = struct {
159 std.debug.warn("\n====found:========\n");232 std.debug.warn("\n====found:========\n");
160 var stderr = try std.io.getStdErr();233 var stderr = try std.io.getStdErr();
161 for (msgs) |msg| {234 for (msgs) |msg| {
162 try errmsg.printToFile(&stderr, msg, errmsg.Color.Auto);235 defer msg.destroy();
236 try msg.printToFile(&stderr, errmsg.Color.Auto);
163 }237 }
164 std.debug.warn("============\n");238 std.debug.warn("============\n");
165 return error.TestFailed;239 return error.TestFailed;
src-self-hosted/type.zig+392-65
...@@ -4,11 +4,17 @@ const Scope = @import("scope.zig").Scope;...@@ -4,11 +4,17 @@ const Scope = @import("scope.zig").Scope;
4const Compilation = @import("compilation.zig").Compilation;4const Compilation = @import("compilation.zig").Compilation;
5const Value = @import("value.zig").Value;5const Value = @import("value.zig").Value;
6const llvm = @import("llvm.zig");6const llvm = @import("llvm.zig");
7const ObjectFile = @import("codegen.zig").ObjectFile;7const event = std.event;
8const Allocator = std.mem.Allocator;
9const assert = std.debug.assert;
810
9pub const Type = struct {11pub const Type = struct {
10 base: Value,12 base: Value,
11 id: Id,13 id: Id,
14 name: []const u8,
15 abi_alignment: AbiAlignment,
16
17 pub const AbiAlignment = event.Future(error{OutOfMemory}!u32);
1218
13 pub const Id = builtin.TypeId;19 pub const Id = builtin.TypeId;
1420
...@@ -42,33 +48,37 @@ pub const Type = struct {...@@ -42,33 +48,37 @@ pub const Type = struct {
42 }48 }
43 }49 }
4450
45 pub fn getLlvmType(base: *Type, ofile: *ObjectFile) (error{OutOfMemory}!llvm.TypeRef) {51 pub fn getLlvmType(
52 base: *Type,
53 allocator: *Allocator,
54 llvm_context: llvm.ContextRef,
55 ) (error{OutOfMemory}!llvm.TypeRef) {
46 switch (base.id) {56 switch (base.id) {
47 Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(ofile),57 Id.Struct => return @fieldParentPtr(Struct, "base", base).getLlvmType(allocator, llvm_context),
48 Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(ofile),58 Id.Fn => return @fieldParentPtr(Fn, "base", base).getLlvmType(allocator, llvm_context),
49 Id.Type => unreachable,59 Id.Type => unreachable,
50 Id.Void => unreachable,60 Id.Void => unreachable,
51 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmType(ofile),61 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmType(allocator, llvm_context),
52 Id.NoReturn => unreachable,62 Id.NoReturn => unreachable,
53 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmType(ofile),63 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmType(allocator, llvm_context),
54 Id.Float => return @fieldParentPtr(Float, "base", base).getLlvmType(ofile),64 Id.Float => return @fieldParentPtr(Float, "base", base).getLlvmType(allocator, llvm_context),
55 Id.Pointer => return @fieldParentPtr(Pointer, "base", base).getLlvmType(ofile),65 Id.Pointer => return @fieldParentPtr(Pointer, "base", base).getLlvmType(allocator, llvm_context),
56 Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmType(ofile),66 Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmType(allocator, llvm_context),
57 Id.ComptimeFloat => unreachable,67 Id.ComptimeFloat => unreachable,
58 Id.ComptimeInt => unreachable,68 Id.ComptimeInt => unreachable,
59 Id.Undefined => unreachable,69 Id.Undefined => unreachable,
60 Id.Null => unreachable,70 Id.Null => unreachable,
61 Id.Optional => return @fieldParentPtr(Optional, "base", base).getLlvmType(ofile),71 Id.Optional => return @fieldParentPtr(Optional, "base", base).getLlvmType(allocator, llvm_context),
62 Id.ErrorUnion => return @fieldParentPtr(ErrorUnion, "base", base).getLlvmType(ofile),72 Id.ErrorUnion => return @fieldParentPtr(ErrorUnion, "base", base).getLlvmType(allocator, llvm_context),
63 Id.ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(ofile),73 Id.ErrorSet => return @fieldParentPtr(ErrorSet, "base", base).getLlvmType(allocator, llvm_context),
64 Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(ofile),74 Id.Enum => return @fieldParentPtr(Enum, "base", base).getLlvmType(allocator, llvm_context),
65 Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(ofile),75 Id.Union => return @fieldParentPtr(Union, "base", base).getLlvmType(allocator, llvm_context),
66 Id.Namespace => unreachable,76 Id.Namespace => unreachable,
67 Id.Block => unreachable,77 Id.Block => unreachable,
68 Id.BoundFn => return @fieldParentPtr(BoundFn, "base", base).getLlvmType(ofile),78 Id.BoundFn => return @fieldParentPtr(BoundFn, "base", base).getLlvmType(allocator, llvm_context),
69 Id.ArgTuple => unreachable,79 Id.ArgTuple => unreachable,
70 Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(ofile),80 Id.Opaque => return @fieldParentPtr(Opaque, "base", base).getLlvmType(allocator, llvm_context),
71 Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(ofile),81 Id.Promise => return @fieldParentPtr(Promise, "base", base).getLlvmType(allocator, llvm_context),
72 }82 }
73 }83 }
7484
...@@ -151,8 +161,49 @@ pub const Type = struct {...@@ -151,8 +161,49 @@ pub const Type = struct {
151 std.debug.warn("{}", @tagName(base.id));161 std.debug.warn("{}", @tagName(base.id));
152 }162 }
153163
154 pub fn getAbiAlignment(base: *Type, comp: *Compilation) u32 {164 fn init(base: *Type, comp: *Compilation, id: Id, name: []const u8) void {
155 @panic("TODO getAbiAlignment");165 base.* = Type{
166 .base = Value{
167 .id = Value.Id.Type,
168 .typ = &MetaType.get(comp).base,
169 .ref_count = std.atomic.Int(usize).init(1),
170 },
171 .id = id,
172 .name = name,
173 .abi_alignment = AbiAlignment.init(comp.loop),
174 };
175 }
176
177 /// If you happen to have an llvm context handy, use getAbiAlignmentInContext instead.
178 /// Otherwise, this one will grab one from the pool and then release it.
179 pub async fn getAbiAlignment(base: *Type, comp: *Compilation) !u32 {
180 if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*;
181
182 {
183 const held = try comp.event_loop_local.getAnyLlvmContext();
184 defer held.release(comp.event_loop_local);
185
186 const llvm_context = held.node.data;
187
188 base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable);
189 }
190 base.abi_alignment.resolve();
191 return base.abi_alignment.data;
192 }
193
194 /// If you have an llvm conext handy, you can use it here.
195 pub async fn getAbiAlignmentInContext(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
196 if (await (async base.abi_alignment.start() catch unreachable)) |ptr| return ptr.*;
197
198 base.abi_alignment.data = await (async base.resolveAbiAlignment(comp, llvm_context) catch unreachable);
199 base.abi_alignment.resolve();
200 return base.abi_alignment.data;
201 }
202
203 /// Lower level function that does the work. See getAbiAlignment.
204 async fn resolveAbiAlignment(base: *Type, comp: *Compilation, llvm_context: llvm.ContextRef) !u32 {
205 const llvm_type = try base.getLlvmType(comp.gpa(), llvm_context);
206 return @intCast(u32, llvm.ABIAlignmentOfType(comp.target_data_ref, llvm_type));
156 }207 }
157208
158 pub const Struct = struct {209 pub const Struct = struct {
...@@ -163,7 +214,7 @@ pub const Type = struct {...@@ -163,7 +214,7 @@ pub const Type = struct {
163 comp.gpa().destroy(self);214 comp.gpa().destroy(self);
164 }215 }
165216
166 pub fn getLlvmType(self: *Struct, ofile: *ObjectFile) llvm.TypeRef {217 pub fn getLlvmType(self: *Struct, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
167 @panic("TODO");218 @panic("TODO");
168 }219 }
169 };220 };
...@@ -176,28 +227,23 @@ pub const Type = struct {...@@ -176,28 +227,23 @@ pub const Type = struct {
176227
177 pub const Param = struct {228 pub const Param = struct {
178 is_noalias: bool,229 is_noalias: bool,
179 typeof: *Type,230 typ: *Type,
180 };231 };
181232
182 pub fn create(comp: *Compilation, return_type: *Type, params: []Param, is_var_args: bool) !*Fn {233 pub fn create(comp: *Compilation, return_type: *Type, params: []Param, is_var_args: bool) !*Fn {
183 const result = try comp.gpa().create(Fn{234 const result = try comp.gpa().create(Fn{
184 .base = Type{235 .base = undefined,
185 .base = Value{
186 .id = Value.Id.Type,
187 .typeof = &MetaType.get(comp).base,
188 .ref_count = std.atomic.Int(usize).init(1),
189 },
190 .id = builtin.TypeId.Fn,
191 },
192 .return_type = return_type,236 .return_type = return_type,
193 .params = params,237 .params = params,
194 .is_var_args = is_var_args,238 .is_var_args = is_var_args,
195 });239 });
196 errdefer comp.gpa().destroy(result);240 errdefer comp.gpa().destroy(result);
197241
242 result.base.init(comp, Id.Fn, "TODO fn type name");
243
198 result.return_type.base.ref();244 result.return_type.base.ref();
199 for (result.params) |param| {245 for (result.params) |param| {
200 param.typeof.base.ref();246 param.typ.base.ref();
201 }247 }
202 return result;248 return result;
203 }249 }
...@@ -205,20 +251,20 @@ pub const Type = struct {...@@ -205,20 +251,20 @@ pub const Type = struct {
205 pub fn destroy(self: *Fn, comp: *Compilation) void {251 pub fn destroy(self: *Fn, comp: *Compilation) void {
206 self.return_type.base.deref(comp);252 self.return_type.base.deref(comp);
207 for (self.params) |param| {253 for (self.params) |param| {
208 param.typeof.base.deref(comp);254 param.typ.base.deref(comp);
209 }255 }
210 comp.gpa().destroy(self);256 comp.gpa().destroy(self);
211 }257 }
212258
213 pub fn getLlvmType(self: *Fn, ofile: *ObjectFile) !llvm.TypeRef {259 pub fn getLlvmType(self: *Fn, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
214 const llvm_return_type = switch (self.return_type.id) {260 const llvm_return_type = switch (self.return_type.id) {
215 Type.Id.Void => llvm.VoidTypeInContext(ofile.context) orelse return error.OutOfMemory,261 Type.Id.Void => llvm.VoidTypeInContext(llvm_context) orelse return error.OutOfMemory,
216 else => try self.return_type.getLlvmType(ofile),262 else => try self.return_type.getLlvmType(allocator, llvm_context),
217 };263 };
218 const llvm_param_types = try ofile.gpa().alloc(llvm.TypeRef, self.params.len);264 const llvm_param_types = try allocator.alloc(llvm.TypeRef, self.params.len);
219 defer ofile.gpa().free(llvm_param_types);265 defer allocator.free(llvm_param_types);
220 for (llvm_param_types) |*llvm_param_type, i| {266 for (llvm_param_types) |*llvm_param_type, i| {
221 llvm_param_type.* = try self.params[i].typeof.getLlvmType(ofile);267 llvm_param_type.* = try self.params[i].typ.getLlvmType(allocator, llvm_context);
222 }268 }
223269
224 return llvm.FunctionType(270 return llvm.FunctionType(
...@@ -272,7 +318,7 @@ pub const Type = struct {...@@ -272,7 +318,7 @@ pub const Type = struct {
272 comp.gpa().destroy(self);318 comp.gpa().destroy(self);
273 }319 }
274320
275 pub fn getLlvmType(self: *Bool, ofile: *ObjectFile) llvm.TypeRef {321 pub fn getLlvmType(self: *Bool, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
276 @panic("TODO");322 @panic("TODO");
277 }323 }
278 };324 };
...@@ -293,13 +339,83 @@ pub const Type = struct {...@@ -293,13 +339,83 @@ pub const Type = struct {
293339
294 pub const Int = struct {340 pub const Int = struct {
295 base: Type,341 base: Type,
342 key: Key,
343 garbage_node: std.atomic.Stack(*Int).Node,
344
345 pub const Key = struct {
346 bit_count: u32,
347 is_signed: bool,
348
349 pub fn hash(self: *const Key) u32 {
350 const rands = [2]u32{ 0xa4ba6498, 0x75fc5af7 };
351 return rands[@boolToInt(self.is_signed)] *% self.bit_count;
352 }
353
354 pub fn eql(self: *const Key, other: *const Key) bool {
355 return self.bit_count == other.bit_count and self.is_signed == other.is_signed;
356 }
357 };
358
359 pub fn get_u8(comp: *Compilation) *Int {
360 comp.u8_type.base.base.ref();
361 return comp.u8_type;
362 }
363
364 pub async fn get(comp: *Compilation, key: Key) !*Int {
365 {
366 const held = await (async comp.int_type_table.acquire() catch unreachable);
367 defer held.release();
368
369 if (held.value.get(&key)) |entry| {
370 entry.value.base.base.ref();
371 return entry.value;
372 }
373 }
374
375 const self = try comp.gpa().create(Int{
376 .base = undefined,
377 .key = key,
378 .garbage_node = undefined,
379 });
380 errdefer comp.gpa().destroy(self);
381
382 const u_or_i = "ui"[@boolToInt(key.is_signed)];
383 const name = try std.fmt.allocPrint(comp.gpa(), "{c}{}", u_or_i, key.bit_count);
384 errdefer comp.gpa().free(name);
385
386 self.base.init(comp, Id.Int, name);
387
388 {
389 const held = await (async comp.int_type_table.acquire() catch unreachable);
390 defer held.release();
391
392 _ = try held.value.put(&self.key, self);
393 }
394 return self;
395 }
296396
297 pub fn destroy(self: *Int, comp: *Compilation) void {397 pub fn destroy(self: *Int, comp: *Compilation) void {
398 self.garbage_node = std.atomic.Stack(*Int).Node{
399 .data = self,
400 .next = undefined,
401 };
402 comp.registerGarbage(Int, &self.garbage_node);
403 }
404
405 pub async fn gcDestroy(self: *Int, comp: *Compilation) void {
406 {
407 const held = await (async comp.int_type_table.acquire() catch unreachable);
408 defer held.release();
409
410 _ = held.value.remove(&self.key).?;
411 }
412 // we allocated the name
413 comp.gpa().free(self.base.name);
298 comp.gpa().destroy(self);414 comp.gpa().destroy(self);
299 }415 }
300416
301 pub fn getLlvmType(self: *Int, ofile: *ObjectFile) llvm.TypeRef {417 pub fn getLlvmType(self: *Int, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
302 @panic("TODO");418 return llvm.IntTypeInContext(llvm_context, self.key.bit_count) orelse return error.OutOfMemory;
303 }419 }
304 };420 };
305421
...@@ -310,56 +426,236 @@ pub const Type = struct {...@@ -310,56 +426,236 @@ pub const Type = struct {
310 comp.gpa().destroy(self);426 comp.gpa().destroy(self);
311 }427 }
312428
313 pub fn getLlvmType(self: *Float, ofile: *ObjectFile) llvm.TypeRef {429 pub fn getLlvmType(self: *Float, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
314 @panic("TODO");430 @panic("TODO");
315 }431 }
316 };432 };
317 pub const Pointer = struct {433 pub const Pointer = struct {
318 base: Type,434 base: Type,
319 mut: Mut,435 key: Key,
320 vol: Vol,436 garbage_node: std.atomic.Stack(*Pointer).Node,
321 size: Size,437
322 alignment: u32,438 pub const Key = struct {
439 child_type: *Type,
440 mut: Mut,
441 vol: Vol,
442 size: Size,
443 alignment: Align,
444
445 pub fn hash(self: *const Key) u32 {
446 const align_hash = switch (self.alignment) {
447 Align.Abi => 0xf201c090,
448 Align.Override => |x| x,
449 };
450 return hash_usize(@ptrToInt(self.child_type)) *%
451 hash_enum(self.mut) *%
452 hash_enum(self.vol) *%
453 hash_enum(self.size) *%
454 align_hash;
455 }
456
457 pub fn eql(self: *const Key, other: *const Key) bool {
458 if (self.child_type != other.child_type or
459 self.mut != other.mut or
460 self.vol != other.vol or
461 self.size != other.size or
462 @TagType(Align)(self.alignment) != @TagType(Align)(other.alignment))
463 {
464 return false;
465 }
466 switch (self.alignment) {
467 Align.Abi => return true,
468 Align.Override => |x| return x == other.alignment.Override,
469 }
470 }
471 };
323472
324 pub const Mut = enum {473 pub const Mut = enum {
325 Mut,474 Mut,
326 Const,475 Const,
327 };476 };
477
328 pub const Vol = enum {478 pub const Vol = enum {
329 Non,479 Non,
330 Volatile,480 Volatile,
331 };481 };
482
483 pub const Align = union(enum) {
484 Abi,
485 Override: u32,
486 };
487
332 pub const Size = builtin.TypeInfo.Pointer.Size;488 pub const Size = builtin.TypeInfo.Pointer.Size;
333489
334 pub fn destroy(self: *Pointer, comp: *Compilation) void {490 pub fn destroy(self: *Pointer, comp: *Compilation) void {
491 self.garbage_node = std.atomic.Stack(*Pointer).Node{
492 .data = self,
493 .next = undefined,
494 };
495 comp.registerGarbage(Pointer, &self.garbage_node);
496 }
497
498 pub async fn gcDestroy(self: *Pointer, comp: *Compilation) void {
499 {
500 const held = await (async comp.ptr_type_table.acquire() catch unreachable);
501 defer held.release();
502
503 _ = held.value.remove(&self.key).?;
504 }
505 self.key.child_type.base.deref(comp);
335 comp.gpa().destroy(self);506 comp.gpa().destroy(self);
336 }507 }
337508
338 pub fn get(509 pub async fn getAlignAsInt(self: *Pointer, comp: *Compilation) u32 {
510 switch (self.key.alignment) {
511 Align.Abi => return await (async self.key.child_type.getAbiAlignment(comp) catch unreachable),
512 Align.Override => |alignment| return alignment,
513 }
514 }
515
516 pub async fn get(
339 comp: *Compilation,517 comp: *Compilation,
340 elem_type: *Type,518 key: Key,
341 mut: Mut,519 ) !*Pointer {
342 vol: Vol,520 var normal_key = key;
343 size: Size,521 switch (key.alignment) {
344 alignment: u32,522 Align.Abi => {},
345 ) *Pointer {523 Align.Override => |alignment| {
346 @panic("TODO get pointer");524 const abi_align = try await (async key.child_type.getAbiAlignment(comp) catch unreachable);
525 if (abi_align == alignment) {
526 normal_key.alignment = Align.Abi;
527 }
528 },
529 }
530 {
531 const held = await (async comp.ptr_type_table.acquire() catch unreachable);
532 defer held.release();
533
534 if (held.value.get(&normal_key)) |entry| {
535 entry.value.base.base.ref();
536 return entry.value;
537 }
538 }
539
540 const self = try comp.gpa().create(Pointer{
541 .base = undefined,
542 .key = normal_key,
543 .garbage_node = undefined,
544 });
545 errdefer comp.gpa().destroy(self);
546
547 const size_str = switch (self.key.size) {
548 Size.One => "*",
549 Size.Many => "[*]",
550 Size.Slice => "[]",
551 };
552 const mut_str = switch (self.key.mut) {
553 Mut.Const => "const ",
554 Mut.Mut => "",
555 };
556 const vol_str = switch (self.key.vol) {
557 Vol.Volatile => "volatile ",
558 Vol.Non => "",
559 };
560 const name = switch (self.key.alignment) {
561 Align.Abi => try std.fmt.allocPrint(
562 comp.gpa(),
563 "{}{}{}{}",
564 size_str,
565 mut_str,
566 vol_str,
567 self.key.child_type.name,
568 ),
569 Align.Override => |alignment| try std.fmt.allocPrint(
570 comp.gpa(),
571 "{}align<{}> {}{}{}",
572 size_str,
573 alignment,
574 mut_str,
575 vol_str,
576 self.key.child_type.name,
577 ),
578 };
579 errdefer comp.gpa().free(name);
580
581 self.base.init(comp, Id.Pointer, name);
582
583 {
584 const held = await (async comp.ptr_type_table.acquire() catch unreachable);
585 defer held.release();
586
587 _ = try held.value.put(&self.key, self);
588 }
589 return self;
347 }590 }
348591
349 pub fn getLlvmType(self: *Pointer, ofile: *ObjectFile) llvm.TypeRef {592 pub fn getLlvmType(self: *Pointer, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
350 @panic("TODO");593 const elem_llvm_type = try self.key.child_type.getLlvmType(allocator, llvm_context);
594 return llvm.PointerType(elem_llvm_type, 0) orelse return error.OutOfMemory;
351 }595 }
352 };596 };
353597
354 pub const Array = struct {598 pub const Array = struct {
355 base: Type,599 base: Type,
600 key: Key,
601 garbage_node: std.atomic.Stack(*Array).Node,
602
603 pub const Key = struct {
604 elem_type: *Type,
605 len: usize,
606
607 pub fn hash(self: *const Key) u32 {
608 return hash_usize(@ptrToInt(self.elem_type)) *% hash_usize(self.len);
609 }
610
611 pub fn eql(self: *const Key, other: *const Key) bool {
612 return self.elem_type == other.elem_type and self.len == other.len;
613 }
614 };
356615
357 pub fn destroy(self: *Array, comp: *Compilation) void {616 pub fn destroy(self: *Array, comp: *Compilation) void {
617 self.key.elem_type.base.deref(comp);
358 comp.gpa().destroy(self);618 comp.gpa().destroy(self);
359 }619 }
360620
361 pub fn getLlvmType(self: *Array, ofile: *ObjectFile) llvm.TypeRef {621 pub async fn get(comp: *Compilation, key: Key) !*Array {
362 @panic("TODO");622 key.elem_type.base.ref();
623 errdefer key.elem_type.base.deref(comp);
624
625 {
626 const held = await (async comp.array_type_table.acquire() catch unreachable);
627 defer held.release();
628
629 if (held.value.get(&key)) |entry| {
630 entry.value.base.base.ref();
631 return entry.value;
632 }
633 }
634
635 const self = try comp.gpa().create(Array{
636 .base = undefined,
637 .key = key,
638 .garbage_node = undefined,
639 });
640 errdefer comp.gpa().destroy(self);
641
642 const name = try std.fmt.allocPrint(comp.gpa(), "[{}]{}", key.len, key.elem_type.name);
643 errdefer comp.gpa().free(name);
644
645 self.base.init(comp, Id.Array, name);
646
647 {
648 const held = await (async comp.array_type_table.acquire() catch unreachable);
649 defer held.release();
650
651 _ = try held.value.put(&self.key, self);
652 }
653 return self;
654 }
655
656 pub fn getLlvmType(self: *Array, allocator: *Allocator, llvm_context: llvm.ContextRef) !llvm.TypeRef {
657 const elem_llvm_type = try self.key.elem_type.getLlvmType(allocator, llvm_context);
658 return llvm.ArrayType(elem_llvm_type, @intCast(c_uint, self.key.len)) orelse return error.OutOfMemory;
363 }659 }
364 };660 };
365661
...@@ -374,6 +670,12 @@ pub const Type = struct {...@@ -374,6 +670,12 @@ pub const Type = struct {
374 pub const ComptimeInt = struct {670 pub const ComptimeInt = struct {
375 base: Type,671 base: Type,
376672
673 /// Adds 1 reference to the resulting type
674 pub fn get(comp: *Compilation) *ComptimeInt {
675 comp.comptime_int_type.base.base.ref();
676 return comp.comptime_int_type;
677 }
678
377 pub fn destroy(self: *ComptimeInt, comp: *Compilation) void {679 pub fn destroy(self: *ComptimeInt, comp: *Compilation) void {
378 comp.gpa().destroy(self);680 comp.gpa().destroy(self);
379 }681 }
...@@ -402,7 +704,7 @@ pub const Type = struct {...@@ -402,7 +704,7 @@ pub const Type = struct {
402 comp.gpa().destroy(self);704 comp.gpa().destroy(self);
403 }705 }
404706
405 pub fn getLlvmType(self: *Optional, ofile: *ObjectFile) llvm.TypeRef {707 pub fn getLlvmType(self: *Optional, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
406 @panic("TODO");708 @panic("TODO");
407 }709 }
408 };710 };
...@@ -414,7 +716,7 @@ pub const Type = struct {...@@ -414,7 +716,7 @@ pub const Type = struct {
414 comp.gpa().destroy(self);716 comp.gpa().destroy(self);
415 }717 }
416718
417 pub fn getLlvmType(self: *ErrorUnion, ofile: *ObjectFile) llvm.TypeRef {719 pub fn getLlvmType(self: *ErrorUnion, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
418 @panic("TODO");720 @panic("TODO");
419 }721 }
420 };722 };
...@@ -426,7 +728,7 @@ pub const Type = struct {...@@ -426,7 +728,7 @@ pub const Type = struct {
426 comp.gpa().destroy(self);728 comp.gpa().destroy(self);
427 }729 }
428730
429 pub fn getLlvmType(self: *ErrorSet, ofile: *ObjectFile) llvm.TypeRef {731 pub fn getLlvmType(self: *ErrorSet, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
430 @panic("TODO");732 @panic("TODO");
431 }733 }
432 };734 };
...@@ -438,7 +740,7 @@ pub const Type = struct {...@@ -438,7 +740,7 @@ pub const Type = struct {
438 comp.gpa().destroy(self);740 comp.gpa().destroy(self);
439 }741 }
440742
441 pub fn getLlvmType(self: *Enum, ofile: *ObjectFile) llvm.TypeRef {743 pub fn getLlvmType(self: *Enum, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
442 @panic("TODO");744 @panic("TODO");
443 }745 }
444 };746 };
...@@ -450,7 +752,7 @@ pub const Type = struct {...@@ -450,7 +752,7 @@ pub const Type = struct {
450 comp.gpa().destroy(self);752 comp.gpa().destroy(self);
451 }753 }
452754
453 pub fn getLlvmType(self: *Union, ofile: *ObjectFile) llvm.TypeRef {755 pub fn getLlvmType(self: *Union, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
454 @panic("TODO");756 @panic("TODO");
455 }757 }
456 };758 };
...@@ -478,7 +780,7 @@ pub const Type = struct {...@@ -478,7 +780,7 @@ pub const Type = struct {
478 comp.gpa().destroy(self);780 comp.gpa().destroy(self);
479 }781 }
480782
481 pub fn getLlvmType(self: *BoundFn, ofile: *ObjectFile) llvm.TypeRef {783 pub fn getLlvmType(self: *BoundFn, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
482 @panic("TODO");784 @panic("TODO");
483 }785 }
484 };786 };
...@@ -498,7 +800,7 @@ pub const Type = struct {...@@ -498,7 +800,7 @@ pub const Type = struct {
498 comp.gpa().destroy(self);800 comp.gpa().destroy(self);
499 }801 }
500802
501 pub fn getLlvmType(self: *Opaque, ofile: *ObjectFile) llvm.TypeRef {803 pub fn getLlvmType(self: *Opaque, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
502 @panic("TODO");804 @panic("TODO");
503 }805 }
504 };806 };
...@@ -510,8 +812,33 @@ pub const Type = struct {...@@ -510,8 +812,33 @@ pub const Type = struct {
510 comp.gpa().destroy(self);812 comp.gpa().destroy(self);
511 }813 }
512814
513 pub fn getLlvmType(self: *Promise, ofile: *ObjectFile) llvm.TypeRef {815 pub fn getLlvmType(self: *Promise, allocator: *Allocator, llvm_context: llvm.ContextRef) llvm.TypeRef {
514 @panic("TODO");816 @panic("TODO");
515 }817 }
516 };818 };
517};819};
820
821fn hash_usize(x: usize) u32 {
822 return switch (@sizeOf(usize)) {
823 4 => x,
824 8 => @truncate(u32, x *% 0xad44ee2d8e3fc13d),
825 else => @compileError("implement this hash function"),
826 };
827}
828
829fn hash_enum(x: var) u32 {
830 const rands = []u32{
831 0x85ebf64f,
832 0x3fcb3211,
833 0x240a4e8e,
834 0x40bb0e3c,
835 0x78be45af,
836 0x1ca98e37,
837 0xec56053a,
838 0x906adc48,
839 0xd4fe9763,
840 0x54c80dac,
841 };
842 comptime assert(@memberCount(@typeOf(x)) < rands.len);
843 return rands[@enumToInt(x)];
844}
src-self-hosted/value.zig+368-4
...@@ -5,12 +5,13 @@ const Compilation = @import("compilation.zig").Compilation;...@@ -5,12 +5,13 @@ const 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;7const Buffer = std.Buffer;
8const assert = std.debug.assert;
89
9/// Values are ref-counted, heap-allocated, and copy-on-write10/// Values are ref-counted, heap-allocated, and copy-on-write
10/// If there is only 1 ref then write need not copy11/// If there is only 1 ref then write need not copy
11pub const Value = struct {12pub const Value = struct {
12 id: Id,13 id: Id,
13 typeof: *Type,14 typ: *Type,
14 ref_count: std.atomic.Int(usize),15 ref_count: std.atomic.Int(usize),
1516
16 /// Thread-safe17 /// Thread-safe
...@@ -21,23 +22,37 @@ pub const Value = struct {...@@ -21,23 +22,37 @@ pub const Value = struct {
21 /// Thread-safe22 /// Thread-safe
22 pub fn deref(base: *Value, comp: *Compilation) void {23 pub fn deref(base: *Value, comp: *Compilation) void {
23 if (base.ref_count.decr() == 1) {24 if (base.ref_count.decr() == 1) {
24 base.typeof.base.deref(comp);25 base.typ.base.deref(comp);
25 switch (base.id) {26 switch (base.id) {
26 Id.Type => @fieldParentPtr(Type, "base", base).destroy(comp),27 Id.Type => @fieldParentPtr(Type, "base", base).destroy(comp),
27 Id.Fn => @fieldParentPtr(Fn, "base", base).destroy(comp),28 Id.Fn => @fieldParentPtr(Fn, "base", base).destroy(comp),
29 Id.FnProto => @fieldParentPtr(FnProto, "base", base).destroy(comp),
28 Id.Void => @fieldParentPtr(Void, "base", base).destroy(comp),30 Id.Void => @fieldParentPtr(Void, "base", base).destroy(comp),
29 Id.Bool => @fieldParentPtr(Bool, "base", base).destroy(comp),31 Id.Bool => @fieldParentPtr(Bool, "base", base).destroy(comp),
30 Id.NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(comp),32 Id.NoReturn => @fieldParentPtr(NoReturn, "base", base).destroy(comp),
31 Id.Ptr => @fieldParentPtr(Ptr, "base", base).destroy(comp),33 Id.Ptr => @fieldParentPtr(Ptr, "base", base).destroy(comp),
34 Id.Int => @fieldParentPtr(Int, "base", base).destroy(comp),
35 Id.Array => @fieldParentPtr(Array, "base", base).destroy(comp),
32 }36 }
33 }37 }
34 }38 }
3539
40 pub fn setType(base: *Value, new_type: *Type, comp: *Compilation) void {
41 base.typ.base.deref(comp);
42 new_type.base.ref();
43 base.typ = new_type;
44 }
45
36 pub fn getRef(base: *Value) *Value {46 pub fn getRef(base: *Value) *Value {
37 base.ref();47 base.ref();
38 return base;48 return base;
39 }49 }
4050
51 pub fn cast(base: *Value, comptime T: type) ?*T {
52 if (base.id != @field(Id, @typeName(T))) return null;
53 return @fieldParentPtr(T, "base", base);
54 }
55
41 pub fn dump(base: *const Value) void {56 pub fn dump(base: *const Value) void {
42 std.debug.warn("{}", @tagName(base.id));57 std.debug.warn("{}", @tagName(base.id));
43 }58 }
...@@ -46,24 +61,111 @@ pub const Value = struct {...@@ -46,24 +61,111 @@ pub const Value = struct {
46 switch (base.id) {61 switch (base.id) {
47 Id.Type => unreachable,62 Id.Type => unreachable,
48 Id.Fn => @panic("TODO"),63 Id.Fn => @panic("TODO"),
64 Id.FnProto => return @fieldParentPtr(FnProto, "base", base).getLlvmConst(ofile),
49 Id.Void => return null,65 Id.Void => return null,
50 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile),66 Id.Bool => return @fieldParentPtr(Bool, "base", base).getLlvmConst(ofile),
51 Id.NoReturn => unreachable,67 Id.NoReturn => unreachable,
52 Id.Ptr => @panic("TODO"),68 Id.Ptr => return @fieldParentPtr(Ptr, "base", base).getLlvmConst(ofile),
69 Id.Int => return @fieldParentPtr(Int, "base", base).getLlvmConst(ofile),
70 Id.Array => return @fieldParentPtr(Array, "base", base).getLlvmConst(ofile),
71 }
72 }
73
74 pub fn derefAndCopy(self: *Value, comp: *Compilation) (error{OutOfMemory}!*Value) {
75 if (self.ref_count.get() == 1) {
76 // ( Í¡° ͜ʖ Í¡°)
77 return self;
78 }
79
80 assert(self.ref_count.decr() != 1);
81 return self.copy(comp);
82 }
83
84 pub fn copy(base: *Value, comp: *Compilation) (error{OutOfMemory}!*Value) {
85 switch (base.id) {
86 Id.Type => unreachable,
87 Id.Fn => unreachable,
88 Id.FnProto => unreachable,
89 Id.Void => unreachable,
90 Id.Bool => unreachable,
91 Id.NoReturn => unreachable,
92 Id.Ptr => unreachable,
93 Id.Array => unreachable,
94 Id.Int => return &(try @fieldParentPtr(Int, "base", base).copy(comp)).base,
53 }95 }
54 }96 }
5597
98 pub const Parent = union(enum) {
99 None,
100 BaseStruct: BaseStruct,
101 BaseArray: BaseArray,
102 BaseUnion: *Value,
103 BaseScalar: *Value,
104
105 pub const BaseStruct = struct {
106 val: *Value,
107 field_index: usize,
108 };
109
110 pub const BaseArray = struct {
111 val: *Value,
112 elem_index: usize,
113 };
114 };
115
56 pub const Id = enum {116 pub const Id = enum {
57 Type,117 Type,
58 Fn,118 Fn,
59 Void,119 Void,
60 Bool,120 Bool,
61 NoReturn,121 NoReturn,
122 Array,
62 Ptr,123 Ptr,
124 Int,
125 FnProto,
63 };126 };
64127
65 pub const Type = @import("type.zig").Type;128 pub const Type = @import("type.zig").Type;
66129
130 pub const FnProto = struct {
131 base: Value,
132
133 /// The main external name that is used in the .o file.
134 /// TODO https://github.com/ziglang/zig/issues/265
135 symbol_name: Buffer,
136
137 pub fn create(comp: *Compilation, fn_type: *Type.Fn, symbol_name: Buffer) !*FnProto {
138 const self = try comp.gpa().create(FnProto{
139 .base = Value{
140 .id = Value.Id.FnProto,
141 .typ = &fn_type.base,
142 .ref_count = std.atomic.Int(usize).init(1),
143 },
144 .symbol_name = symbol_name,
145 });
146 fn_type.base.base.ref();
147 return self;
148 }
149
150 pub fn destroy(self: *FnProto, comp: *Compilation) void {
151 self.symbol_name.deinit();
152 comp.gpa().destroy(self);
153 }
154
155 pub fn getLlvmConst(self: *FnProto, ofile: *ObjectFile) !?llvm.ValueRef {
156 const llvm_fn_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
157 const llvm_fn = llvm.AddFunction(
158 ofile.module,
159 self.symbol_name.ptr(),
160 llvm_fn_type,
161 ) orelse return error.OutOfMemory;
162
163 // TODO port more logic from codegen.cpp:fn_llvm_value
164
165 return llvm_fn;
166 }
167 };
168
67 pub const Fn = struct {169 pub const Fn = struct {
68 base: Value,170 base: Value,
69171
...@@ -98,7 +200,7 @@ pub const Value = struct {...@@ -98,7 +200,7 @@ pub const Value = struct {
98 const self = try comp.gpa().create(Fn{200 const self = try comp.gpa().create(Fn{
99 .base = Value{201 .base = Value{
100 .id = Value.Id.Fn,202 .id = Value.Id.Fn,
101 .typeof = &fn_type.base,203 .typ = &fn_type.base,
102 .ref_count = std.atomic.Int(usize).init(1),204 .ref_count = std.atomic.Int(usize).init(1),
103 },205 },
104 .fndef_scope = fndef_scope,206 .fndef_scope = fndef_scope,
...@@ -187,6 +289,8 @@ pub const Value = struct {...@@ -187,6 +289,8 @@ pub const Value = struct {
187289
188 pub const Ptr = struct {290 pub const Ptr = struct {
189 base: Value,291 base: Value,
292 special: Special,
293 mut: Mut,
190294
191 pub const Mut = enum {295 pub const Mut = enum {
192 CompTimeConst,296 CompTimeConst,
...@@ -194,8 +298,268 @@ pub const Value = struct {...@@ -194,8 +298,268 @@ pub const Value = struct {
194 RunTime,298 RunTime,
195 };299 };
196300
301 pub const Special = union(enum) {
302 Scalar: *Value,
303 BaseArray: BaseArray,
304 BaseStruct: BaseStruct,
305 HardCodedAddr: u64,
306 Discard,
307 };
308
309 pub const BaseArray = struct {
310 val: *Value,
311 elem_index: usize,
312 };
313
314 pub const BaseStruct = struct {
315 val: *Value,
316 field_index: usize,
317 };
318
319 pub async fn createArrayElemPtr(
320 comp: *Compilation,
321 array_val: *Array,
322 mut: Type.Pointer.Mut,
323 size: Type.Pointer.Size,
324 elem_index: usize,
325 ) !*Ptr {
326 array_val.base.ref();
327 errdefer array_val.base.deref(comp);
328
329 const elem_type = array_val.base.typ.cast(Type.Array).?.key.elem_type;
330 const ptr_type = try await (async Type.Pointer.get(comp, Type.Pointer.Key{
331 .child_type = elem_type,
332 .mut = mut,
333 .vol = Type.Pointer.Vol.Non,
334 .size = size,
335 .alignment = Type.Pointer.Align.Abi,
336 }) catch unreachable);
337 var ptr_type_consumed = false;
338 errdefer if (!ptr_type_consumed) ptr_type.base.base.deref(comp);
339
340 const self = try comp.gpa().create(Value.Ptr{
341 .base = Value{
342 .id = Value.Id.Ptr,
343 .typ = &ptr_type.base,
344 .ref_count = std.atomic.Int(usize).init(1),
345 },
346 .special = Special{
347 .BaseArray = BaseArray{
348 .val = &array_val.base,
349 .elem_index = 0,
350 },
351 },
352 .mut = Mut.CompTimeConst,
353 });
354 ptr_type_consumed = true;
355 errdefer comp.gpa().destroy(self);
356
357 return self;
358 }
359
197 pub fn destroy(self: *Ptr, comp: *Compilation) void {360 pub fn destroy(self: *Ptr, comp: *Compilation) void {
198 comp.gpa().destroy(self);361 comp.gpa().destroy(self);
199 }362 }
363
364 pub fn getLlvmConst(self: *Ptr, ofile: *ObjectFile) !?llvm.ValueRef {
365 const llvm_type = self.base.typ.getLlvmType(ofile.arena, ofile.context);
366 // TODO carefully port the logic from codegen.cpp:gen_const_val_ptr
367 switch (self.special) {
368 Special.Scalar => |scalar| @panic("TODO"),
369 Special.BaseArray => |base_array| {
370 // TODO put this in one .o file only, and after that, generate extern references to it
371 const array_llvm_value = (try base_array.val.getLlvmConst(ofile)).?;
372 const ptr_bit_count = ofile.comp.target_ptr_bits;
373 const usize_llvm_type = llvm.IntTypeInContext(ofile.context, ptr_bit_count) orelse return error.OutOfMemory;
374 const indices = []llvm.ValueRef{
375 llvm.ConstNull(usize_llvm_type) orelse return error.OutOfMemory,
376 llvm.ConstInt(usize_llvm_type, base_array.elem_index, 0) orelse return error.OutOfMemory,
377 };
378 return llvm.ConstInBoundsGEP(
379 array_llvm_value,
380 &indices,
381 @intCast(c_uint, indices.len),
382 ) orelse return error.OutOfMemory;
383 },
384 Special.BaseStruct => |base_struct| @panic("TODO"),
385 Special.HardCodedAddr => |addr| @panic("TODO"),
386 Special.Discard => unreachable,
387 }
388 }
389 };
390
391 pub const Array = struct {
392 base: Value,
393 special: Special,
394
395 pub const Special = union(enum) {
396 Undefined,
397 OwnedBuffer: []u8,
398 Explicit: Data,
399 };
400
401 pub const Data = struct {
402 parent: Parent,
403 elements: []*Value,
404 };
405
406 /// Takes ownership of buffer
407 pub async fn createOwnedBuffer(comp: *Compilation, buffer: []u8) !*Array {
408 const u8_type = Type.Int.get_u8(comp);
409 defer u8_type.base.base.deref(comp);
410
411 const array_type = try await (async Type.Array.get(comp, Type.Array.Key{
412 .elem_type = &u8_type.base,
413 .len = buffer.len,
414 }) catch unreachable);
415 errdefer array_type.base.base.deref(comp);
416
417 const self = try comp.gpa().create(Value.Array{
418 .base = Value{
419 .id = Value.Id.Array,
420 .typ = &array_type.base,
421 .ref_count = std.atomic.Int(usize).init(1),
422 },
423 .special = Special{ .OwnedBuffer = buffer },
424 });
425 errdefer comp.gpa().destroy(self);
426
427 return self;
428 }
429
430 pub fn destroy(self: *Array, comp: *Compilation) void {
431 switch (self.special) {
432 Special.Undefined => {},
433 Special.OwnedBuffer => |buf| {
434 comp.gpa().free(buf);
435 },
436 Special.Explicit => {},
437 }
438 comp.gpa().destroy(self);
439 }
440
441 pub fn getLlvmConst(self: *Array, ofile: *ObjectFile) !?llvm.ValueRef {
442 switch (self.special) {
443 Special.Undefined => {
444 const llvm_type = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
445 return llvm.GetUndef(llvm_type);
446 },
447 Special.OwnedBuffer => |buf| {
448 const dont_null_terminate = 1;
449 const llvm_str_init = llvm.ConstStringInContext(
450 ofile.context,
451 buf.ptr,
452 @intCast(c_uint, buf.len),
453 dont_null_terminate,
454 ) orelse return error.OutOfMemory;
455 const str_init_type = llvm.TypeOf(llvm_str_init);
456 const global = llvm.AddGlobal(ofile.module, str_init_type, c"") orelse return error.OutOfMemory;
457 llvm.SetInitializer(global, llvm_str_init);
458 llvm.SetLinkage(global, llvm.PrivateLinkage);
459 llvm.SetGlobalConstant(global, 1);
460 llvm.SetUnnamedAddr(global, 1);
461 llvm.SetAlignment(global, llvm.ABIAlignmentOfType(ofile.comp.target_data_ref, str_init_type));
462 return global;
463 },
464 Special.Explicit => @panic("TODO"),
465 }
466
467 //{
468 // uint64_t len = type_entry->data.array.len;
469 // if (const_val->data.x_array.special == ConstArraySpecialUndef) {
470 // return LLVMGetUndef(type_entry->type_ref);
471 // }
472
473 // LLVMValueRef *values = allocate<LLVMValueRef>(len);
474 // LLVMTypeRef element_type_ref = type_entry->data.array.child_type->type_ref;
475 // bool make_unnamed_struct = false;
476 // for (uint64_t i = 0; i < len; i += 1) {
477 // ConstExprValue *elem_value = &const_val->data.x_array.s_none.elements[i];
478 // LLVMValueRef val = gen_const_val(g, elem_value, "");
479 // values[i] = val;
480 // make_unnamed_struct = make_unnamed_struct || is_llvm_value_unnamed_type(elem_value->type, val);
481 // }
482 // if (make_unnamed_struct) {
483 // return LLVMConstStruct(values, len, true);
484 // } else {
485 // return LLVMConstArray(element_type_ref, values, (unsigned)len);
486 // }
487 //}
488 }
489 };
490
491 pub const Int = struct {
492 base: Value,
493 big_int: std.math.big.Int,
494
495 pub fn createFromString(comp: *Compilation, typ: *Type, base: u8, value: []const u8) !*Int {
496 const self = try comp.gpa().create(Value.Int{
497 .base = Value{
498 .id = Value.Id.Int,
499 .typ = typ,
500 .ref_count = std.atomic.Int(usize).init(1),
501 },
502 .big_int = undefined,
503 });
504 typ.base.ref();
505 errdefer comp.gpa().destroy(self);
506
507 self.big_int = try std.math.big.Int.init(comp.gpa());
508 errdefer self.big_int.deinit();
509
510 try self.big_int.setString(base, value);
511
512 return self;
513 }
514
515 pub fn getLlvmConst(self: *Int, ofile: *ObjectFile) !?llvm.ValueRef {
516 switch (self.base.typ.id) {
517 Type.Id.Int => {
518 const type_ref = try self.base.typ.getLlvmType(ofile.arena, ofile.context);
519 if (self.big_int.len == 0) {
520 return llvm.ConstNull(type_ref);
521 }
522 const unsigned_val = if (self.big_int.len == 1) blk: {
523 break :blk llvm.ConstInt(type_ref, self.big_int.limbs[0], @boolToInt(false));
524 } else if (@sizeOf(std.math.big.Limb) == @sizeOf(u64)) blk: {
525 break :blk llvm.ConstIntOfArbitraryPrecision(
526 type_ref,
527 @intCast(c_uint, self.big_int.len),
528 @ptrCast([*]u64, self.big_int.limbs.ptr),
529 );
530 } else {
531 @compileError("std.math.Big.Int.Limb size does not match LLVM");
532 };
533 return if (self.big_int.positive) unsigned_val else llvm.ConstNeg(unsigned_val);
534 },
535 Type.Id.ComptimeInt => unreachable,
536 else => unreachable,
537 }
538 }
539
540 pub fn copy(old: *Int, comp: *Compilation) !*Int {
541 old.base.typ.base.ref();
542 errdefer old.base.typ.base.deref(comp);
543
544 const new = try comp.gpa().create(Value.Int{
545 .base = Value{
546 .id = Value.Id.Int,
547 .typ = old.base.typ,
548 .ref_count = std.atomic.Int(usize).init(1),
549 },
550 .big_int = undefined,
551 });
552 errdefer comp.gpa().destroy(new);
553
554 new.big_int = try old.big_int.clone();
555 errdefer new.big_int.deinit();
556
557 return new;
558 }
559
560 pub fn destroy(self: *Int, comp: *Compilation) void {
561 self.big_int.deinit();
562 comp.gpa().destroy(self);
563 }
200 };564 };
201};565};
src/analyze.cpp+3-4
...@@ -4379,7 +4379,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {...@@ -4379,7 +4379,7 @@ bool handle_is_ptr(TypeTableEntry *type_entry) {
43794379
4380static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {4380static ZigWindowsSDK *get_windows_sdk(CodeGen *g) {
4381 if (g->win_sdk == nullptr) {4381 if (g->win_sdk == nullptr) {
4382 if (os_find_windows_sdk(&g->win_sdk)) {4382 if (zig_find_windows_sdk(&g->win_sdk)) {
4383 fprintf(stderr, "unable to determine windows sdk path\n");4383 fprintf(stderr, "unable to determine windows sdk path\n");
4384 exit(1);4384 exit(1);
4385 }4385 }
...@@ -4499,12 +4499,11 @@ void find_libc_lib_path(CodeGen *g) {...@@ -4499,12 +4499,11 @@ void find_libc_lib_path(CodeGen *g) {
4499 ZigWindowsSDK *sdk = get_windows_sdk(g);4499 ZigWindowsSDK *sdk = get_windows_sdk(g);
45004500
4501 if (g->msvc_lib_dir == nullptr) {4501 if (g->msvc_lib_dir == nullptr) {
4502 Buf* vc_lib_dir = buf_alloc();4502 if (sdk->msvc_lib_dir_ptr == nullptr) {
4503 if (os_get_win32_vcruntime_path(vc_lib_dir, g->zig_target.arch.arch)) {
4504 fprintf(stderr, "Unable to determine vcruntime path. --msvc-lib-dir");4503 fprintf(stderr, "Unable to determine vcruntime path. --msvc-lib-dir");
4505 exit(1);4504 exit(1);
4506 }4505 }
4507 g->msvc_lib_dir = vc_lib_dir;4506 g->msvc_lib_dir = buf_create_from_mem(sdk->msvc_lib_dir_ptr, sdk->msvc_lib_dir_len);
4508 }4507 }
45094508
4510 if (g->libc_lib_dir == nullptr) {4509 if (g->libc_lib_dir == nullptr) {
src/link.cpp+1-1
...@@ -901,7 +901,7 @@ static void construct_linker_job_macho(LinkJob *lj) {...@@ -901,7 +901,7 @@ static void construct_linker_job_macho(LinkJob *lj) {
901 if (strchr(buf_ptr(link_lib->name), '/') == nullptr) {901 if (strchr(buf_ptr(link_lib->name), '/') == nullptr) {
902 Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));902 Buf *arg = buf_sprintf("-l%s", buf_ptr(link_lib->name));
903 lj->args.append(buf_ptr(arg));903 lj->args.append(buf_ptr(arg));
904 } else {904 } else {
905 lj->args.append(buf_ptr(link_lib->name));905 lj->args.append(buf_ptr(link_lib->name));
906 }906 }
907 }907 }
src/os.cpp+4-244
...@@ -26,7 +26,6 @@...@@ -26,7 +26,6 @@
26#include <windows.h>26#include <windows.h>
27#include <io.h>27#include <io.h>
28#include <fcntl.h>28#include <fcntl.h>
29#include "windows_com.hpp"
3029
31typedef SSIZE_T ssize_t;30typedef SSIZE_T ssize_t;
32#else31#else
...@@ -1115,249 +1114,10 @@ void os_stderr_set_color(TermColor color) {...@@ -1115,249 +1114,10 @@ void os_stderr_set_color(TermColor color) {
1115#endif1114#endif
1116}1115}
11171116
1118int os_find_windows_sdk(ZigWindowsSDK **out_sdk) {
1119#if defined(ZIG_OS_WINDOWS)
1120 ZigWindowsSDK *result_sdk = allocate<ZigWindowsSDK>(1);
1121 buf_resize(&result_sdk->path10, 0);
1122 buf_resize(&result_sdk->path81, 0);
1123
1124 HKEY key;
1125 HRESULT rc;
1126 rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &key);
1127 if (rc != ERROR_SUCCESS) {
1128 return ErrorFileNotFound;
1129 }
1130
1131 {
1132 DWORD tmp_buf_len = MAX_PATH;
1133 buf_resize(&result_sdk->path10, tmp_buf_len);
1134 rc = RegQueryValueEx(key, "KitsRoot10", NULL, NULL, (LPBYTE)buf_ptr(&result_sdk->path10), &tmp_buf_len);
1135 if (rc == ERROR_FILE_NOT_FOUND) {
1136 buf_resize(&result_sdk->path10, 0);
1137 } else {
1138 buf_resize(&result_sdk->path10, tmp_buf_len);
1139 }
1140 }
1141 {
1142 DWORD tmp_buf_len = MAX_PATH;
1143 buf_resize(&result_sdk->path81, tmp_buf_len);
1144 rc = RegQueryValueEx(key, "KitsRoot81", NULL, NULL, (LPBYTE)buf_ptr(&result_sdk->path81), &tmp_buf_len);
1145 if (rc == ERROR_FILE_NOT_FOUND) {
1146 buf_resize(&result_sdk->path81, 0);
1147 } else {
1148 buf_resize(&result_sdk->path81, tmp_buf_len);
1149 }
1150 }
1151
1152 if (buf_len(&result_sdk->path10) != 0) {
1153 Buf *sdk_lib_dir = buf_sprintf("%s\\Lib\\*", buf_ptr(&result_sdk->path10));
1154
1155 // enumerate files in sdk path looking for latest version
1156 WIN32_FIND_DATA ffd;
1157 HANDLE hFind = FindFirstFileA(buf_ptr(sdk_lib_dir), &ffd);
1158 if (hFind == INVALID_HANDLE_VALUE) {
1159 return ErrorFileNotFound;
1160 }
1161 int v0 = 0, v1 = 0, v2 = 0, v3 = 0;
1162 bool found_version_dir = false;
1163 for (;;) {
1164 if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1165 int c0 = 0, c1 = 0, c2 = 0, c3 = 0;
1166 sscanf(ffd.cFileName, "%d.%d.%d.%d", &c0, &c1, &c2, &c3);
1167 if (c0 == 10 && c1 == 0 && c2 == 10240 && c3 == 0) {
1168 // Microsoft released 26624 as 10240 accidentally.
1169 // https://developer.microsoft.com/en-us/windows/downloads/sdk-archive
1170 c2 = 26624;
1171 }
1172 if ((c0 > v0) || (c1 > v1) || (c2 > v2) || (c3 > v3)) {
1173 v0 = c0, v1 = c1, v2 = c2, v3 = c3;
1174 buf_init_from_str(&result_sdk->version10, ffd.cFileName);
1175 found_version_dir = true;
1176 }
1177 }
1178 if (FindNextFile(hFind, &ffd) == 0) {
1179 FindClose(hFind);
1180 break;
1181 }
1182 }
1183 if (!found_version_dir) {
1184 buf_resize(&result_sdk->path10, 0);
1185 }
1186 }
1187
1188 if (buf_len(&result_sdk->path81) != 0) {
1189 Buf *sdk_lib_dir = buf_sprintf("%s\\Lib\\winv*", buf_ptr(&result_sdk->path81));
1190
1191 // enumerate files in sdk path looking for latest version
1192 WIN32_FIND_DATA ffd;
1193 HANDLE hFind = FindFirstFileA(buf_ptr(sdk_lib_dir), &ffd);
1194 if (hFind == INVALID_HANDLE_VALUE) {
1195 return ErrorFileNotFound;
1196 }
1197 int v0 = 0, v1 = 0;
1198 bool found_version_dir = false;
1199 for (;;) {
1200 if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
1201 int c0 = 0, c1 = 0;
1202 sscanf(ffd.cFileName, "winv%d.%d", &c0, &c1);
1203 if ((c0 > v0) || (c1 > v1)) {
1204 v0 = c0, v1 = c1;
1205 buf_init_from_str(&result_sdk->version81, ffd.cFileName);
1206 found_version_dir = true;
1207 }
1208 }
1209 if (FindNextFile(hFind, &ffd) == 0) {
1210 FindClose(hFind);
1211 break;
1212 }
1213 }
1214 if (!found_version_dir) {
1215 buf_resize(&result_sdk->path81, 0);
1216 }
1217 }
1218
1219 *out_sdk = result_sdk;
1220 return 0;
1221#else
1222 return ErrorFileNotFound;
1223#endif
1224}
1225
1226int os_get_win32_vcruntime_path(Buf* output_buf, ZigLLVM_ArchType platform_type) {
1227#if defined(ZIG_OS_WINDOWS)
1228 buf_resize(output_buf, 0);
1229 //COM Smart Pointerse requires explicit scope
1230 {
1231 HRESULT rc;
1232 rc = CoInitializeEx(NULL, COINIT_MULTITHREADED);
1233 if (rc != S_OK) {
1234 goto com_done;
1235 }
1236
1237 //This COM class is installed when a VS2017
1238 ISetupConfigurationPtr setup_config;
1239 rc = setup_config.CreateInstance(__uuidof(SetupConfiguration));
1240 if (rc != S_OK) {
1241 goto com_done;
1242 }
1243
1244 IEnumSetupInstancesPtr all_instances;
1245 rc = setup_config->EnumInstances(&all_instances);
1246 if (rc != S_OK) {
1247 goto com_done;
1248 }
1249
1250 ISetupInstance* curr_instance;
1251 ULONG found_inst;
1252 while ((rc = all_instances->Next(1, &curr_instance, &found_inst) == S_OK)) {
1253 BSTR bstr_inst_path;
1254 rc = curr_instance->GetInstallationPath(&bstr_inst_path);
1255 if (rc != S_OK) {
1256 goto com_done;
1257 }
1258 //BSTRs are UTF-16 encoded, so we need to convert the string & adjust the length
1259 UINT bstr_path_len = *((UINT*)bstr_inst_path - 1);
1260 ULONG tmp_path_len = bstr_path_len / 2 + 1;
1261 char* conv_path = (char*)bstr_inst_path;
1262 char *tmp_path = (char*)alloca(tmp_path_len);
1263 memset(tmp_path, 0, tmp_path_len);
1264 uint32_t c = 0;
1265 for (uint32_t i = 0; i < bstr_path_len; i += 2) {
1266 tmp_path[c] = conv_path[i];
1267 ++c;
1268 assert(c != tmp_path_len);
1269 }
1270
1271 buf_append_str(output_buf, tmp_path);
1272 buf_append_char(output_buf, '\\');
1273
1274 Buf* tmp_buf = buf_alloc();
1275 buf_append_buf(tmp_buf, output_buf);
1276 buf_append_str(tmp_buf, "VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt");
1277 FILE* tools_file = fopen(buf_ptr(tmp_buf), "r");
1278 if (!tools_file) {
1279 goto com_done;
1280 }
1281 memset(tmp_path, 0, tmp_path_len);
1282 fgets(tmp_path, tmp_path_len, tools_file);
1283 strtok(tmp_path, " \r\n");
1284 fclose(tools_file);
1285 buf_appendf(output_buf, "VC\\Tools\\MSVC\\%s\\lib\\", tmp_path);
1286 switch (platform_type) {
1287 case ZigLLVM_x86:
1288 buf_append_str(output_buf, "x86\\");
1289 break;
1290 case ZigLLVM_x86_64:
1291 buf_append_str(output_buf, "x64\\");
1292 break;
1293 case ZigLLVM_arm:
1294 buf_append_str(output_buf, "arm\\");
1295 break;
1296 default:
1297 zig_panic("Attemped to use vcruntime for non-supported platform.");
1298 }
1299 buf_resize(tmp_buf, 0);
1300 buf_append_buf(tmp_buf, output_buf);
1301 buf_append_str(tmp_buf, "vcruntime.lib");
1302
1303 if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
1304 return 0;
1305 }
1306 }
1307 }
1308
1309com_done:;
1310 HKEY key;
1311 HRESULT rc;
1312 rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key);
1313 if (rc != ERROR_SUCCESS) {
1314 return ErrorFileNotFound;
1315 }
1316
1317 DWORD dw_type = 0;
1318 DWORD cb_data = 0;
1319 rc = RegQueryValueEx(key, "14.0", NULL, &dw_type, NULL, &cb_data);
1320 if ((rc == ERROR_FILE_NOT_FOUND) || (REG_SZ != dw_type)) {
1321 return ErrorFileNotFound;
1322 }
1323
1324 Buf* tmp_buf = buf_alloc_fixed(cb_data);
1325 RegQueryValueExA(key, "14.0", NULL, NULL, (LPBYTE)buf_ptr(tmp_buf), &cb_data);
1326 //RegQueryValueExA returns the length of the string INCLUDING the null terminator
1327 buf_resize(tmp_buf, cb_data-1);
1328 buf_append_str(tmp_buf, "VC\\Lib\\");
1329 switch (platform_type) {
1330 case ZigLLVM_x86:
1331 //x86 is in the root of the Lib folder
1332 break;
1333 case ZigLLVM_x86_64:
1334 buf_append_str(tmp_buf, "amd64\\");
1335 break;
1336 case ZigLLVM_arm:
1337 buf_append_str(tmp_buf, "arm\\");
1338 break;
1339 default:
1340 zig_panic("Attemped to use vcruntime for non-supported platform.");
1341 }
1342
1343 buf_append_buf(output_buf, tmp_buf);
1344 buf_append_str(tmp_buf, "vcruntime.lib");
1345
1346 if (GetFileAttributesA(buf_ptr(tmp_buf)) != INVALID_FILE_ATTRIBUTES) {
1347 return 0;
1348 } else {
1349 buf_resize(output_buf, 0);
1350 return ErrorFileNotFound;
1351 }
1352#else
1353 return ErrorFileNotFound;
1354#endif
1355}
1356
1357int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {1117int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchType platform_type) {
1358#if defined(ZIG_OS_WINDOWS)1118#if defined(ZIG_OS_WINDOWS)
1359 buf_resize(output_buf, 0);1119 buf_resize(output_buf, 0);
1360 buf_appendf(output_buf, "%s\\Lib\\%s\\ucrt\\", buf_ptr(&sdk->path10), buf_ptr(&sdk->version10));1120 buf_appendf(output_buf, "%s\\Lib\\%s\\ucrt\\", sdk->path10_ptr, sdk->version10_ptr);
1361 switch (platform_type) {1121 switch (platform_type) {
1362 case ZigLLVM_x86:1122 case ZigLLVM_x86:
1363 buf_append_str(output_buf, "x86\\");1123 buf_append_str(output_buf, "x86\\");
...@@ -1389,7 +1149,7 @@ int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch...@@ -1389,7 +1149,7 @@ int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_Arch
1389int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {1149int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf* output_buf) {
1390#if defined(ZIG_OS_WINDOWS)1150#if defined(ZIG_OS_WINDOWS)
1391 buf_resize(output_buf, 0);1151 buf_resize(output_buf, 0);
1392 buf_appendf(output_buf, "%s\\Include\\%s\\ucrt", buf_ptr(&sdk->path10), buf_ptr(&sdk->version10));1152 buf_appendf(output_buf, "%s\\Include\\%s\\ucrt", sdk->path10_ptr, sdk->version10_ptr);
1393 if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) {1153 if (GetFileAttributesA(buf_ptr(output_buf)) != INVALID_FILE_ATTRIBUTES) {
1394 return 0;1154 return 0;
1395 }1155 }
...@@ -1406,7 +1166,7 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy...@@ -1406,7 +1166,7 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
1406#if defined(ZIG_OS_WINDOWS)1166#if defined(ZIG_OS_WINDOWS)
1407 {1167 {
1408 buf_resize(output_buf, 0);1168 buf_resize(output_buf, 0);
1409 buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", buf_ptr(&sdk->path10), buf_ptr(&sdk->version10));1169 buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", sdk->path10_ptr, sdk->version10_ptr);
1410 switch (platform_type) {1170 switch (platform_type) {
1411 case ZigLLVM_x86:1171 case ZigLLVM_x86:
1412 buf_append_str(output_buf, "x86\\");1172 buf_append_str(output_buf, "x86\\");
...@@ -1429,7 +1189,7 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy...@@ -1429,7 +1189,7 @@ int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf* output_buf, ZigLLVM_ArchTy
1429 }1189 }
1430 {1190 {
1431 buf_resize(output_buf, 0);1191 buf_resize(output_buf, 0);
1432 buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", buf_ptr(&sdk->path81), buf_ptr(&sdk->version81));1192 buf_appendf(output_buf, "%s\\Lib\\%s\\um\\", sdk->path81_ptr, sdk->version81_ptr);
1433 switch (platform_type) {1193 switch (platform_type) {
1434 case ZigLLVM_x86:1194 case ZigLLVM_x86:
1435 buf_append_str(output_buf, "x86\\");1195 buf_append_str(output_buf, "x86\\");
src/os.hpp+1-9
...@@ -12,6 +12,7 @@...@@ -12,6 +12,7 @@
12#include "buffer.hpp"12#include "buffer.hpp"
13#include "error.hpp"13#include "error.hpp"
14#include "zig_llvm.h"14#include "zig_llvm.h"
15#include "windows_sdk.h"
1516
16#include <stdio.h>17#include <stdio.h>
17#include <inttypes.h>18#include <inttypes.h>
...@@ -79,15 +80,6 @@ bool os_is_sep(uint8_t c);...@@ -79,15 +80,6 @@ bool os_is_sep(uint8_t c);
7980
80int os_self_exe_path(Buf *out_path);81int os_self_exe_path(Buf *out_path);
8182
82struct ZigWindowsSDK {
83 Buf path10;
84 Buf version10;
85 Buf path81;
86 Buf version81;
87};
88
89int os_find_windows_sdk(ZigWindowsSDK **out_sdk);
90int os_get_win32_vcruntime_path(Buf *output_buf, ZigLLVM_ArchType platform_type);
91int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);83int os_get_win32_ucrt_include_path(ZigWindowsSDK *sdk, Buf *output_buf);
92int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);84int os_get_win32_ucrt_lib_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
93int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);85int os_get_win32_kern32_path(ZigWindowsSDK *sdk, Buf *output_buf, ZigLLVM_ArchType platform_type);
src/windows_sdk.cpp created+352
...@@ -0,0 +1,352 @@
1/*
2 * Copyright (c) 2018 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#include "windows_sdk.h"
9
10#if defined(_WIN32)
11
12#include "windows_com.hpp"
13#include <inttypes.h>
14#include <assert.h>
15
16struct ZigWindowsSDKPrivate {
17 ZigWindowsSDK base;
18};
19
20enum NativeArch {
21 NativeArchArm,
22 NativeArchi386,
23 NativeArchx86_64,
24};
25
26#if defined(_M_ARM) || defined(__arm_)
27static const NativeArch native_arch = NativeArchArm;
28#endif
29#if defined(_M_IX86) || defined(__i386__)
30static const NativeArch native_arch = NativeArchi386;
31#endif
32#if defined(_M_X64) || defined(__x86_64__)
33static const NativeArch native_arch = NativeArchx86_64;
34#endif
35
36void zig_free_windows_sdk(struct ZigWindowsSDK *sdk) {
37 if (sdk == nullptr) {
38 return;
39 }
40 free((void*)sdk->path10_ptr);
41 free((void*)sdk->version10_ptr);
42 free((void*)sdk->path81_ptr);
43 free((void*)sdk->version81_ptr);
44 free((void*)sdk->msvc_lib_dir_ptr);
45}
46
47static ZigFindWindowsSdkError find_msvc_lib_dir(ZigWindowsSDKPrivate *priv) {
48 //COM Smart Pointers requires explicit scope
49 {
50 HRESULT rc = CoInitializeEx(NULL, COINIT_MULTITHREADED);
51 if (rc != S_OK && rc != S_FALSE) {
52 goto com_done;
53 }
54
55 //This COM class is installed when a VS2017
56 ISetupConfigurationPtr setup_config;
57 rc = setup_config.CreateInstance(__uuidof(SetupConfiguration));
58 if (rc != S_OK) {
59 goto com_done;
60 }
61
62 IEnumSetupInstancesPtr all_instances;
63 rc = setup_config->EnumInstances(&all_instances);
64 if (rc != S_OK) {
65 goto com_done;
66 }
67
68 ISetupInstance* curr_instance;
69 ULONG found_inst;
70 while ((rc = all_instances->Next(1, &curr_instance, &found_inst) == S_OK)) {
71 BSTR bstr_inst_path;
72 rc = curr_instance->GetInstallationPath(&bstr_inst_path);
73 if (rc != S_OK) {
74 goto com_done;
75 }
76 //BSTRs are UTF-16 encoded, so we need to convert the string & adjust the length
77 //TODO call an actual function to do this
78 UINT bstr_path_len = *((UINT*)bstr_inst_path - 1);
79 ULONG tmp_path_len = bstr_path_len / 2 + 1;
80 char* conv_path = (char*)bstr_inst_path;
81 // TODO don't use alloca
82 char *tmp_path = (char*)alloca(tmp_path_len);
83 memset(tmp_path, 0, tmp_path_len);
84 uint32_t c = 0;
85 for (uint32_t i = 0; i < bstr_path_len; i += 2) {
86 tmp_path[c] = conv_path[i];
87 ++c;
88 assert(c != tmp_path_len);
89 }
90 char output_path[4096];
91 output_path[0] = 0;
92 char *out_append_ptr = output_path;
93
94 out_append_ptr += sprintf(out_append_ptr, "%s\\", tmp_path);
95
96 char tmp_buf[4096];
97 sprintf(tmp_buf, "%s%s", output_path, "VC\\Auxiliary\\Build\\Microsoft.VCToolsVersion.default.txt");
98 FILE* tools_file = fopen(tmp_buf, "rb");
99 if (!tools_file) {
100 goto com_done;
101 }
102 memset(tmp_path, 0, tmp_path_len);
103 fgets(tmp_path, tmp_path_len, tools_file);
104 strtok(tmp_path, " \r\n");
105 fclose(tools_file);
106 out_append_ptr += sprintf(out_append_ptr, "VC\\Tools\\MSVC\\%s\\lib\\", tmp_path);
107 switch (native_arch) {
108 case NativeArchi386:
109 out_append_ptr += sprintf(out_append_ptr, "x86\\");
110 break;
111 case NativeArchx86_64:
112 out_append_ptr += sprintf(out_append_ptr, "x64\\");
113 break;
114 case NativeArchArm:
115 out_append_ptr += sprintf(out_append_ptr, "arm\\");
116 break;
117 }
118 sprintf(tmp_buf, "%s%s", output_path, "vcruntime.lib");
119
120 if (GetFileAttributesA(tmp_buf) != INVALID_FILE_ATTRIBUTES) {
121 priv->base.msvc_lib_dir_ptr = strdup(output_path);
122 if (priv->base.msvc_lib_dir_ptr == nullptr) {
123 return ZigFindWindowsSdkErrorOutOfMemory;
124 }
125 priv->base.msvc_lib_dir_len = strlen(priv->base.msvc_lib_dir_ptr);
126 return ZigFindWindowsSdkErrorNone;
127 }
128 }
129 }
130
131com_done:;
132 HKEY key;
133 HRESULT rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\VisualStudio\\SxS\\VS7", 0,
134 KEY_QUERY_VALUE | KEY_WOW64_32KEY, &key);
135 if (rc != ERROR_SUCCESS) {
136 return ZigFindWindowsSdkErrorNotFound;
137 }
138
139 DWORD dw_type = 0;
140 DWORD cb_data = 0;
141 rc = RegQueryValueEx(key, "14.0", NULL, &dw_type, NULL, &cb_data);
142 if ((rc == ERROR_FILE_NOT_FOUND) || (REG_SZ != dw_type)) {
143 return ZigFindWindowsSdkErrorNotFound;
144 }
145
146 char tmp_buf[4096];
147
148 RegQueryValueExA(key, "14.0", NULL, NULL, (LPBYTE)tmp_buf, &cb_data);
149 // RegQueryValueExA returns the length of the string INCLUDING the null terminator
150 char *tmp_buf_append_ptr = tmp_buf + (cb_data - 1);
151 tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "VC\\Lib\\");
152 switch (native_arch) {
153 case NativeArchi386:
154 //x86 is in the root of the Lib folder
155 break;
156 case NativeArchx86_64:
157 tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "amd64\\");
158 break;
159 case NativeArchArm:
160 tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "arm\\");
161 break;
162 }
163
164 char *output_path = strdup(tmp_buf);
165 if (output_path == nullptr) {
166 return ZigFindWindowsSdkErrorOutOfMemory;
167 }
168
169 tmp_buf_append_ptr += sprintf(tmp_buf_append_ptr, "vcruntime.lib");
170
171 if (GetFileAttributesA(tmp_buf) != INVALID_FILE_ATTRIBUTES) {
172 priv->base.msvc_lib_dir_ptr = output_path;
173 priv->base.msvc_lib_dir_len = strlen(output_path);
174 return ZigFindWindowsSdkErrorNone;
175 } else {
176 free(output_path);
177 return ZigFindWindowsSdkErrorNotFound;
178 }
179}
180
181static ZigFindWindowsSdkError find_10_version(ZigWindowsSDKPrivate *priv) {
182 if (priv->base.path10_ptr == nullptr)
183 return ZigFindWindowsSdkErrorNone;
184
185 char sdk_lib_dir[4096];
186 int n = snprintf(sdk_lib_dir, 4096, "%s\\Lib\\*", priv->base.path10_ptr);
187 if (n < 0 || n >= 4096) {
188 return ZigFindWindowsSdkErrorPathTooLong;
189 }
190
191 // enumerate files in sdk path looking for latest version
192 WIN32_FIND_DATA ffd;
193 HANDLE hFind = FindFirstFileA(sdk_lib_dir, &ffd);
194 if (hFind == INVALID_HANDLE_VALUE) {
195 return ZigFindWindowsSdkErrorNotFound;
196 }
197 int v0 = 0, v1 = 0, v2 = 0, v3 = 0;
198 for (;;) {
199 if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
200 int c0 = 0, c1 = 0, c2 = 0, c3 = 0;
201 sscanf(ffd.cFileName, "%d.%d.%d.%d", &c0, &c1, &c2, &c3);
202 if (c0 == 10 && c1 == 0 && c2 == 10240 && c3 == 0) {
203 // Microsoft released 26624 as 10240 accidentally.
204 // https://developer.microsoft.com/en-us/windows/downloads/sdk-archive
205 c2 = 26624;
206 }
207 if ((c0 > v0) || (c1 > v1) || (c2 > v2) || (c3 > v3)) {
208 v0 = c0, v1 = c1, v2 = c2, v3 = c3;
209 free((void*)priv->base.version10_ptr);
210 priv->base.version10_ptr = strdup(ffd.cFileName);
211 if (priv->base.version10_ptr == nullptr) {
212 FindClose(hFind);
213 return ZigFindWindowsSdkErrorOutOfMemory;
214 }
215 }
216 }
217 if (FindNextFile(hFind, &ffd) == 0) {
218 FindClose(hFind);
219 break;
220 }
221 }
222 priv->base.version10_len = strlen(priv->base.version10_ptr);
223 return ZigFindWindowsSdkErrorNone;
224}
225
226static ZigFindWindowsSdkError find_81_version(ZigWindowsSDKPrivate *priv) {
227 if (priv->base.path81_ptr == nullptr)
228 return ZigFindWindowsSdkErrorNone;
229
230 char sdk_lib_dir[4096];
231 int n = snprintf(sdk_lib_dir, 4096, "%s\\Lib\\winv*", priv->base.path81_ptr);
232 if (n < 0 || n >= 4096) {
233 return ZigFindWindowsSdkErrorPathTooLong;
234 }
235
236 // enumerate files in sdk path looking for latest version
237 WIN32_FIND_DATA ffd;
238 HANDLE hFind = FindFirstFileA(sdk_lib_dir, &ffd);
239 if (hFind == INVALID_HANDLE_VALUE) {
240 return ZigFindWindowsSdkErrorNotFound;
241 }
242 int v0 = 0, v1 = 0;
243 for (;;) {
244 if (ffd.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
245 int c0 = 0, c1 = 0;
246 sscanf(ffd.cFileName, "winv%d.%d", &c0, &c1);
247 if ((c0 > v0) || (c1 > v1)) {
248 v0 = c0, v1 = c1;
249 free((void*)priv->base.version81_ptr);
250 priv->base.version81_ptr = strdup(ffd.cFileName);
251 if (priv->base.version81_ptr == nullptr) {
252 FindClose(hFind);
253 return ZigFindWindowsSdkErrorOutOfMemory;
254 }
255 }
256 }
257 if (FindNextFile(hFind, &ffd) == 0) {
258 FindClose(hFind);
259 break;
260 }
261 }
262 priv->base.version81_len = strlen(priv->base.version81_ptr);
263 return ZigFindWindowsSdkErrorNone;
264}
265
266ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk) {
267 ZigWindowsSDKPrivate *priv = (ZigWindowsSDKPrivate*)calloc(1, sizeof(ZigWindowsSDKPrivate));
268 if (priv == nullptr) {
269 return ZigFindWindowsSdkErrorOutOfMemory;
270 }
271
272 HKEY key;
273 HRESULT rc;
274 rc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows Kits\\Installed Roots", 0,
275 KEY_QUERY_VALUE | KEY_WOW64_32KEY | KEY_ENUMERATE_SUB_KEYS, &key);
276 if (rc != ERROR_SUCCESS) {
277 zig_free_windows_sdk(&priv->base);
278 return ZigFindWindowsSdkErrorNotFound;
279 }
280
281 {
282 DWORD tmp_buf_len = MAX_PATH;
283 priv->base.path10_ptr = (const char *)calloc(tmp_buf_len, 1);
284 if (priv->base.path10_ptr == nullptr) {
285 zig_free_windows_sdk(&priv->base);
286 return ZigFindWindowsSdkErrorOutOfMemory;
287 }
288 rc = RegQueryValueEx(key, "KitsRoot10", NULL, NULL, (LPBYTE)priv->base.path10_ptr, &tmp_buf_len);
289 if (rc == ERROR_SUCCESS) {
290 priv->base.path10_len = tmp_buf_len - 1;
291 if (priv->base.path10_ptr[priv->base.path10_len - 1] == '\\') {
292 priv->base.path10_len -= 1;
293 }
294 } else {
295 free((void*)priv->base.path10_ptr);
296 priv->base.path10_ptr = nullptr;
297 }
298 }
299 {
300 DWORD tmp_buf_len = MAX_PATH;
301 priv->base.path81_ptr = (const char *)calloc(tmp_buf_len, 1);
302 if (priv->base.path81_ptr == nullptr) {
303 zig_free_windows_sdk(&priv->base);
304 return ZigFindWindowsSdkErrorOutOfMemory;
305 }
306 rc = RegQueryValueEx(key, "KitsRoot81", NULL, NULL, (LPBYTE)priv->base.path81_ptr, &tmp_buf_len);
307 if (rc == ERROR_SUCCESS) {
308 priv->base.path81_len = tmp_buf_len - 1;
309 if (priv->base.path81_ptr[priv->base.path81_len - 1] == '\\') {
310 priv->base.path81_len -= 1;
311 }
312 } else {
313 free((void*)priv->base.path81_ptr);
314 priv->base.path81_ptr = nullptr;
315 }
316 }
317
318 {
319 ZigFindWindowsSdkError err = find_10_version(priv);
320 if (err == ZigFindWindowsSdkErrorOutOfMemory) {
321 zig_free_windows_sdk(&priv->base);
322 return err;
323 }
324 }
325 {
326 ZigFindWindowsSdkError err = find_81_version(priv);
327 if (err == ZigFindWindowsSdkErrorOutOfMemory) {
328 zig_free_windows_sdk(&priv->base);
329 return err;
330 }
331 }
332
333 {
334 ZigFindWindowsSdkError err = find_msvc_lib_dir(priv);
335 if (err == ZigFindWindowsSdkErrorOutOfMemory) {
336 zig_free_windows_sdk(&priv->base);
337 return err;
338 }
339 }
340
341 *out_sdk = &priv->base;
342 return ZigFindWindowsSdkErrorNone;
343}
344
345#else
346
347void zig_free_windows_sdk(struct ZigWindowsSDK *sdk) {}
348ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk) {
349 return ZigFindWindowsSdkErrorNotFound;
350}
351
352#endif
src/windows_sdk.h created+47
...@@ -0,0 +1,47 @@
1/*
2 * Copyright (c) 2018 Andrew Kelley
3 *
4 * This file is part of zig, which is MIT licensed.
5 * See http://opensource.org/licenses/MIT
6 */
7
8#ifndef ZIG_WINDOWS_SDK_H
9#define ZIG_WINDOWS_SDK_H
10
11#ifdef __cplusplus
12#define ZIG_EXTERN_C extern "C"
13#else
14#define ZIG_EXTERN_C
15#endif
16
17#include <stddef.h>
18
19struct ZigWindowsSDK {
20 const char *path10_ptr;
21 size_t path10_len;
22
23 const char *version10_ptr;
24 size_t version10_len;
25
26 const char *path81_ptr;
27 size_t path81_len;
28
29 const char *version81_ptr;
30 size_t version81_len;
31
32 const char *msvc_lib_dir_ptr;
33 size_t msvc_lib_dir_len;
34};
35
36enum ZigFindWindowsSdkError {
37 ZigFindWindowsSdkErrorNone,
38 ZigFindWindowsSdkErrorOutOfMemory,
39 ZigFindWindowsSdkErrorNotFound,
40 ZigFindWindowsSdkErrorPathTooLong,
41};
42
43ZIG_EXTERN_C enum ZigFindWindowsSdkError zig_find_windows_sdk(struct ZigWindowsSDK **out_sdk);
44
45ZIG_EXTERN_C void zig_free_windows_sdk(struct ZigWindowsSDK *sdk);
46
47#endif
std/event/group.zig+14-2
...@@ -6,7 +6,7 @@ const AtomicRmwOp = builtin.AtomicRmwOp;...@@ -6,7 +6,7 @@ const AtomicRmwOp = builtin.AtomicRmwOp;
6const AtomicOrder = builtin.AtomicOrder;6const AtomicOrder = builtin.AtomicOrder;
7const assert = std.debug.assert;7const assert = std.debug.assert;
88
9/// ReturnType should be `void` or `E!void`9/// ReturnType must be `void` or `E!void`
10pub fn Group(comptime ReturnType: type) type {10pub fn Group(comptime ReturnType: type) type {
11 return struct {11 return struct {
12 coro_stack: Stack,12 coro_stack: Stack,
...@@ -38,8 +38,17 @@ pub fn Group(comptime ReturnType: type) type {...@@ -38,8 +38,17 @@ pub fn Group(comptime ReturnType: type) type {
38 self.alloc_stack.push(node);38 self.alloc_stack.push(node);
39 }39 }
4040
41 /// Add a node to the group. Thread-safe. Cannot fail.
42 /// `node.data` should be the promise handle to add to the group.
43 /// The node's memory should be in the coroutine frame of
44 /// the handle that is in the node, or somewhere guaranteed to live
45 /// at least as long.
46 pub fn addNode(self: *Self, node: *Stack.Node) void {
47 self.coro_stack.push(node);
48 }
49
41 /// This is equivalent to an async call, but the async function is added to the group, instead50 /// This is equivalent to an async call, but the async function is added to the group, instead
42 /// of returning a promise. func must be async and have return type void.51 /// of returning a promise. func must be async and have return type ReturnType.
43 /// Thread-safe.52 /// Thread-safe.
44 pub fn call(self: *Self, comptime func: var, args: ...) (error{OutOfMemory}!void) {53 pub fn call(self: *Self, comptime func: var, args: ...) (error{OutOfMemory}!void) {
45 const S = struct {54 const S = struct {
...@@ -67,6 +76,7 @@ pub fn Group(comptime ReturnType: type) type {...@@ -67,6 +76,7 @@ pub fn Group(comptime ReturnType: type) type {
6776
68 /// Wait for all the calls and promises of the group to complete.77 /// Wait for all the calls and promises of the group to complete.
69 /// Thread-safe.78 /// Thread-safe.
79 /// Safe to call any number of times.
70 pub async fn wait(self: *Self) ReturnType {80 pub async fn wait(self: *Self) ReturnType {
71 // TODO catch unreachable because the allocation can be grouped with81 // TODO catch unreachable because the allocation can be grouped with
72 // the coro frame allocation82 // the coro frame allocation
...@@ -98,6 +108,8 @@ pub fn Group(comptime ReturnType: type) type {...@@ -98,6 +108,8 @@ pub fn Group(comptime ReturnType: type) type {
98 }108 }
99109
100 /// Cancel all the outstanding promises. May only be called if wait was never called.110 /// Cancel all the outstanding promises. May only be called if wait was never called.
111 /// TODO These should be `cancelasync` not `cancel`.
112 /// See https://github.com/ziglang/zig/issues/1261
101 pub fn cancelAll(self: *Self) void {113 pub fn cancelAll(self: *Self) void {
102 while (self.coro_stack.pop()) |node| {114 while (self.coro_stack.pop()) |node| {
103 cancel node.data;115 cancel node.data;
std/event/loop.zig+1-1
...@@ -444,7 +444,7 @@ pub const Loop = struct {...@@ -444,7 +444,7 @@ pub const Loop = struct {
444 .next = undefined,444 .next = undefined,
445 .data = p,445 .data = p,
446 };446 };
447 loop.onNextTick(&my_tick_node);447 self.onNextTick(&my_tick_node);
448 }448 }
449 }449 }
450450
std/fmt/index.zig+6-2
...@@ -785,11 +785,15 @@ pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {...@@ -785,11 +785,15 @@ pub fn bufPrint(buf: []u8, comptime fmt: []const u8, args: ...) ![]u8 {
785 return buf[0 .. buf.len - context.remaining.len];785 return buf[0 .. buf.len - context.remaining.len];
786}786}
787787
788pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: ...) ![]u8 {788pub const AllocPrintError = error{OutOfMemory};
789
790pub fn allocPrint(allocator: *mem.Allocator, comptime fmt: []const u8, args: ...) AllocPrintError![]u8 {
789 var size: usize = 0;791 var size: usize = 0;
790 format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};792 format(&size, error{}, countSize, fmt, args) catch |err| switch (err) {};
791 const buf = try allocator.alloc(u8, size);793 const buf = try allocator.alloc(u8, size);
792 return bufPrint(buf, fmt, args);794 return bufPrint(buf, fmt, args) catch |err| switch (err) {
795 error.BufferTooSmall => unreachable, // we just counted the size above
796 };
793}797}
794798
795fn countSize(size: *usize, bytes: []const u8) (error{}!void) {799fn countSize(size: *usize, bytes: []const u8) (error{}!void) {
std/macho.zig+1-1
...@@ -141,7 +141,7 @@ pub fn loadSymbols(allocator: *mem.Allocator, in: *io.FileInStream) !SymbolTable...@@ -141,7 +141,7 @@ pub fn loadSymbols(allocator: *mem.Allocator, in: *io.FileInStream) !SymbolTable
141 }141 }
142142
143 // Effectively a no-op, lld emits symbols in ascending order.143 // Effectively a no-op, lld emits symbols in ascending order.
144 std.sort.insertionSort(Symbol, symbols[0..nsyms], Symbol.addressLessThan);144 std.sort.sort(Symbol, symbols[0..nsyms], Symbol.addressLessThan);
145145
146 // Insert the sentinel. Since we don't know where the last function ends,146 // Insert the sentinel. Since we don't know where the last function ends,
147 // we arbitrarily limit it to the start address + 4 KB.147 // we arbitrarily limit it to the start address + 4 KB.
std/math/big/int.zig+18-1
...@@ -60,8 +60,9 @@ pub const Int = struct {...@@ -60,8 +60,9 @@ pub const Int = struct {
60 self.limbs = try self.allocator.realloc(Limb, self.limbs, capacity);60 self.limbs = try self.allocator.realloc(Limb, self.limbs, capacity);
61 }61 }
6262
63 pub fn deinit(self: Int) void {63 pub fn deinit(self: *Int) void {
64 self.allocator.free(self.limbs);64 self.allocator.free(self.limbs);
65 self.* = undefined;
65 }66 }
6667
67 pub fn clone(other: Int) !Int {68 pub fn clone(other: Int) !Int {
...@@ -332,6 +333,7 @@ pub const Int = struct {...@@ -332,6 +333,7 @@ pub const Int = struct {
332 self.positive = positive;333 self.positive = positive;
333 }334 }
334335
336 /// TODO make this call format instead of the other way around
335 pub fn toString(self: Int, allocator: *Allocator, base: u8) ![]const u8 {337 pub fn toString(self: Int, allocator: *Allocator, base: u8) ![]const u8 {
336 if (base < 2 or base > 16) {338 if (base < 2 or base > 16) {
337 return error.InvalidBase;339 return error.InvalidBase;
...@@ -414,6 +416,21 @@ pub const Int = struct {...@@ -414,6 +416,21 @@ pub const Int = struct {
414 return s;416 return s;
415 }417 }
416418
419 /// for the std lib format function
420 /// TODO make this non-allocating
421 pub fn format(
422 self: Int,
423 comptime fmt: []const u8,
424 context: var,
425 comptime FmtError: type,
426 output: fn (@typeOf(context), []const u8) FmtError!void,
427 ) FmtError!void {
428 // TODO look at fmt and support other bases
429 const str = self.toString(self.allocator, 10) catch @panic("TODO make this non allocating");
430 defer self.allocator.free(str);
431 return output(context, str);
432 }
433
417 // returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.434 // returns -1, 0, 1 if |a| < |b|, |a| == |b| or |a| > |b| respectively.
418 pub fn cmpAbs(a: Int, b: Int) i8 {435 pub fn cmpAbs(a: Int, b: Int) i8 {
419 if (a.len < b.len) {436 if (a.len < b.len) {
std/mem.zig+10-2
...@@ -35,6 +35,7 @@ pub const Allocator = struct {...@@ -35,6 +35,7 @@ pub const Allocator = struct {
35 freeFn: fn (self: *Allocator, old_mem: []u8) void,35 freeFn: fn (self: *Allocator, old_mem: []u8) void,
3636
37 /// Call `destroy` with the result37 /// Call `destroy` with the result
38 /// TODO this is deprecated. use createOne instead
38 pub fn create(self: *Allocator, init: var) Error!*@typeOf(init) {39 pub fn create(self: *Allocator, init: var) Error!*@typeOf(init) {
39 const T = @typeOf(init);40 const T = @typeOf(init);
40 if (@sizeOf(T) == 0) return &(T{});41 if (@sizeOf(T) == 0) return &(T{});
...@@ -44,6 +45,14 @@ pub const Allocator = struct {...@@ -44,6 +45,14 @@ pub const Allocator = struct {
44 return ptr;45 return ptr;
45 }46 }
4647
48 /// Call `destroy` with the result.
49 /// Returns undefined memory.
50 pub fn createOne(self: *Allocator, comptime T: type) Error!*T {
51 if (@sizeOf(T) == 0) return &(T{});
52 const slice = try self.alloc(T, 1);
53 return &slice[0];
54 }
55
47 /// `ptr` should be the return value of `create`56 /// `ptr` should be the return value of `create`
48 pub fn destroy(self: *Allocator, ptr: var) void {57 pub fn destroy(self: *Allocator, ptr: var) void {
49 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));58 const non_const_ptr = @intToPtr([*]u8, @ptrToInt(ptr));
...@@ -149,13 +158,12 @@ pub fn copyBackwards(comptime T: type, dest: []T, source: []const T) void {...@@ -149,13 +158,12 @@ pub fn copyBackwards(comptime T: type, dest: []T, source: []const T) void {
149 @setRuntimeSafety(false);158 @setRuntimeSafety(false);
150 assert(dest.len >= source.len);159 assert(dest.len >= source.len);
151 var i = source.len;160 var i = source.len;
152 while(i > 0){161 while (i > 0) {
153 i -= 1;162 i -= 1;
154 dest[i] = source[i];163 dest[i] = source[i];
155 }164 }
156}165}
157166
158
159pub fn set(comptime T: type, dest: []T, value: T) void {167pub fn set(comptime T: type, dest: []T, value: T) void {
160 for (dest) |*d|168 for (dest) |*d|
161 d.* = value;169 d.* = value;
std/os/file.zig+23-24
...@@ -109,43 +109,42 @@ pub const File = struct {...@@ -109,43 +109,42 @@ pub const File = struct {
109 Unexpected,109 Unexpected,
110 };110 };
111111
112 pub fn access(allocator: *mem.Allocator, path: []const u8, file_mode: os.FileMode) AccessError!bool {112 pub fn access(allocator: *mem.Allocator, path: []const u8) AccessError!void {
113 const path_with_null = try std.cstr.addNullByte(allocator, path);113 const path_with_null = try std.cstr.addNullByte(allocator, path);
114 defer allocator.free(path_with_null);114 defer allocator.free(path_with_null);
115115
116 if (is_posix) {116 if (is_posix) {
117 // mode is ignored and is always F_OK for now
118 const result = posix.access(path_with_null.ptr, posix.F_OK);117 const result = posix.access(path_with_null.ptr, posix.F_OK);
119 const err = posix.getErrno(result);118 const err = posix.getErrno(result);
120 if (err > 0) {119 switch (err) {
121 return switch (err) {120 0 => return,
122 posix.EACCES => error.PermissionDenied,121 posix.EACCES => return error.PermissionDenied,
123 posix.EROFS => error.PermissionDenied,122 posix.EROFS => return error.PermissionDenied,
124 posix.ELOOP => error.PermissionDenied,123 posix.ELOOP => return error.PermissionDenied,
125 posix.ETXTBSY => error.PermissionDenied,124 posix.ETXTBSY => return error.PermissionDenied,
126 posix.ENOTDIR => error.NotFound,125 posix.ENOTDIR => return error.NotFound,
127 posix.ENOENT => error.NotFound,126 posix.ENOENT => return error.NotFound,
128127
129 posix.ENAMETOOLONG => error.NameTooLong,128 posix.ENAMETOOLONG => return error.NameTooLong,
130 posix.EINVAL => error.BadMode,129 posix.EINVAL => unreachable,
131 posix.EFAULT => error.BadPathName,130 posix.EFAULT => return error.BadPathName,
132 posix.EIO => error.Io,131 posix.EIO => return error.Io,
133 posix.ENOMEM => error.SystemResources,132 posix.ENOMEM => return error.SystemResources,
134 else => os.unexpectedErrorPosix(err),133 else => return os.unexpectedErrorPosix(err),
135 };
136 }134 }
137 return true;
138 } else if (is_windows) {135 } else if (is_windows) {
139 if (os.windows.GetFileAttributesA(path_with_null.ptr) != os.windows.INVALID_FILE_ATTRIBUTES) {136 if (os.windows.GetFileAttributesA(path_with_null.ptr) != os.windows.INVALID_FILE_ATTRIBUTES) {
140 return true;137 return;
141 }138 }
142139
143 const err = windows.GetLastError();140 const err = windows.GetLastError();
144 return switch (err) {141 switch (err) {
145 windows.ERROR.FILE_NOT_FOUND => error.NotFound,142 windows.ERROR.FILE_NOT_FOUND,
146 windows.ERROR.ACCESS_DENIED => error.PermissionDenied,143 windows.ERROR.PATH_NOT_FOUND,
147 else => os.unexpectedErrorWindows(err),144 => return error.NotFound,
148 };145 windows.ERROR.ACCESS_DENIED => return error.PermissionDenied,
146 else => return os.unexpectedErrorWindows(err),
147 }
149 } else {148 } else {
150 @compileError("TODO implement access for this OS");149 @compileError("TODO implement access for this OS");
151 }150 }
std/os/test.zig+3-3
...@@ -23,14 +23,14 @@ test "makePath, put some files in it, deleteTree" {...@@ -23,14 +23,14 @@ test "makePath, put some files in it, deleteTree" {
2323
24test "access file" {24test "access file" {
25 try os.makePath(a, "os_test_tmp");25 try os.makePath(a, "os_test_tmp");
26 if (os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) |ok| {26 if (os.File.access(a, "os_test_tmp/file.txt")) |ok| {
27 unreachable;27 @panic("expected error");
28 } else |err| {28 } else |err| {
29 assert(err == error.NotFound);29 assert(err == error.NotFound);
30 }30 }
3131
32 try io.writeFile(a, "os_test_tmp/file.txt", "");32 try io.writeFile(a, "os_test_tmp/file.txt", "");
33 assert((try os.File.access(a, "os_test_tmp/file.txt", os.default_file_mode)) == true);33 try os.File.access(a, "os_test_tmp/file.txt");
34 try os.deleteTree(a, "os_test_tmp");34 try os.deleteTree(a, "os_test_tmp");
35}35}
3636
std/os/windows/advapi32.zig created+30
...@@ -0,0 +1,30 @@
1use @import("index.zig");
2
3pub const PROV_RSA_FULL = 1;
4
5pub const REGSAM = ACCESS_MASK;
6pub const ACCESS_MASK = DWORD;
7pub const PHKEY = &HKEY;
8pub const HKEY = &HKEY__;
9pub const HKEY__ = extern struct {
10 unused: c_int,
11};
12pub const LSTATUS = LONG;
13
14pub extern "advapi32" stdcallcc fn CryptAcquireContextA(
15 phProv: *HCRYPTPROV,
16 pszContainer: ?LPCSTR,
17 pszProvider: ?LPCSTR,
18 dwProvType: DWORD,
19 dwFlags: DWORD,
20) BOOL;
21
22pub extern "advapi32" stdcallcc fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) BOOL;
23
24pub extern "advapi32" stdcallcc fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: [*]BYTE) BOOL;
25
26pub extern "advapi32" stdcallcc fn RegOpenKeyExW(hKey: HKEY, lpSubKey: LPCWSTR, ulOptions: DWORD, samDesired: REGSAM,
27 phkResult: &HKEY,) LSTATUS;
28
29pub extern "advapi32" stdcallcc fn RegQueryValueExW(hKey: HKEY, lpValueName: LPCWSTR, lpReserved: LPDWORD,
30 lpType: LPDWORD, lpData: LPBYTE, lpcbData: LPDWORD,) LSTATUS;
std/os/windows/index.zig+9-183
...@@ -1,190 +1,19 @@...@@ -1,190 +1,19 @@
1const std = @import("../../index.zig");1const std = @import("../../index.zig");
2const assert = std.debug.assert;2const assert = std.debug.assert;
3
4pub use @import("advapi32.zig");
5pub use @import("kernel32.zig");
6pub use @import("ole32.zig");
7pub use @import("shell32.zig");
8pub use @import("shlwapi.zig");
9pub use @import("user32.zig");
10
3test "import" {11test "import" {
4 _ = @import("util.zig");12 _ = @import("util.zig");
5}13}
614
7pub const ERROR = @import("error.zig");15pub const ERROR = @import("error.zig");
816
9pub extern "advapi32" stdcallcc fn CryptAcquireContextA(
10 phProv: *HCRYPTPROV,
11 pszContainer: ?LPCSTR,
12 pszProvider: ?LPCSTR,
13 dwProvType: DWORD,
14 dwFlags: DWORD,
15) BOOL;
16
17pub extern "advapi32" stdcallcc fn CryptReleaseContext(hProv: HCRYPTPROV, dwFlags: DWORD) BOOL;
18
19pub extern "advapi32" stdcallcc fn CryptGenRandom(hProv: HCRYPTPROV, dwLen: DWORD, pbBuffer: [*]BYTE) BOOL;
20
21pub extern "kernel32" stdcallcc fn CloseHandle(hObject: HANDLE) BOOL;
22
23pub extern "kernel32" stdcallcc fn CreateDirectoryA(
24 lpPathName: LPCSTR,
25 lpSecurityAttributes: ?*SECURITY_ATTRIBUTES,
26) BOOL;
27
28pub extern "kernel32" stdcallcc fn CreateFileA(
29 lpFileName: LPCSTR,
30 dwDesiredAccess: DWORD,
31 dwShareMode: DWORD,
32 lpSecurityAttributes: ?LPSECURITY_ATTRIBUTES,
33 dwCreationDisposition: DWORD,
34 dwFlagsAndAttributes: DWORD,
35 hTemplateFile: ?HANDLE,
36) HANDLE;
37
38pub extern "kernel32" stdcallcc fn CreatePipe(
39 hReadPipe: *HANDLE,
40 hWritePipe: *HANDLE,
41 lpPipeAttributes: *const SECURITY_ATTRIBUTES,
42 nSize: DWORD,
43) BOOL;
44
45pub extern "kernel32" stdcallcc fn CreateProcessA(
46 lpApplicationName: ?LPCSTR,
47 lpCommandLine: LPSTR,
48 lpProcessAttributes: ?*SECURITY_ATTRIBUTES,
49 lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
50 bInheritHandles: BOOL,
51 dwCreationFlags: DWORD,
52 lpEnvironment: ?*c_void,
53 lpCurrentDirectory: ?LPCSTR,
54 lpStartupInfo: *STARTUPINFOA,
55 lpProcessInformation: *PROCESS_INFORMATION,
56) BOOL;
57
58pub extern "kernel32" stdcallcc fn CreateSymbolicLinkA(
59 lpSymlinkFileName: LPCSTR,
60 lpTargetFileName: LPCSTR,
61 dwFlags: DWORD,
62) BOOLEAN;
63
64pub extern "kernel32" stdcallcc fn CreateIoCompletionPort(FileHandle: HANDLE, ExistingCompletionPort: ?HANDLE, CompletionKey: ULONG_PTR, NumberOfConcurrentThreads: DWORD) ?HANDLE;
65
66pub extern "kernel32" stdcallcc fn CreateThread(lpThreadAttributes: ?LPSECURITY_ATTRIBUTES, dwStackSize: SIZE_T, lpStartAddress: LPTHREAD_START_ROUTINE, lpParameter: ?LPVOID, dwCreationFlags: DWORD, lpThreadId: ?LPDWORD) ?HANDLE;
67
68pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) BOOL;
69
70pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn;
71
72pub extern "kernel32" stdcallcc fn FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: *WIN32_FIND_DATAA) HANDLE;
73pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL;
74pub extern "kernel32" stdcallcc fn FindNextFileA(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAA) BOOL;
75
76pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL;
77
78pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
79
80pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL;
81
82pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) DWORD;
83
84pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8;
85
86pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;
87
88pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: *DWORD) BOOL;
89
90pub extern "kernel32" stdcallcc fn GetFileSizeEx(hFile: HANDLE, lpFileSize: *LARGE_INTEGER) BOOL;
91
92pub extern "kernel32" stdcallcc fn GetFileAttributesA(lpFileName: LPCSTR) DWORD;
93
94pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: LPSTR, nSize: DWORD) DWORD;
95
96pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
97
98pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(
99 in_hFile: HANDLE,
100 in_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
101 out_lpFileInformation: *c_void,
102 in_dwBufferSize: DWORD,
103) BOOL;
104
105pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(
106 hFile: HANDLE,
107 lpszFilePath: LPSTR,
108 cchFilePath: DWORD,
109 dwFlags: DWORD,
110) DWORD;
111
112pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;
113pub extern "kernel32" stdcallcc fn GetQueuedCompletionStatus(CompletionPort: HANDLE, lpNumberOfBytesTransferred: LPDWORD, lpCompletionKey: *ULONG_PTR, lpOverlapped: *?*OVERLAPPED, dwMilliseconds: DWORD) BOOL;
114
115pub extern "kernel32" stdcallcc fn GetSystemInfo(lpSystemInfo: *SYSTEM_INFO) void;
116pub extern "kernel32" stdcallcc fn GetSystemTimeAsFileTime(*FILETIME) void;
117
118pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE;
119pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL;
120pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void, dwBytes: SIZE_T) ?*c_void;
121pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) SIZE_T;
122pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) BOOL;
123pub extern "kernel32" stdcallcc fn HeapCompact(hHeap: HANDLE, dwFlags: DWORD) SIZE_T;
124pub extern "kernel32" stdcallcc fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) BOOL;
125
126pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) ?HANDLE;
127
128pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?*c_void;
129
130pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void) BOOL;
131
132pub extern "kernel32" stdcallcc fn MoveFileExA(
133 lpExistingFileName: LPCSTR,
134 lpNewFileName: LPCSTR,
135 dwFlags: DWORD,
136) BOOL;
137
138pub extern "kernel32" stdcallcc fn PostQueuedCompletionStatus(CompletionPort: HANDLE, dwNumberOfBytesTransferred: DWORD, dwCompletionKey: ULONG_PTR, lpOverlapped: ?*OVERLAPPED) BOOL;
139
140pub extern "kernel32" stdcallcc fn QueryPerformanceCounter(lpPerformanceCount: *LARGE_INTEGER) BOOL;
141
142pub extern "kernel32" stdcallcc fn QueryPerformanceFrequency(lpFrequency: *LARGE_INTEGER) BOOL;
143
144pub extern "kernel32" stdcallcc fn ReadFile(
145 in_hFile: HANDLE,
146 out_lpBuffer: *c_void,
147 in_nNumberOfBytesToRead: DWORD,
148 out_lpNumberOfBytesRead: *DWORD,
149 in_out_lpOverlapped: ?*OVERLAPPED,
150) BOOL;
151
152pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;
153
154pub extern "kernel32" stdcallcc fn SetFilePointerEx(
155 in_fFile: HANDLE,
156 in_liDistanceToMove: LARGE_INTEGER,
157 out_opt_ldNewFilePointer: ?*LARGE_INTEGER,
158 in_dwMoveMethod: DWORD,
159) BOOL;
160
161pub extern "kernel32" stdcallcc fn SetHandleInformation(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD) BOOL;
162
163pub extern "kernel32" stdcallcc fn Sleep(dwMilliseconds: DWORD) void;
164
165pub extern "kernel32" stdcallcc fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) BOOL;
166
167pub extern "kernel32" stdcallcc fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) DWORD;
168
169pub extern "kernel32" stdcallcc fn WriteFile(
170 in_hFile: HANDLE,
171 in_lpBuffer: *const c_void,
172 in_nNumberOfBytesToWrite: DWORD,
173 out_lpNumberOfBytesWritten: ?*DWORD,
174 in_out_lpOverlapped: ?*OVERLAPPED,
175) BOOL;
176
177//TODO: call unicode versions instead of relying on ANSI code page
178pub extern "kernel32" stdcallcc fn LoadLibraryA(lpLibFileName: LPCSTR) ?HMODULE;
179
180pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL;
181
182pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) c_int;
183
184pub extern "shlwapi" stdcallcc fn PathFileExistsA(pszPath: ?LPCTSTR) BOOL;
185
186pub const PROV_RSA_FULL = 1;
187
188pub const BOOL = c_int;17pub const BOOL = c_int;
189pub const BOOLEAN = BYTE;18pub const BOOLEAN = BYTE;
190pub const BYTE = u8;19pub const BYTE = u8;
...@@ -206,6 +35,7 @@ pub const LPSTR = [*]CHAR;...@@ -206,6 +35,7 @@ pub const LPSTR = [*]CHAR;
206pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR;35pub const LPTSTR = if (UNICODE) LPWSTR else LPSTR;
207pub const LPVOID = *c_void;36pub const LPVOID = *c_void;
208pub const LPWSTR = [*]WCHAR;37pub const LPWSTR = [*]WCHAR;
38pub const LPCWSTR = [*]const WCHAR;
209pub const PVOID = *c_void;39pub const PVOID = *c_void;
210pub const PWSTR = [*]WCHAR;40pub const PWSTR = [*]WCHAR;
211pub const SIZE_T = usize;41pub const SIZE_T = usize;
...@@ -442,10 +272,6 @@ pub const SYSTEM_INFO = extern struct {...@@ -442,10 +272,6 @@ pub const SYSTEM_INFO = extern struct {
442 wProcessorRevision: WORD,272 wProcessorRevision: WORD,
443};273};
444274
445pub extern "ole32.dll" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;
446
447pub extern "shell32.dll" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT;
448
449pub const HRESULT = c_long;275pub const HRESULT = c_long;
450276
451pub const KNOWNFOLDERID = GUID;277pub const KNOWNFOLDERID = GUID;
std/os/windows/kernel32.zig created+162
...@@ -0,0 +1,162 @@
1use @import("index.zig");
2
3pub extern "kernel32" stdcallcc fn CloseHandle(hObject: HANDLE) BOOL;
4
5pub extern "kernel32" stdcallcc fn CreateDirectoryA(
6 lpPathName: LPCSTR,
7 lpSecurityAttributes: ?*SECURITY_ATTRIBUTES,
8) BOOL;
9
10pub extern "kernel32" stdcallcc fn CreateFileA(
11 lpFileName: LPCSTR,
12 dwDesiredAccess: DWORD,
13 dwShareMode: DWORD,
14 lpSecurityAttributes: ?LPSECURITY_ATTRIBUTES,
15 dwCreationDisposition: DWORD,
16 dwFlagsAndAttributes: DWORD,
17 hTemplateFile: ?HANDLE,
18) HANDLE;
19
20pub extern "kernel32" stdcallcc fn CreatePipe(
21 hReadPipe: *HANDLE,
22 hWritePipe: *HANDLE,
23 lpPipeAttributes: *const SECURITY_ATTRIBUTES,
24 nSize: DWORD,
25) BOOL;
26
27pub extern "kernel32" stdcallcc fn CreateProcessA(
28 lpApplicationName: ?LPCSTR,
29 lpCommandLine: LPSTR,
30 lpProcessAttributes: ?*SECURITY_ATTRIBUTES,
31 lpThreadAttributes: ?*SECURITY_ATTRIBUTES,
32 bInheritHandles: BOOL,
33 dwCreationFlags: DWORD,
34 lpEnvironment: ?*c_void,
35 lpCurrentDirectory: ?LPCSTR,
36 lpStartupInfo: *STARTUPINFOA,
37 lpProcessInformation: *PROCESS_INFORMATION,
38) BOOL;
39
40pub extern "kernel32" stdcallcc fn CreateSymbolicLinkA(
41 lpSymlinkFileName: LPCSTR,
42 lpTargetFileName: LPCSTR,
43 dwFlags: DWORD,
44) BOOLEAN;
45
46pub extern "kernel32" stdcallcc fn CreateIoCompletionPort(FileHandle: HANDLE, ExistingCompletionPort: ?HANDLE, CompletionKey: ULONG_PTR, NumberOfConcurrentThreads: DWORD) ?HANDLE;
47
48pub extern "kernel32" stdcallcc fn CreateThread(lpThreadAttributes: ?LPSECURITY_ATTRIBUTES, dwStackSize: SIZE_T, lpStartAddress: LPTHREAD_START_ROUTINE, lpParameter: ?LPVOID, dwCreationFlags: DWORD, lpThreadId: ?LPDWORD) ?HANDLE;
49
50pub extern "kernel32" stdcallcc fn DeleteFileA(lpFileName: LPCSTR) BOOL;
51
52pub extern "kernel32" stdcallcc fn ExitProcess(exit_code: UINT) noreturn;
53
54pub extern "kernel32" stdcallcc fn FindFirstFileA(lpFileName: LPCSTR, lpFindFileData: *WIN32_FIND_DATAA) HANDLE;
55pub extern "kernel32" stdcallcc fn FindClose(hFindFile: HANDLE) BOOL;
56pub extern "kernel32" stdcallcc fn FindNextFileA(hFindFile: HANDLE, lpFindFileData: *WIN32_FIND_DATAA) BOOL;
57
58pub extern "kernel32" stdcallcc fn FreeEnvironmentStringsA(penv: [*]u8) BOOL;
59
60pub extern "kernel32" stdcallcc fn GetCommandLineA() LPSTR;
61
62pub extern "kernel32" stdcallcc fn GetConsoleMode(in_hConsoleHandle: HANDLE, out_lpMode: *DWORD) BOOL;
63
64pub extern "kernel32" stdcallcc fn GetCurrentDirectoryA(nBufferLength: WORD, lpBuffer: ?LPSTR) DWORD;
65
66pub extern "kernel32" stdcallcc fn GetEnvironmentStringsA() ?[*]u8;
67
68pub extern "kernel32" stdcallcc fn GetEnvironmentVariableA(lpName: LPCSTR, lpBuffer: LPSTR, nSize: DWORD) DWORD;
69
70pub extern "kernel32" stdcallcc fn GetExitCodeProcess(hProcess: HANDLE, lpExitCode: *DWORD) BOOL;
71
72pub extern "kernel32" stdcallcc fn GetFileSizeEx(hFile: HANDLE, lpFileSize: *LARGE_INTEGER) BOOL;
73
74pub extern "kernel32" stdcallcc fn GetFileAttributesA(lpFileName: LPCSTR) DWORD;
75
76pub extern "kernel32" stdcallcc fn GetModuleFileNameA(hModule: ?HMODULE, lpFilename: LPSTR, nSize: DWORD) DWORD;
77
78pub extern "kernel32" stdcallcc fn GetLastError() DWORD;
79
80pub extern "kernel32" stdcallcc fn GetFileInformationByHandleEx(
81 in_hFile: HANDLE,
82 in_FileInformationClass: FILE_INFO_BY_HANDLE_CLASS,
83 out_lpFileInformation: *c_void,
84 in_dwBufferSize: DWORD,
85) BOOL;
86
87pub extern "kernel32" stdcallcc fn GetFinalPathNameByHandleA(
88 hFile: HANDLE,
89 lpszFilePath: LPSTR,
90 cchFilePath: DWORD,
91 dwFlags: DWORD,
92) DWORD;
93
94pub extern "kernel32" stdcallcc fn GetProcessHeap() ?HANDLE;
95pub extern "kernel32" stdcallcc fn GetQueuedCompletionStatus(CompletionPort: HANDLE, lpNumberOfBytesTransferred: LPDWORD, lpCompletionKey: *ULONG_PTR, lpOverlapped: *?*OVERLAPPED, dwMilliseconds: DWORD) BOOL;
96
97pub extern "kernel32" stdcallcc fn GetSystemInfo(lpSystemInfo: *SYSTEM_INFO) void;
98pub extern "kernel32" stdcallcc fn GetSystemTimeAsFileTime(*FILETIME) void;
99
100pub extern "kernel32" stdcallcc fn HeapCreate(flOptions: DWORD, dwInitialSize: SIZE_T, dwMaximumSize: SIZE_T) ?HANDLE;
101pub extern "kernel32" stdcallcc fn HeapDestroy(hHeap: HANDLE) BOOL;
102pub extern "kernel32" stdcallcc fn HeapReAlloc(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void, dwBytes: SIZE_T) ?*c_void;
103pub extern "kernel32" stdcallcc fn HeapSize(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) SIZE_T;
104pub extern "kernel32" stdcallcc fn HeapValidate(hHeap: HANDLE, dwFlags: DWORD, lpMem: *const c_void) BOOL;
105pub extern "kernel32" stdcallcc fn HeapCompact(hHeap: HANDLE, dwFlags: DWORD) SIZE_T;
106pub extern "kernel32" stdcallcc fn HeapSummary(hHeap: HANDLE, dwFlags: DWORD, lpSummary: LPHEAP_SUMMARY) BOOL;
107
108pub extern "kernel32" stdcallcc fn GetStdHandle(in_nStdHandle: DWORD) ?HANDLE;
109
110pub extern "kernel32" stdcallcc fn HeapAlloc(hHeap: HANDLE, dwFlags: DWORD, dwBytes: SIZE_T) ?*c_void;
111
112pub extern "kernel32" stdcallcc fn HeapFree(hHeap: HANDLE, dwFlags: DWORD, lpMem: *c_void) BOOL;
113
114pub extern "kernel32" stdcallcc fn MoveFileExA(
115 lpExistingFileName: LPCSTR,
116 lpNewFileName: LPCSTR,
117 dwFlags: DWORD,
118) BOOL;
119
120pub extern "kernel32" stdcallcc fn PostQueuedCompletionStatus(CompletionPort: HANDLE, dwNumberOfBytesTransferred: DWORD, dwCompletionKey: ULONG_PTR, lpOverlapped: ?*OVERLAPPED) BOOL;
121
122pub extern "kernel32" stdcallcc fn QueryPerformanceCounter(lpPerformanceCount: *LARGE_INTEGER) BOOL;
123
124pub extern "kernel32" stdcallcc fn QueryPerformanceFrequency(lpFrequency: *LARGE_INTEGER) BOOL;
125
126pub extern "kernel32" stdcallcc fn ReadFile(
127 in_hFile: HANDLE,
128 out_lpBuffer: *c_void,
129 in_nNumberOfBytesToRead: DWORD,
130 out_lpNumberOfBytesRead: *DWORD,
131 in_out_lpOverlapped: ?*OVERLAPPED,
132) BOOL;
133
134pub extern "kernel32" stdcallcc fn RemoveDirectoryA(lpPathName: LPCSTR) BOOL;
135
136pub extern "kernel32" stdcallcc fn SetFilePointerEx(
137 in_fFile: HANDLE,
138 in_liDistanceToMove: LARGE_INTEGER,
139 out_opt_ldNewFilePointer: ?*LARGE_INTEGER,
140 in_dwMoveMethod: DWORD,
141) BOOL;
142
143pub extern "kernel32" stdcallcc fn SetHandleInformation(hObject: HANDLE, dwMask: DWORD, dwFlags: DWORD) BOOL;
144
145pub extern "kernel32" stdcallcc fn Sleep(dwMilliseconds: DWORD) void;
146
147pub extern "kernel32" stdcallcc fn TerminateProcess(hProcess: HANDLE, uExitCode: UINT) BOOL;
148
149pub extern "kernel32" stdcallcc fn WaitForSingleObject(hHandle: HANDLE, dwMilliseconds: DWORD) DWORD;
150
151pub extern "kernel32" stdcallcc fn WriteFile(
152 in_hFile: HANDLE,
153 in_lpBuffer: *const c_void,
154 in_nNumberOfBytesToWrite: DWORD,
155 out_lpNumberOfBytesWritten: ?*DWORD,
156 in_out_lpOverlapped: ?*OVERLAPPED,
157) BOOL;
158
159//TODO: call unicode versions instead of relying on ANSI code page
160pub extern "kernel32" stdcallcc fn LoadLibraryA(lpLibFileName: LPCSTR) ?HMODULE;
161
162pub extern "kernel32" stdcallcc fn FreeLibrary(hModule: HMODULE) BOOL;
std/os/windows/ole32.zig created+18
...@@ -0,0 +1,18 @@
1use @import("index.zig");
2
3pub extern "ole32.dll" stdcallcc fn CoTaskMemFree(pv: LPVOID) void;
4pub extern "ole32.dll" stdcallcc fn CoUninitialize() void;
5pub extern "ole32.dll" stdcallcc fn CoGetCurrentProcess() DWORD;
6pub extern "ole32.dll" stdcallcc fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) HRESULT;
7
8
9pub const COINIT_APARTMENTTHREADED = COINIT.COINIT_APARTMENTTHREADED;
10pub const COINIT_MULTITHREADED = COINIT.COINIT_MULTITHREADED;
11pub const COINIT_DISABLE_OLE1DDE = COINIT.COINIT_DISABLE_OLE1DDE;
12pub const COINIT_SPEED_OVER_MEMORY = COINIT.COINIT_SPEED_OVER_MEMORY;
13pub const COINIT = extern enum {
14 COINIT_APARTMENTTHREADED = 2,
15 COINIT_MULTITHREADED = 0,
16 COINIT_DISABLE_OLE1DDE = 4,
17 COINIT_SPEED_OVER_MEMORY = 8,
18};
std/os/windows/shell32.zig created+4
...@@ -0,0 +1,4 @@
1use @import("index.zig");
2
3pub extern "shell32.dll" stdcallcc fn SHGetKnownFolderPath(rfid: *const KNOWNFOLDERID, dwFlags: DWORD, hToken: ?HANDLE, ppszPath: *[*]WCHAR) HRESULT;
4
std/os/windows/shlwapi.zig created+4
...@@ -0,0 +1,4 @@
1use @import("index.zig");
2
3pub extern "shlwapi" stdcallcc fn PathFileExistsA(pszPath: ?LPCTSTR) BOOL;
4
std/os/windows/user32.zig created+4
...@@ -0,0 +1,4 @@
1use @import("index.zig");
2
3pub extern "user32" stdcallcc fn MessageBoxA(hWnd: ?HANDLE, lpText: ?LPCTSTR, lpCaption: ?LPCTSTR, uType: UINT) c_int;
4
std/zig/index.zig+3
...@@ -2,6 +2,7 @@ const tokenizer = @import("tokenizer.zig");...@@ -2,6 +2,7 @@ const tokenizer = @import("tokenizer.zig");
2pub const Token = tokenizer.Token;2pub const Token = tokenizer.Token;
3pub const Tokenizer = tokenizer.Tokenizer;3pub const Tokenizer = tokenizer.Tokenizer;
4pub const parse = @import("parse.zig").parse;4pub const parse = @import("parse.zig").parse;
5pub const parseStringLiteral = @import("parse_string_literal.zig").parseStringLiteral;
5pub const render = @import("render.zig").render;6pub const render = @import("render.zig").render;
6pub const ast = @import("ast.zig");7pub const ast = @import("ast.zig");
78
...@@ -10,4 +11,6 @@ test "std.zig tests" {...@@ -10,4 +11,6 @@ test "std.zig tests" {
10 _ = @import("parse.zig");11 _ = @import("parse.zig");
11 _ = @import("render.zig");12 _ = @import("render.zig");
12 _ = @import("tokenizer.zig");13 _ = @import("tokenizer.zig");
14 _ = @import("parse_string_literal.zig");
13}15}
16
std/zig/parse.zig+1-1
...@@ -2356,7 +2356,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {...@@ -2356,7 +2356,7 @@ pub fn parse(allocator: *mem.Allocator, source: []const u8) !ast.Tree {
2356 const token = nextToken(&tok_it, &tree);2356 const token = nextToken(&tok_it, &tree);
2357 switch (token.ptr.id) {2357 switch (token.ptr.id) {
2358 Token.Id.IntegerLiteral => {2358 Token.Id.IntegerLiteral => {
2359 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.StringLiteral, token.index);2359 _ = try createToCtxLiteral(arena, opt_ctx, ast.Node.IntegerLiteral, token.index);
2360 continue;2360 continue;
2361 },2361 },
2362 Token.Id.FloatLiteral => {2362 Token.Id.FloatLiteral => {
std/zig/parse_string_literal.zig created+76
...@@ -0,0 +1,76 @@
1const std = @import("../index.zig");
2const assert = std.debug.assert;
3
4const State = enum {
5 Start,
6 Backslash,
7};
8
9pub const ParseStringLiteralError = error{
10 OutOfMemory,
11
12 /// When this is returned, index will be the position of the character.
13 InvalidCharacter,
14};
15
16/// caller owns returned memory
17pub fn parseStringLiteral(
18 allocator: *std.mem.Allocator,
19 bytes: []const u8,
20 bad_index: *usize, // populated if error.InvalidCharacter is returned
21) ParseStringLiteralError![]u8 {
22 const first_index = if (bytes[0] == 'c') usize(2) else usize(1);
23 assert(bytes[bytes.len - 1] == '"');
24
25 var list = std.ArrayList(u8).init(allocator);
26 errdefer list.deinit();
27
28 const slice = bytes[first_index..];
29 try list.ensureCapacity(slice.len - 1);
30
31 var state = State.Start;
32 for (slice) |b, index| {
33 switch (state) {
34 State.Start => switch (b) {
35 '\\' => state = State.Backslash,
36 '\n' => {
37 bad_index.* = index;
38 return error.InvalidCharacter;
39 },
40 '"' => return list.toOwnedSlice(),
41 else => try list.append(b),
42 },
43 State.Backslash => switch (b) {
44 'x' => @panic("TODO"),
45 'u' => @panic("TODO"),
46 'U' => @panic("TODO"),
47 'n' => {
48 try list.append('\n');
49 state = State.Start;
50 },
51 'r' => {
52 try list.append('\r');
53 state = State.Start;
54 },
55 '\\' => {
56 try list.append('\\');
57 state = State.Start;
58 },
59 't' => {
60 try list.append('\t');
61 state = State.Start;
62 },
63 '"' => {
64 try list.append('"');
65 state = State.Start;
66 },
67 else => {
68 bad_index.* = index;
69 return error.InvalidCharacter;
70 },
71 },
72 else => unreachable,
73 }
74 }
75 unreachable;
76}
std/zig/tokenizer.zig+1
...@@ -73,6 +73,7 @@ pub const Token = struct {...@@ -73,6 +73,7 @@ pub const Token = struct {
73 return null;73 return null;
74 }74 }
7575
76 /// TODO remove this enum
76 const StrLitKind = enum {77 const StrLitKind = enum {
77 Normal,78 Normal,
78 C,79 C,
test/stage2/compare_output.zig created+12
...@@ -0,0 +1,12 @@
1const std = @import("std");
2const TestContext = @import("../../src-self-hosted/test.zig").TestContext;
3
4pub fn addCases(ctx: *TestContext) !void {
5 try ctx.testCompareOutputLibC(
6 \\extern fn puts([*]const u8) void;
7 \\export fn main() c_int {
8 \\ puts(c"Hello, world!");
9 \\ return 0;
10 \\}
11 , "Hello, world!" ++ std.cstr.line_sep);
12}
test/stage2/compile_errors.zig+18
...@@ -9,4 +9,22 @@ pub fn addCases(ctx: *TestContext) !void {...@@ -9,4 +9,22 @@ pub fn addCases(ctx: *TestContext) !void {
9 try ctx.testCompileError(9 try ctx.testCompileError(
10 \\fn() void {}10 \\fn() void {}
11 , "1.zig", 1, 1, "missing function name");11 , "1.zig", 1, 1, "missing function name");
12
13 try ctx.testCompileError(
14 \\comptime {
15 \\ return;
16 \\}
17 , "1.zig", 2, 5, "return expression outside function definition");
18
19 try ctx.testCompileError(
20 \\export fn entry() void {
21 \\ defer return;
22 \\}
23 , "1.zig", 2, 11, "cannot return from defer expression");
24
25 try ctx.testCompileError(
26 \\export fn entry() c_int {
27 \\ return 36893488147419103232;
28 \\}
29 , "1.zig", 2, 12, "integer value '36893488147419103232' cannot be stored in type 'c_int'");
12}30}