authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-14 13:20:27-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-14 13:20:27-04:00
log0986dcf1cf5b67ad2b2e606622bf9b2c22e01194
tree0f2a6536a654932e15985717d2ddd78b944ccb66
parentfb947c365e95298a4619b8db2c0d40b9d69172f2

self-hosted: fix codegen and resolve some analysis bugs


7 files changed, 302 insertions(+), 79 deletions(-)

lib/std/fifo.zig+20-17
......@@ -191,8 +191,8 @@ pub fn LinearFifo(
191191 }
192192
193193 /// Read the next item from the fifo
194 pub fn readItem(self: *Self) !T {
195 if (self.count == 0) return error.EndOfStream;
194 pub fn readItem(self: *Self) ?T {
195 if (self.count == 0) return null;
196196
197197 const c = self.buf[self.head];
198198 self.discard(1);
......@@ -282,7 +282,10 @@ pub fn LinearFifo(
282282 /// Write a single item to the fifo
283283 pub fn writeItem(self: *Self, item: T) !void {
284284 try self.ensureUnusedCapacity(1);
285 return self.writeItemAssumeCapacity(item);
286 }
285287
288 pub fn writeItemAssumeCapacity(self: *Self, item: T) void {
286289 var tail = self.head + self.count;
287290 if (powers_of_two) {
288291 tail &= self.buf.len - 1;
......@@ -342,10 +345,10 @@ pub fn LinearFifo(
342345 }
343346 }
344347
345 /// Peek at the item at `offset`
346 pub fn peekItem(self: Self, offset: usize) error{EndOfStream}!T {
347 if (offset >= self.count)
348 return error.EndOfStream;
348 /// Returns the item at `offset`.
349 /// Asserts offset is within bounds.
350 pub fn peekItem(self: Self, offset: usize) T {
351 assert(offset < self.count);
349352
350353 var index = self.head + offset;
351354 if (powers_of_two) {
......@@ -369,18 +372,18 @@ test "LinearFifo(u8, .Dynamic)" {
369372 {
370373 var i: usize = 0;
371374 while (i < 5) : (i += 1) {
372 try fifo.write(&[_]u8{try fifo.peekItem(i)});
375 try fifo.write(&[_]u8{fifo.peekItem(i)});
373376 }
374377 testing.expectEqual(@as(usize, 10), fifo.readableLength());
375378 testing.expectEqualSlices(u8, "HELLOHELLO", fifo.readableSlice(0));
376379 }
377380
378381 {
379 testing.expectEqual(@as(u8, 'H'), try fifo.readItem());
380 testing.expectEqual(@as(u8, 'E'), try fifo.readItem());
381 testing.expectEqual(@as(u8, 'L'), try fifo.readItem());
382 testing.expectEqual(@as(u8, 'L'), try fifo.readItem());
383 testing.expectEqual(@as(u8, 'O'), try fifo.readItem());
382 testing.expectEqual(@as(u8, 'H'), fifo.readItem().?);
383 testing.expectEqual(@as(u8, 'E'), fifo.readItem().?);
384 testing.expectEqual(@as(u8, 'L'), fifo.readItem().?);
385 testing.expectEqual(@as(u8, 'L'), fifo.readItem().?);
386 testing.expectEqual(@as(u8, 'O'), fifo.readItem().?);
384387 }
385388 testing.expectEqual(@as(usize, 5), fifo.readableLength());
386389
......@@ -451,11 +454,11 @@ test "LinearFifo" {
451454 testing.expectEqual(@as(usize, 5), fifo.readableLength());
452455
453456 {
454 testing.expectEqual(@as(T, 0), try fifo.readItem());
455 testing.expectEqual(@as(T, 1), try fifo.readItem());
456 testing.expectEqual(@as(T, 1), try fifo.readItem());
457 testing.expectEqual(@as(T, 0), try fifo.readItem());
458 testing.expectEqual(@as(T, 1), try fifo.readItem());
457 testing.expectEqual(@as(T, 0), fifo.readItem().?);
458 testing.expectEqual(@as(T, 1), fifo.readItem().?);
459 testing.expectEqual(@as(T, 1), fifo.readItem().?);
460 testing.expectEqual(@as(T, 0), fifo.readItem().?);
461 testing.expectEqual(@as(T, 1), fifo.readItem().?);
459462 testing.expectEqual(@as(usize, 0), fifo.readableLength());
460463 }
461464
src-self-hosted/codegen.zig+77-10
......@@ -9,7 +9,18 @@ const link = @import("link.zig");
99const Target = std.Target;
1010const Allocator = mem.Allocator;
1111
12pub fn generateSymbol(bin_file: *link.ElfFile, typed_value: TypedValue, code: *std.ArrayList(u8)) !?*ir.ErrorMsg {
12pub const Result = union(enum) {
13 /// This value might or might not alias the `code` parameter passed to `generateSymbol`.
14 ok: []const u8,
15 fail: *ir.ErrorMsg,
16};
17
18pub fn generateSymbol(
19 bin_file: *link.ElfFile,
20 src: usize,
21 typed_value: TypedValue,
22 code: *std.ArrayList(u8),
23) error{OutOfMemory}!Result {
1324 switch (typed_value.ty.zigTypeTag()) {
1425 .Fn => {
1526 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
......@@ -18,25 +29,77 @@ pub fn generateSymbol(bin_file: *link.ElfFile, typed_value: TypedValue, code: *s
1829 .target = &bin_file.options.target,
1930 .mod_fn = module_fn,
2031 .code = code,
21 .inst_table = std.AutoHashMap(*ir.Inst, Function.MCValue).init(code.allocator),
32 .inst_table = std.AutoHashMap(*ir.Inst, Function.MCValue).init(bin_file.allocator),
2233 .err_msg = null,
2334 };
2435 defer function.inst_table.deinit();
2536
2637 for (module_fn.analysis.success.instructions) |inst| {
2738 const new_inst = function.genFuncInst(inst) catch |err| switch (err) {
28 error.CodegenFail => {
29 assert(function.err_msg != null);
30 break;
31 },
39 error.CodegenFail => return Result{ .fail = function.err_msg.? },
3240 else => |e| return e,
3341 };
3442 try function.inst_table.putNoClobber(inst, new_inst);
3543 }
3644
37 return function.err_msg;
45 if (function.err_msg) |em| {
46 return Result{ .fail = em };
47 } else {
48 return Result{ .ok = code.items };
49 }
50 },
51 .Array => {
52 if (typed_value.val.cast(Value.Payload.Bytes)) |payload| {
53 return Result{ .ok = payload.data };
54 }
55 return Result{
56 .fail = try ir.ErrorMsg.create(
57 bin_file.allocator,
58 src,
59 "TODO implement generateSymbol for more kinds of arrays",
60 .{},
61 ),
62 };
63 },
64 .Pointer => {
65 if (typed_value.val.cast(Value.Payload.DeclRef)) |payload| {
66 const decl = payload.decl;
67 assert(decl.link.local_sym_index != 0);
68 // TODO handle the dependency of this symbol on the decl's vaddr.
69 // If the decl changes vaddr, then this symbol needs to get regenerated.
70 const vaddr = bin_file.symbols.items[decl.link.local_sym_index].st_value;
71 const endian = bin_file.options.target.cpu.arch.endian();
72 switch (bin_file.ptr_width) {
73 .p32 => {
74 try code.resize(4);
75 mem.writeInt(u32, code.items[0..4], @intCast(u32, vaddr), endian);
76 },
77 .p64 => {
78 try code.resize(8);
79 mem.writeInt(u64, code.items[0..8], vaddr, endian);
80 },
81 }
82 return Result{ .ok = code.items };
83 }
84 return Result{
85 .fail = try ir.ErrorMsg.create(
86 bin_file.allocator,
87 src,
88 "TODO implement generateSymbol for pointer {}",
89 .{typed_value.val},
90 ),
91 };
92 },
93 else => |t| {
94 return Result{
95 .fail = try ir.ErrorMsg.create(
96 bin_file.allocator,
97 src,
98 "TODO implement generateSymbol for type '{}'",
99 .{@tagName(t)},
100 ),
101 };
38102 },
39 else => @panic("TODO implement generateSymbol for non-function decls"),
40103 }
41104}
42105
......@@ -390,14 +453,18 @@ const Function = struct {
390453 }
391454
392455 fn genTypedValue(self: *Function, src: usize, typed_value: TypedValue) !MCValue {
456 const allocator = self.code.allocator;
393457 switch (typed_value.ty.zigTypeTag()) {
394458 .Pointer => {
395459 const ptr_elem_type = typed_value.ty.elemType();
396460 switch (ptr_elem_type.zigTypeTag()) {
397461 .Array => {
398462 // TODO more checks to make sure this can be emitted as a string literal
399 const bytes = try typed_value.val.toAllocatedBytes(self.code.allocator);
400 defer self.code.allocator.free(bytes);
463 const bytes = typed_value.val.toAllocatedBytes(allocator) catch |err| switch (err) {
464 error.AnalysisFail => unreachable,
465 else => |e| return e,
466 };
467 defer allocator.free(bytes);
401468 const smaller_len = std.math.cast(u32, bytes.len) catch
402469 return self.fail(src, "TODO handle a larger string constant", .{});
403470
src-self-hosted/ir.zig+101-26
......@@ -191,7 +191,7 @@ pub const Module = struct {
191191 optimize_mode: std.builtin.Mode,
192192 link_error_flags: link.ElfFile.ErrorFlags = link.ElfFile.ErrorFlags{},
193193
194 work_stack: ArrayListUnmanaged(WorkItem) = ArrayListUnmanaged(WorkItem){},
194 work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic),
195195
196196 /// We optimize memory usage for a compilation with no compile errors by storing the
197197 /// error messages and mapping outside of `Decl`.
......@@ -333,6 +333,15 @@ pub const Module = struct {
333333 return (try self.typedValue()).val;
334334 }
335335
336 pub fn dump(self: *Decl) void {
337 self.scope.dumpSrc(self.src);
338 std.debug.warn(" name={} status={}", .{ mem.spanZ(self.name), @tagName(self.analysis) });
339 if (self.typedValueManaged()) |tvm| {
340 std.debug.warn(" ty={} val={}", .{ tvm.typed_value.ty, tvm.typed_value.val });
341 }
342 std.debug.warn("\n", .{});
343 }
344
336345 fn typedValueManaged(self: *Decl) ?*TypedValue.Managed {
337346 switch (self.analysis) {
338347 .initial_in_progress,
......@@ -359,7 +368,10 @@ pub const Module = struct {
359368 queued: *text.Inst.Fn,
360369 in_progress: *Analysis,
361370 /// There will be a corresponding ErrorMsg in Module.failed_decls
362 failure,
371 sema_failure,
372 /// This Fn might be OK but it depends on another Decl which did not successfully complete
373 /// semantic analysis.
374 dependency_failure,
363375 success: Body,
364376 },
365377
......@@ -390,7 +402,7 @@ pub const Module = struct {
390402 switch (self.tag) {
391403 .block => return self.cast(Block).?.arena,
392404 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
393 .zir_module => unreachable,
405 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
394406 }
395407 }
396408
......@@ -414,6 +426,18 @@ pub const Module = struct {
414426 }
415427 }
416428
429 pub fn dumpInst(self: *Scope, inst: *Inst) void {
430 const zir_module = self.namespace();
431 const loc = std.zig.findLineColumn(zir_module.source.bytes, inst.src);
432 std.debug.warn("{}:{}:{}: {}: ty={}\n", .{
433 zir_module.sub_file_path,
434 loc.line + 1,
435 loc.column + 1,
436 @tagName(inst.tag),
437 inst.ty,
438 });
439 }
440
417441 pub const Tag = enum {
418442 zir_module,
419443 block,
......@@ -438,6 +462,7 @@ pub const Module = struct {
438462 unloaded,
439463 unloaded_parse_failure,
440464 loaded_parse_failure,
465 loaded_sema_failure,
441466 loaded_success,
442467 },
443468
......@@ -446,7 +471,7 @@ pub const Module = struct {
446471 .unloaded,
447472 .unloaded_parse_failure,
448473 => {},
449 .loaded_success => {
474 .loaded_success, .loaded_sema_failure => {
450475 allocator.free(self.source.bytes);
451476 self.contents.module.deinit(allocator);
452477 },
......@@ -456,6 +481,11 @@ pub const Module = struct {
456481 }
457482 self.* = undefined;
458483 }
484
485 pub fn dumpSrc(self: *ZIRModule, src: usize) void {
486 const loc = std.zig.findLineColumn(self.source.bytes, src);
487 std.debug.warn("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
488 }
459489 };
460490
461491 /// This is a temporary structure, references to it are valid only
......@@ -520,7 +550,7 @@ pub const Module = struct {
520550
521551 pub fn deinit(self: *Module) void {
522552 const allocator = self.allocator;
523 self.work_stack.deinit(allocator);
553 self.work_queue.deinit();
524554 {
525555 var it = self.decl_table.iterator();
526556 while (it.next()) |kv| {
......@@ -587,6 +617,8 @@ pub const Module = struct {
587617
588618 try self.performAllTheWork();
589619
620 // TODO unload all the source files from memory
621
590622 try self.bin_file.flush();
591623 self.link_error_flags = self.bin_file.error_flags;
592624 }
......@@ -654,7 +686,7 @@ pub const Module = struct {
654686 const InnerError = error{ OutOfMemory, AnalysisFail };
655687
656688 pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {
657 while (self.work_stack.popOrNull()) |work_item| switch (work_item) {
689 while (self.work_queue.readItem()) |work_item| switch (work_item) {
658690 .codegen_decl => |decl| switch (decl.analysis) {
659691 .initial_in_progress,
660692 .repeat_in_progress,
......@@ -671,14 +703,22 @@ pub const Module = struct {
671703 if (decl.typed_value.most_recent.typed_value.val.cast(Value.Payload.Function)) |payload| {
672704 switch (payload.func.analysis) {
673705 .queued => self.analyzeFnBody(decl, payload.func) catch |err| switch (err) {
674 error.AnalysisFail => continue,
706 error.AnalysisFail => {
707 if (payload.func.analysis == .queued) {
708 payload.func.analysis = .dependency_failure;
709 }
710 continue;
711 },
675712 else => |e| return e,
676713 },
677714 .in_progress => unreachable,
678 .failure => continue,
715 .sema_failure, .dependency_failure => continue,
679716 .success => {},
680717 }
681718 }
719 if (!decl.typed_value.most_recent.typed_value.ty.hasCodeGenBits())
720 continue;
721
682722 self.bin_file.updateDecl(self, decl) catch |err| switch (err) {
683723 error.OutOfMemory => return error.OutOfMemory,
684724 else => {
......@@ -739,7 +779,10 @@ pub const Module = struct {
739779 return zir_module;
740780 },
741781
742 .unloaded_parse_failure, .loaded_parse_failure => return error.AnalysisFail,
782 .unloaded_parse_failure,
783 .loaded_parse_failure,
784 .loaded_sema_failure,
785 => return error.AnalysisFail,
743786 .loaded_success => return root_scope.contents.module,
744787 }
745788 }
......@@ -756,14 +799,11 @@ pub const Module = struct {
756799
757800 // Here we ensure enough queue capacity to store all the decls, so that later we can use
758801 // appendAssumeCapacity.
759 try self.work_stack.ensureCapacity(
760 self.allocator,
761 self.work_stack.items.len + src_module.decls.len,
762 );
802 try self.work_queue.ensureUnusedCapacity(src_module.decls.len);
763803
764804 for (src_module.decls) |decl| {
765805 if (decl.cast(text.Inst.Export)) |export_inst| {
766 try analyzeExport(self, &root_scope.base, export_inst);
806 _ = try self.resolveDecl(&root_scope.base, &export_inst.base);
767807 }
768808 }
769809 }
......@@ -825,10 +865,19 @@ pub const Module = struct {
825865 };
826866 errdefer decl_scope.arena.deinit();
827867
868 const typed_value = self.analyzeInstConst(&decl_scope.base, old_inst) catch |err| switch (err) {
869 error.OutOfMemory => return error.OutOfMemory,
870 error.AnalysisFail => {
871 switch (new_decl.analysis) {
872 .initial_in_progress => new_decl.analysis = .initial_dependency_failure,
873 .repeat_in_progress => new_decl.analysis = .repeat_dependency_failure,
874 else => {},
875 }
876 return error.AnalysisFail;
877 },
878 };
828879 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);
829880
830 const typed_value = try self.analyzeInstConst(&decl_scope.base, old_inst);
831
832881 arena_state.* = decl_scope.arena.state;
833882
834883 new_decl.typed_value = .{
......@@ -839,7 +888,7 @@ pub const Module = struct {
839888 };
840889 new_decl.analysis = .complete;
841890 // We ensureCapacity when scanning for decls.
842 self.work_stack.appendAssumeCapacity(.{ .codegen_decl = new_decl });
891 self.work_queue.writeItemAssumeCapacity(.{ .codegen_decl = new_decl });
843892 return new_decl;
844893 }
845894 }
......@@ -1021,11 +1070,8 @@ pub const Module = struct {
10211070 }
10221071
10231072 fn constStr(self: *Module, scope: *Scope, src: usize, str: []const u8) !*Inst {
1024 const array_payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
1025 array_payload.* = .{ .len = str.len };
1026
1027 const ty_payload = try scope.arena().create(Type.Payload.SingleConstPointer);
1028 ty_payload.* = .{ .pointee_type = Type.initPayload(&array_payload.base) };
1073 const ty_payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
1074 ty_payload.* = .{ .len = str.len };
10291075
10301076 const bytes_payload = try scope.arena().create(Value.Payload.Bytes);
10311077 bytes_payload.* = .{ .data = str };
......@@ -1150,6 +1196,7 @@ pub const Module = struct {
11501196 return self.constVoid(scope, old_inst.src);
11511197 },
11521198 .primitive => return self.analyzeInstPrimitive(scope, old_inst.cast(text.Inst.Primitive).?),
1199 .ref => return self.analyzeInstRef(scope, old_inst.cast(text.Inst.Ref).?),
11531200 .fntype => return self.analyzeInstFnType(scope, old_inst.cast(text.Inst.FnType).?),
11541201 .intcast => return self.analyzeInstIntCast(scope, old_inst.cast(text.Inst.IntCast).?),
11551202 .bitcast => return self.analyzeInstBitCast(scope, old_inst.cast(text.Inst.BitCast).?),
......@@ -1167,12 +1214,34 @@ pub const Module = struct {
11671214 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){});
11681215 }
11691216
1217 fn analyzeInstRef(self: *Module, scope: *Scope, inst: *text.Inst.Ref) InnerError!*Inst {
1218 const decl = try self.resolveCompleteDecl(scope, inst.positionals.operand);
1219 return self.analyzeDeclRef(scope, inst.base.src, decl);
1220 }
1221
11701222 fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *text.Inst.DeclRef) InnerError!*Inst {
1171 return self.fail(scope, inst.base.src, "TODO implement analyzeInstDeclFef", .{});
1223 const decl_name = try self.resolveConstString(scope, inst.positionals.name);
1224 // This will need to get more fleshed out when there are proper structs & namespaces.
1225 const zir_module = scope.namespace();
1226 for (zir_module.contents.module.decls) |src_decl| {
1227 if (mem.eql(u8, src_decl.name, decl_name)) {
1228 const decl = try self.resolveCompleteDecl(scope, src_decl);
1229 return self.analyzeDeclRef(scope, inst.base.src, decl);
1230 }
1231 }
1232 return self.fail(scope, inst.positionals.name.src, "use of undeclared identifier '{}'", .{decl_name});
11721233 }
11731234
11741235 fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {
1175 return self.fail(scope, src, "TODO implement analyzeDeclRef", .{});
1236 const decl_tv = try decl.typedValue();
1237 const ty_payload = try scope.arena().create(Type.Payload.SingleConstPointer);
1238 ty_payload.* = .{ .pointee_type = decl_tv.ty };
1239 const val_payload = try scope.arena().create(Value.Payload.DeclRef);
1240 val_payload.* = .{ .decl = decl };
1241 return self.constInst(scope, src, .{
1242 .ty = Type.initPayload(&ty_payload.base),
1243 .val = Value.initPayload(&val_payload.base),
1244 });
11761245 }
11771246
11781247 fn analyzeInstCall(self: *Module, scope: *Scope, inst: *text.Inst.Call) InnerError!*Inst {
......@@ -1929,6 +1998,7 @@ pub const Module = struct {
19291998 fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: var) InnerError {
19301999 @setCold(true);
19312000 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
2001 try self.failed_files.ensureCapacity(self.failed_files.size + 1);
19322002 const err_msg = try ErrorMsg.create(self.allocator, src, format, args);
19332003 switch (scope.tag) {
19342004 .decl => {
......@@ -1942,10 +2012,14 @@ pub const Module = struct {
19422012 },
19432013 .block => {
19442014 const block = scope.cast(Scope.Block).?;
1945 block.func.analysis = .failure;
2015 block.func.analysis = .sema_failure;
19462016 self.failed_decls.putAssumeCapacityNoClobber(block.decl, err_msg);
19472017 },
1948 .zir_module => unreachable,
2018 .zir_module => {
2019 const zir_module = scope.cast(Scope.ZIRModule).?;
2020 zir_module.status = .loaded_sema_failure;
2021 self.failed_files.putAssumeCapacityNoClobber(zir_module, err_msg);
2022 },
19492023 }
19502024 return error.AnalysisFail;
19512025 }
......@@ -2044,6 +2118,7 @@ pub fn main() anyerror!void {
20442118 .failed_decls = std.AutoHashMap(*Module.Decl, *ErrorMsg).init(allocator),
20452119 .failed_files = std.AutoHashMap(*Module.Scope.ZIRModule, *ErrorMsg).init(allocator),
20462120 .failed_exports = std.AutoHashMap(*Module.Export, *ErrorMsg).init(allocator),
2121 .work_queue = std.fifo.LinearFifo(Module.WorkItem, .Dynamic).init(allocator),
20472122 };
20482123 };
20492124 defer module.deinit();
src-self-hosted/ir/text.zig+25-9
......@@ -24,8 +24,7 @@ pub const Inst = struct {
2424 breakpoint,
2525 call,
2626 /// Represents a reference to a global decl by name.
27 /// Canonicalized ZIR will not have any of these. The
28 /// syntax `@foo` is equivalent to `declref("foo")`.
27 /// The syntax `@foo` is equivalent to `declref("foo")`.
2928 declref,
3029 str,
3130 int,
......@@ -39,6 +38,7 @@ pub const Inst = struct {
3938 @"fn",
4039 @"export",
4140 primitive,
41 ref,
4242 fntype,
4343 intcast,
4444 bitcast,
......@@ -67,6 +67,7 @@ pub const Inst = struct {
6767 .@"fn" => Fn,
6868 .@"export" => Export,
6969 .primitive => Primitive,
70 .ref => Ref,
7071 .fntype => FnType,
7172 .intcast => IntCast,
7273 .bitcast => BitCast,
......@@ -234,6 +235,16 @@ pub const Inst = struct {
234235 kw_args: struct {},
235236 };
236237
238 pub const Ref = struct {
239 pub const base_tag = Tag.ref;
240 base: Inst,
241
242 positionals: struct {
243 operand: *Inst,
244 },
245 kw_args: struct {},
246 };
247
237248 pub const Primitive = struct {
238249 pub const base_tag = Tag.primitive;
239250 base: Inst,
......@@ -407,7 +418,7 @@ pub const ErrorMsg = struct {
407418
408419pub const Module = struct {
409420 decls: []*Inst,
410 arena: std.heap.ArenaAllocator.State,
421 arena: std.heap.ArenaAllocator,
411422 error_msg: ?ErrorMsg = null,
412423
413424 pub const Body = struct {
......@@ -416,7 +427,7 @@ pub const Module = struct {
416427
417428 pub fn deinit(self: *Module, allocator: *Allocator) void {
418429 allocator.free(self.decls);
419 self.arena.promote(allocator).deinit();
430 self.arena.deinit();
420431 self.* = undefined;
421432 }
422433
......@@ -475,6 +486,7 @@ pub const Module = struct {
475486 .@"return" => return self.writeInstToStreamGeneric(stream, .@"return", decl, inst_table),
476487 .@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", decl, inst_table),
477488 .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", decl, inst_table),
489 .ref => return self.writeInstToStreamGeneric(stream, .ref, decl, inst_table),
478490 .primitive => return self.writeInstToStreamGeneric(stream, .primitive, decl, inst_table),
479491 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, decl, inst_table),
480492 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, decl, inst_table),
......@@ -591,7 +603,7 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module
591603
592604 return Module{
593605 .decls = parser.decls.toOwnedSlice(allocator),
594 .arena = parser.arena.state,
606 .arena = parser.arena,
595607 .error_msg = parser.error_msg,
596608 };
597609}
......@@ -630,7 +642,7 @@ const Parser = struct {
630642 skipSpace(self);
631643 try requireEatBytes(self, "=");
632644 skipSpace(self);
633 const inst = try parseInstruction(self, &body_context, ident[1..]);
645 const inst = try parseInstruction(self, &body_context, ident);
634646 const ident_index = body_context.instructions.items.len;
635647 if (try body_context.name_map.put(ident, ident_index)) |_| {
636648 return self.fail("redefinition of identifier '{}'", .{ident});
......@@ -716,7 +728,7 @@ const Parser = struct {
716728 skipSpace(self);
717729 try requireEatBytes(self, "=");
718730 skipSpace(self);
719 const inst = try parseInstruction(self, null, ident[1..]);
731 const inst = try parseInstruction(self, null, ident);
720732 const ident_index = self.decls.items.len;
721733 if (try self.global_name_map.put(ident, ident_index)) |_| {
722734 return self.fail("redefinition of identifier '{}'", .{ident});
......@@ -987,7 +999,7 @@ pub fn emit_zir(allocator: *Allocator, old_module: ir.Module) !Module {
987999
9881000 return Module{
9891001 .decls = ctx.decls.toOwnedSlice(allocator),
990 .arena = ctx.arena.state,
1002 .arena = ctx.arena,
9911003 };
9921004}
9931005
......@@ -1056,6 +1068,7 @@ const EmitZIR = struct {
10561068 }
10571069
10581070 fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Inst {
1071 const allocator = &self.arena.allocator;
10591072 switch (typed_value.ty.zigTypeTag()) {
10601073 .Pointer => {
10611074 const ptr_elem_type = typed_value.ty.elemType();
......@@ -1067,7 +1080,10 @@ const EmitZIR = struct {
10671080 // ptr_elem_type.hasSentinel(Value.initTag(.zero)))
10681081 //{
10691082 //}
1070 const bytes = try typed_value.val.toAllocatedBytes(&self.arena.allocator);
1083 const bytes = typed_value.val.toAllocatedBytes(allocator) catch |err| switch (err) {
1084 error.AnalysisFail => unreachable,
1085 else => |e| return e,
1086 };
10711087 return self.emitStringLiteral(src, bytes);
10721088 },
10731089 else => |t| std.debug.panic("TODO implement emitTypedValue for pointer to {}", .{@tagName(t)}),
src-self-hosted/link.zig+27-16
......@@ -33,9 +33,11 @@ pub fn openBinFilePath(
3333 options: Options,
3434) !ElfFile {
3535 const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(options) });
36 defer file.close();
36 errdefer file.close();
3737
38 return openBinFile(allocator, file, options);
38 var bin_file = try openBinFile(allocator, file, options);
39 bin_file.owns_file_handle = true;
40 return bin_file;
3941}
4042
4143/// Atomically overwrites the old file, if present.
......@@ -89,6 +91,7 @@ pub fn openBinFile(allocator: *Allocator, file: fs.File, options: Options) !ElfF
8991pub const ElfFile = struct {
9092 allocator: *Allocator,
9193 file: fs.File,
94 owns_file_handle: bool,
9295 options: Options,
9396 ptr_width: enum { p32, p64 },
9497
......@@ -162,6 +165,8 @@ pub const ElfFile = struct {
162165 self.shstrtab.deinit(self.allocator);
163166 self.symbols.deinit(self.allocator);
164167 self.offset_table.deinit(self.allocator);
168 if (self.owns_file_handle)
169 self.file.close();
165170 }
166171
167172 // `alloc_num / alloc_den` is the factor of padding when allocation
......@@ -685,7 +690,7 @@ pub const ElfFile = struct {
685690 // TODO Also detect virtual address collisions.
686691 const text_capacity = self.allocatedSize(shdr.sh_offset);
687692 // TODO instead of looping here, maintain a free list and a pointer to the end.
688 var last_start: u64 = 0;
693 var last_start: u64 = phdr.p_vaddr;
689694 var last_size: u64 = 0;
690695 for (self.symbols.items) |sym| {
691696 if (sym.st_value > last_start) {
......@@ -738,19 +743,21 @@ pub const ElfFile = struct {
738743 }
739744
740745 pub fn updateDecl(self: *ElfFile, module: *ir.Module, decl: *ir.Module.Decl) !void {
741 var code = std.ArrayList(u8).init(self.allocator);
742 defer code.deinit();
746 var code_buffer = std.ArrayList(u8).init(self.allocator);
747 defer code_buffer.deinit();
743748
744749 const typed_value = decl.typed_value.most_recent.typed_value;
745 const err_msg = try codegen.generateSymbol(self, typed_value, &code);
746 if (err_msg) |em| {
747 decl.analysis = .codegen_failure;
748 _ = try module.failed_decls.put(decl, em);
749 return;
750 }
750 const code = switch (try codegen.generateSymbol(self, decl.src, typed_value, &code_buffer)) {
751 .ok => |x| x,
752 .fail => |em| {
753 decl.analysis = .codegen_failure;
754 _ = try module.failed_decls.put(decl, em);
755 return;
756 },
757 };
751758
752759 const file_offset = blk: {
753 const code_size = code.items.len;
760 const code_size = code.len;
754761 const stt_bits: u8 = switch (typed_value.ty.zigTypeTag()) {
755762 .Fn => elf.STT_FUNC,
756763 else => elf.STT_OBJECT,
......@@ -793,11 +800,13 @@ pub const ElfFile = struct {
793800 errdefer self.symbols.shrink(self.allocator, self.symbols.items.len - 1);
794801 self.offset_table.appendAssumeCapacity(new_block.vaddr);
795802 errdefer self.offset_table.shrink(self.allocator, self.offset_table.items.len - 1);
796 try self.writeSymbol(local_sym_index);
797 try self.writeOffsetTableEntry(offset_table_index);
798803
799804 self.symbol_count_dirty = true;
800805 self.offset_table_count_dirty = true;
806
807 try self.writeSymbol(local_sym_index);
808 try self.writeOffsetTableEntry(offset_table_index);
809
801810 decl.link = .{
802811 .local_sym_index = @intCast(u32, local_sym_index),
803812 .offset_table_index = @intCast(u32, offset_table_index),
......@@ -807,7 +816,7 @@ pub const ElfFile = struct {
807816 }
808817 };
809818
810 try self.file.pwriteAll(code.items, file_offset);
819 try self.file.pwriteAll(code, file_offset);
811820
812821 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
813822 const decl_exports = module.decl_exports.getValue(decl) orelse &[0]*ir.Module.Export{};
......@@ -823,7 +832,7 @@ pub const ElfFile = struct {
823832 ) !void {
824833 try self.symbols.ensureCapacity(self.allocator, self.symbols.items.len + exports.len);
825834 const typed_value = decl.typed_value.most_recent.typed_value;
826 assert(decl.link.local_sym_index != 0);
835 if (decl.link.local_sym_index == 0) return;
827836 const decl_sym = self.symbols.items[decl.link.local_sym_index];
828837
829838 for (exports) |exp| {
......@@ -1112,6 +1121,7 @@ pub fn createElfFile(allocator: *Allocator, file: fs.File, options: Options) !El
11121121 else => return error.UnsupportedELFArchitecture,
11131122 },
11141123 .shdr_table_dirty = true,
1124 .owns_file_handle = false,
11151125 };
11161126 errdefer self.deinit();
11171127
......@@ -1161,6 +1171,7 @@ fn openBinFileInner(allocator: *Allocator, file: fs.File, options: Options) !Elf
11611171 var self: ElfFile = .{
11621172 .allocator = allocator,
11631173 .file = file,
1174 .owns_file_handle = false,
11641175 .options = options,
11651176 .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
11661177 32 => .p32,
src-self-hosted/type.zig+44
......@@ -262,6 +262,50 @@ pub const Type = extern union {
262262 }
263263 }
264264
265 pub fn hasCodeGenBits(self: Type) bool {
266 return switch (self.tag()) {
267 .u8,
268 .i8,
269 .isize,
270 .usize,
271 .c_short,
272 .c_ushort,
273 .c_int,
274 .c_uint,
275 .c_long,
276 .c_ulong,
277 .c_longlong,
278 .c_ulonglong,
279 .c_longdouble,
280 .f16,
281 .f32,
282 .f64,
283 .f128,
284 .bool,
285 .anyerror,
286 .fn_noreturn_no_args,
287 .fn_naked_noreturn_no_args,
288 .fn_ccc_void_no_args,
289 .single_const_pointer_to_comptime_int,
290 .const_slice_u8, // See last_no_payload_tag below.
291 .array_u8_sentinel_0,
292 .array,
293 .single_const_pointer,
294 .int_signed,
295 .int_unsigned,
296 => true,
297
298 .c_void,
299 .void,
300 .type,
301 .comptime_int,
302 .comptime_float,
303 .noreturn,
304 .@"null",
305 => false,
306 };
307 }
308
265309 pub fn isSinglePointer(self: Type) bool {
266310 return switch (self.tag()) {
267311 .u8,
src-self-hosted/value.zig+8-1
......@@ -180,10 +180,17 @@ pub const Value = extern union {
180180
181181 /// Asserts that the value is representable as an array of bytes.
182182 /// Copies the value into a freshly allocated slice of memory, which is owned by the caller.
183 pub fn toAllocatedBytes(self: Value, allocator: *Allocator) Allocator.Error![]u8 {
183 pub fn toAllocatedBytes(self: Value, allocator: *Allocator) ![]u8 {
184184 if (self.cast(Payload.Bytes)) |bytes| {
185185 return std.mem.dupe(allocator, u8, bytes.data);
186186 }
187 if (self.cast(Payload.Repeated)) |repeated| {
188 @panic("TODO implement toAllocatedBytes for this Value tag");
189 }
190 if (self.cast(Payload.DeclRef)) |declref| {
191 const val = try declref.decl.value();
192 return val.toAllocatedBytes(allocator);
193 }
187194 unreachable;
188195 }
189196