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(...@@ -191,8 +191,8 @@ pub fn LinearFifo(
191 }191 }
192192
193 /// Read the next item from the fifo193 /// Read the next item from the fifo
194 pub fn readItem(self: *Self) !T {194 pub fn readItem(self: *Self) ?T {
195 if (self.count == 0) return error.EndOfStream;195 if (self.count == 0) return null;
196196
197 const c = self.buf[self.head];197 const c = self.buf[self.head];
198 self.discard(1);198 self.discard(1);
...@@ -282,7 +282,10 @@ pub fn LinearFifo(...@@ -282,7 +282,10 @@ pub fn LinearFifo(
282 /// Write a single item to the fifo282 /// Write a single item to the fifo
283 pub fn writeItem(self: *Self, item: T) !void {283 pub fn writeItem(self: *Self, item: T) !void {
284 try self.ensureUnusedCapacity(1);284 try self.ensureUnusedCapacity(1);
285 return self.writeItemAssumeCapacity(item);
286 }
285287
288 pub fn writeItemAssumeCapacity(self: *Self, item: T) void {
286 var tail = self.head + self.count;289 var tail = self.head + self.count;
287 if (powers_of_two) {290 if (powers_of_two) {
288 tail &= self.buf.len - 1;291 tail &= self.buf.len - 1;
...@@ -342,10 +345,10 @@ pub fn LinearFifo(...@@ -342,10 +345,10 @@ pub fn LinearFifo(
342 }345 }
343 }346 }
344347
345 /// Peek at the item at `offset`348 /// Returns the item at `offset`.
346 pub fn peekItem(self: Self, offset: usize) error{EndOfStream}!T {349 /// Asserts offset is within bounds.
347 if (offset >= self.count)350 pub fn peekItem(self: Self, offset: usize) T {
348 return error.EndOfStream;351 assert(offset < self.count);
349352
350 var index = self.head + offset;353 var index = self.head + offset;
351 if (powers_of_two) {354 if (powers_of_two) {
...@@ -369,18 +372,18 @@ test "LinearFifo(u8, .Dynamic)" {...@@ -369,18 +372,18 @@ test "LinearFifo(u8, .Dynamic)" {
369 {372 {
370 var i: usize = 0;373 var i: usize = 0;
371 while (i < 5) : (i += 1) {374 while (i < 5) : (i += 1) {
372 try fifo.write(&[_]u8{try fifo.peekItem(i)});375 try fifo.write(&[_]u8{fifo.peekItem(i)});
373 }376 }
374 testing.expectEqual(@as(usize, 10), fifo.readableLength());377 testing.expectEqual(@as(usize, 10), fifo.readableLength());
375 testing.expectEqualSlices(u8, "HELLOHELLO", fifo.readableSlice(0));378 testing.expectEqualSlices(u8, "HELLOHELLO", fifo.readableSlice(0));
376 }379 }
377380
378 {381 {
379 testing.expectEqual(@as(u8, 'H'), try fifo.readItem());382 testing.expectEqual(@as(u8, 'H'), fifo.readItem().?);
380 testing.expectEqual(@as(u8, 'E'), try fifo.readItem());383 testing.expectEqual(@as(u8, 'E'), fifo.readItem().?);
381 testing.expectEqual(@as(u8, 'L'), try fifo.readItem());384 testing.expectEqual(@as(u8, 'L'), fifo.readItem().?);
382 testing.expectEqual(@as(u8, 'L'), try fifo.readItem());385 testing.expectEqual(@as(u8, 'L'), fifo.readItem().?);
383 testing.expectEqual(@as(u8, 'O'), try fifo.readItem());386 testing.expectEqual(@as(u8, 'O'), fifo.readItem().?);
384 }387 }
385 testing.expectEqual(@as(usize, 5), fifo.readableLength());388 testing.expectEqual(@as(usize, 5), fifo.readableLength());
386389
...@@ -451,11 +454,11 @@ test "LinearFifo" {...@@ -451,11 +454,11 @@ test "LinearFifo" {
451 testing.expectEqual(@as(usize, 5), fifo.readableLength());454 testing.expectEqual(@as(usize, 5), fifo.readableLength());
452455
453 {456 {
454 testing.expectEqual(@as(T, 0), try fifo.readItem());457 testing.expectEqual(@as(T, 0), fifo.readItem().?);
455 testing.expectEqual(@as(T, 1), try fifo.readItem());458 testing.expectEqual(@as(T, 1), fifo.readItem().?);
456 testing.expectEqual(@as(T, 1), try fifo.readItem());459 testing.expectEqual(@as(T, 1), fifo.readItem().?);
457 testing.expectEqual(@as(T, 0), try fifo.readItem());460 testing.expectEqual(@as(T, 0), fifo.readItem().?);
458 testing.expectEqual(@as(T, 1), try fifo.readItem());461 testing.expectEqual(@as(T, 1), fifo.readItem().?);
459 testing.expectEqual(@as(usize, 0), fifo.readableLength());462 testing.expectEqual(@as(usize, 0), fifo.readableLength());
460 }463 }
461464
src-self-hosted/codegen.zig+77-10
...@@ -9,7 +9,18 @@ const link = @import("link.zig");...@@ -9,7 +9,18 @@ const link = @import("link.zig");
9const Target = std.Target;9const Target = std.Target;
10const Allocator = mem.Allocator;10const 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 {
13 switch (typed_value.ty.zigTypeTag()) {24 switch (typed_value.ty.zigTypeTag()) {
14 .Fn => {25 .Fn => {
15 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;26 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...@@ -18,25 +29,77 @@ pub fn generateSymbol(bin_file: *link.ElfFile, typed_value: TypedValue, code: *s
18 .target = &bin_file.options.target,29 .target = &bin_file.options.target,
19 .mod_fn = module_fn,30 .mod_fn = module_fn,
20 .code = code,31 .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),
22 .err_msg = null,33 .err_msg = null,
23 };34 };
24 defer function.inst_table.deinit();35 defer function.inst_table.deinit();
2536
26 for (module_fn.analysis.success.instructions) |inst| {37 for (module_fn.analysis.success.instructions) |inst| {
27 const new_inst = function.genFuncInst(inst) catch |err| switch (err) {38 const new_inst = function.genFuncInst(inst) catch |err| switch (err) {
28 error.CodegenFail => {39 error.CodegenFail => return Result{ .fail = function.err_msg.? },
29 assert(function.err_msg != null);
30 break;
31 },
32 else => |e| return e,40 else => |e| return e,
33 };41 };
34 try function.inst_table.putNoClobber(inst, new_inst);42 try function.inst_table.putNoClobber(inst, new_inst);
35 }43 }
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 };
38 },102 },
39 else => @panic("TODO implement generateSymbol for non-function decls"),
40 }103 }
41}104}
42105
...@@ -390,14 +453,18 @@ const Function = struct {...@@ -390,14 +453,18 @@ const Function = struct {
390 }453 }
391454
392 fn genTypedValue(self: *Function, src: usize, typed_value: TypedValue) !MCValue {455 fn genTypedValue(self: *Function, src: usize, typed_value: TypedValue) !MCValue {
456 const allocator = self.code.allocator;
393 switch (typed_value.ty.zigTypeTag()) {457 switch (typed_value.ty.zigTypeTag()) {
394 .Pointer => {458 .Pointer => {
395 const ptr_elem_type = typed_value.ty.elemType();459 const ptr_elem_type = typed_value.ty.elemType();
396 switch (ptr_elem_type.zigTypeTag()) {460 switch (ptr_elem_type.zigTypeTag()) {
397 .Array => {461 .Array => {
398 // TODO more checks to make sure this can be emitted as a string literal462 // 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);463 const bytes = typed_value.val.toAllocatedBytes(allocator) catch |err| switch (err) {
400 defer self.code.allocator.free(bytes);464 error.AnalysisFail => unreachable,
465 else => |e| return e,
466 };
467 defer allocator.free(bytes);
401 const smaller_len = std.math.cast(u32, bytes.len) catch468 const smaller_len = std.math.cast(u32, bytes.len) catch
402 return self.fail(src, "TODO handle a larger string constant", .{});469 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 {...@@ -191,7 +191,7 @@ pub const Module = struct {
191 optimize_mode: std.builtin.Mode,191 optimize_mode: std.builtin.Mode,
192 link_error_flags: link.ElfFile.ErrorFlags = link.ElfFile.ErrorFlags{},192 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
196 /// We optimize memory usage for a compilation with no compile errors by storing the196 /// We optimize memory usage for a compilation with no compile errors by storing the
197 /// error messages and mapping outside of `Decl`.197 /// error messages and mapping outside of `Decl`.
...@@ -333,6 +333,15 @@ pub const Module = struct {...@@ -333,6 +333,15 @@ pub const Module = struct {
333 return (try self.typedValue()).val;333 return (try self.typedValue()).val;
334 }334 }
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
336 fn typedValueManaged(self: *Decl) ?*TypedValue.Managed {345 fn typedValueManaged(self: *Decl) ?*TypedValue.Managed {
337 switch (self.analysis) {346 switch (self.analysis) {
338 .initial_in_progress,347 .initial_in_progress,
...@@ -359,7 +368,10 @@ pub const Module = struct {...@@ -359,7 +368,10 @@ pub const Module = struct {
359 queued: *text.Inst.Fn,368 queued: *text.Inst.Fn,
360 in_progress: *Analysis,369 in_progress: *Analysis,
361 /// There will be a corresponding ErrorMsg in Module.failed_decls370 /// 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,
363 success: Body,375 success: Body,
364 },376 },
365377
...@@ -390,7 +402,7 @@ pub const Module = struct {...@@ -390,7 +402,7 @@ pub const Module = struct {
390 switch (self.tag) {402 switch (self.tag) {
391 .block => return self.cast(Block).?.arena,403 .block => return self.cast(Block).?.arena,
392 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,404 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
393 .zir_module => unreachable,405 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
394 }406 }
395 }407 }
396408
...@@ -414,6 +426,18 @@ pub const Module = struct {...@@ -414,6 +426,18 @@ pub const Module = struct {
414 }426 }
415 }427 }
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
417 pub const Tag = enum {441 pub const Tag = enum {
418 zir_module,442 zir_module,
419 block,443 block,
...@@ -438,6 +462,7 @@ pub const Module = struct {...@@ -438,6 +462,7 @@ pub const Module = struct {
438 unloaded,462 unloaded,
439 unloaded_parse_failure,463 unloaded_parse_failure,
440 loaded_parse_failure,464 loaded_parse_failure,
465 loaded_sema_failure,
441 loaded_success,466 loaded_success,
442 },467 },
443468
...@@ -446,7 +471,7 @@ pub const Module = struct {...@@ -446,7 +471,7 @@ pub const Module = struct {
446 .unloaded,471 .unloaded,
447 .unloaded_parse_failure,472 .unloaded_parse_failure,
448 => {},473 => {},
449 .loaded_success => {474 .loaded_success, .loaded_sema_failure => {
450 allocator.free(self.source.bytes);475 allocator.free(self.source.bytes);
451 self.contents.module.deinit(allocator);476 self.contents.module.deinit(allocator);
452 },477 },
...@@ -456,6 +481,11 @@ pub const Module = struct {...@@ -456,6 +481,11 @@ pub const Module = struct {
456 }481 }
457 self.* = undefined;482 self.* = undefined;
458 }483 }
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 }
459 };489 };
460490
461 /// This is a temporary structure, references to it are valid only491 /// This is a temporary structure, references to it are valid only
...@@ -520,7 +550,7 @@ pub const Module = struct {...@@ -520,7 +550,7 @@ pub const Module = struct {
520550
521 pub fn deinit(self: *Module) void {551 pub fn deinit(self: *Module) void {
522 const allocator = self.allocator;552 const allocator = self.allocator;
523 self.work_stack.deinit(allocator);553 self.work_queue.deinit();
524 {554 {
525 var it = self.decl_table.iterator();555 var it = self.decl_table.iterator();
526 while (it.next()) |kv| {556 while (it.next()) |kv| {
...@@ -587,6 +617,8 @@ pub const Module = struct {...@@ -587,6 +617,8 @@ pub const Module = struct {
587617
588 try self.performAllTheWork();618 try self.performAllTheWork();
589619
620 // TODO unload all the source files from memory
621
590 try self.bin_file.flush();622 try self.bin_file.flush();
591 self.link_error_flags = self.bin_file.error_flags;623 self.link_error_flags = self.bin_file.error_flags;
592 }624 }
...@@ -654,7 +686,7 @@ pub const Module = struct {...@@ -654,7 +686,7 @@ pub const Module = struct {
654 const InnerError = error{ OutOfMemory, AnalysisFail };686 const InnerError = error{ OutOfMemory, AnalysisFail };
655687
656 pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void {688 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) {
658 .codegen_decl => |decl| switch (decl.analysis) {690 .codegen_decl => |decl| switch (decl.analysis) {
659 .initial_in_progress,691 .initial_in_progress,
660 .repeat_in_progress,692 .repeat_in_progress,
...@@ -671,14 +703,22 @@ pub const Module = struct {...@@ -671,14 +703,22 @@ pub const Module = struct {
671 if (decl.typed_value.most_recent.typed_value.val.cast(Value.Payload.Function)) |payload| {703 if (decl.typed_value.most_recent.typed_value.val.cast(Value.Payload.Function)) |payload| {
672 switch (payload.func.analysis) {704 switch (payload.func.analysis) {
673 .queued => self.analyzeFnBody(decl, payload.func) catch |err| switch (err) {705 .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 },
675 else => |e| return e,712 else => |e| return e,
676 },713 },
677 .in_progress => unreachable,714 .in_progress => unreachable,
678 .failure => continue,715 .sema_failure, .dependency_failure => continue,
679 .success => {},716 .success => {},
680 }717 }
681 }718 }
719 if (!decl.typed_value.most_recent.typed_value.ty.hasCodeGenBits())
720 continue;
721
682 self.bin_file.updateDecl(self, decl) catch |err| switch (err) {722 self.bin_file.updateDecl(self, decl) catch |err| switch (err) {
683 error.OutOfMemory => return error.OutOfMemory,723 error.OutOfMemory => return error.OutOfMemory,
684 else => {724 else => {
...@@ -739,7 +779,10 @@ pub const Module = struct {...@@ -739,7 +779,10 @@ pub const Module = struct {
739 return zir_module;779 return zir_module;
740 },780 },
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,
743 .loaded_success => return root_scope.contents.module,786 .loaded_success => return root_scope.contents.module,
744 }787 }
745 }788 }
...@@ -756,14 +799,11 @@ pub const Module = struct {...@@ -756,14 +799,11 @@ pub const Module = struct {
756799
757 // Here we ensure enough queue capacity to store all the decls, so that later we can use800 // Here we ensure enough queue capacity to store all the decls, so that later we can use
758 // appendAssumeCapacity.801 // appendAssumeCapacity.
759 try self.work_stack.ensureCapacity(802 try self.work_queue.ensureUnusedCapacity(src_module.decls.len);
760 self.allocator,
761 self.work_stack.items.len + src_module.decls.len,
762 );
763803
764 for (src_module.decls) |decl| {804 for (src_module.decls) |decl| {
765 if (decl.cast(text.Inst.Export)) |export_inst| {805 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);
767 }807 }
768 }808 }
769 }809 }
...@@ -825,10 +865,19 @@ pub const Module = struct {...@@ -825,10 +865,19 @@ pub const Module = struct {
825 };865 };
826 errdefer decl_scope.arena.deinit();866 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 };
828 const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State);879 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
832 arena_state.* = decl_scope.arena.state;881 arena_state.* = decl_scope.arena.state;
833882
834 new_decl.typed_value = .{883 new_decl.typed_value = .{
...@@ -839,7 +888,7 @@ pub const Module = struct {...@@ -839,7 +888,7 @@ pub const Module = struct {
839 };888 };
840 new_decl.analysis = .complete;889 new_decl.analysis = .complete;
841 // We ensureCapacity when scanning for decls.890 // We ensureCapacity when scanning for decls.
842 self.work_stack.appendAssumeCapacity(.{ .codegen_decl = new_decl });891 self.work_queue.writeItemAssumeCapacity(.{ .codegen_decl = new_decl });
843 return new_decl;892 return new_decl;
844 }893 }
845 }894 }
...@@ -1021,11 +1070,8 @@ pub const Module = struct {...@@ -1021,11 +1070,8 @@ pub const Module = struct {
1021 }1070 }
10221071
1023 fn constStr(self: *Module, scope: *Scope, src: usize, str: []const u8) !*Inst {1072 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);1073 const ty_payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
1025 array_payload.* = .{ .len = str.len };1074 ty_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) };
10291075
1030 const bytes_payload = try scope.arena().create(Value.Payload.Bytes);1076 const bytes_payload = try scope.arena().create(Value.Payload.Bytes);
1031 bytes_payload.* = .{ .data = str };1077 bytes_payload.* = .{ .data = str };
...@@ -1150,6 +1196,7 @@ pub const Module = struct {...@@ -1150,6 +1196,7 @@ pub const Module = struct {
1150 return self.constVoid(scope, old_inst.src);1196 return self.constVoid(scope, old_inst.src);
1151 },1197 },
1152 .primitive => return self.analyzeInstPrimitive(scope, old_inst.cast(text.Inst.Primitive).?),1198 .primitive => return self.analyzeInstPrimitive(scope, old_inst.cast(text.Inst.Primitive).?),
1199 .ref => return self.analyzeInstRef(scope, old_inst.cast(text.Inst.Ref).?),
1153 .fntype => return self.analyzeInstFnType(scope, old_inst.cast(text.Inst.FnType).?),1200 .fntype => return self.analyzeInstFnType(scope, old_inst.cast(text.Inst.FnType).?),
1154 .intcast => return self.analyzeInstIntCast(scope, old_inst.cast(text.Inst.IntCast).?),1201 .intcast => return self.analyzeInstIntCast(scope, old_inst.cast(text.Inst.IntCast).?),
1155 .bitcast => return self.analyzeInstBitCast(scope, old_inst.cast(text.Inst.BitCast).?),1202 .bitcast => return self.analyzeInstBitCast(scope, old_inst.cast(text.Inst.BitCast).?),
...@@ -1167,12 +1214,34 @@ pub const Module = struct {...@@ -1167,12 +1214,34 @@ pub const Module = struct {
1167 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){});1214 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){});
1168 }1215 }
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
1170 fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *text.Inst.DeclRef) InnerError!*Inst {1222 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});
1172 }1233 }
11731234
1174 fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {1235 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 });
1176 }1245 }
11771246
1178 fn analyzeInstCall(self: *Module, scope: *Scope, inst: *text.Inst.Call) InnerError!*Inst {1247 fn analyzeInstCall(self: *Module, scope: *Scope, inst: *text.Inst.Call) InnerError!*Inst {
...@@ -1929,6 +1998,7 @@ pub const Module = struct {...@@ -1929,6 +1998,7 @@ pub const Module = struct {
1929 fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: var) InnerError {1998 fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: var) InnerError {
1930 @setCold(true);1999 @setCold(true);
1931 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);2000 try self.failed_decls.ensureCapacity(self.failed_decls.size + 1);
2001 try self.failed_files.ensureCapacity(self.failed_files.size + 1);
1932 const err_msg = try ErrorMsg.create(self.allocator, src, format, args);2002 const err_msg = try ErrorMsg.create(self.allocator, src, format, args);
1933 switch (scope.tag) {2003 switch (scope.tag) {
1934 .decl => {2004 .decl => {
...@@ -1942,10 +2012,14 @@ pub const Module = struct {...@@ -1942,10 +2012,14 @@ pub const Module = struct {
1942 },2012 },
1943 .block => {2013 .block => {
1944 const block = scope.cast(Scope.Block).?;2014 const block = scope.cast(Scope.Block).?;
1945 block.func.analysis = .failure;2015 block.func.analysis = .sema_failure;
1946 self.failed_decls.putAssumeCapacityNoClobber(block.decl, err_msg);2016 self.failed_decls.putAssumeCapacityNoClobber(block.decl, err_msg);
1947 },2017 },
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 },
1949 }2023 }
1950 return error.AnalysisFail;2024 return error.AnalysisFail;
1951 }2025 }
...@@ -2044,6 +2118,7 @@ pub fn main() anyerror!void {...@@ -2044,6 +2118,7 @@ pub fn main() anyerror!void {
2044 .failed_decls = std.AutoHashMap(*Module.Decl, *ErrorMsg).init(allocator),2118 .failed_decls = std.AutoHashMap(*Module.Decl, *ErrorMsg).init(allocator),
2045 .failed_files = std.AutoHashMap(*Module.Scope.ZIRModule, *ErrorMsg).init(allocator),2119 .failed_files = std.AutoHashMap(*Module.Scope.ZIRModule, *ErrorMsg).init(allocator),
2046 .failed_exports = std.AutoHashMap(*Module.Export, *ErrorMsg).init(allocator),2120 .failed_exports = std.AutoHashMap(*Module.Export, *ErrorMsg).init(allocator),
2121 .work_queue = std.fifo.LinearFifo(Module.WorkItem, .Dynamic).init(allocator),
2047 };2122 };
2048 };2123 };
2049 defer module.deinit();2124 defer module.deinit();
src-self-hosted/ir/text.zig+25-9
...@@ -24,8 +24,7 @@ pub const Inst = struct {...@@ -24,8 +24,7 @@ pub const Inst = struct {
24 breakpoint,24 breakpoint,
25 call,25 call,
26 /// Represents a reference to a global decl by name.26 /// Represents a reference to a global decl by name.
27 /// Canonicalized ZIR will not have any of these. The27 /// The syntax `@foo` is equivalent to `declref("foo")`.
28 /// syntax `@foo` is equivalent to `declref("foo")`.
29 declref,28 declref,
30 str,29 str,
31 int,30 int,
...@@ -39,6 +38,7 @@ pub const Inst = struct {...@@ -39,6 +38,7 @@ pub const Inst = struct {
39 @"fn",38 @"fn",
40 @"export",39 @"export",
41 primitive,40 primitive,
41 ref,
42 fntype,42 fntype,
43 intcast,43 intcast,
44 bitcast,44 bitcast,
...@@ -67,6 +67,7 @@ pub const Inst = struct {...@@ -67,6 +67,7 @@ pub const Inst = struct {
67 .@"fn" => Fn,67 .@"fn" => Fn,
68 .@"export" => Export,68 .@"export" => Export,
69 .primitive => Primitive,69 .primitive => Primitive,
70 .ref => Ref,
70 .fntype => FnType,71 .fntype => FnType,
71 .intcast => IntCast,72 .intcast => IntCast,
72 .bitcast => BitCast,73 .bitcast => BitCast,
...@@ -234,6 +235,16 @@ pub const Inst = struct {...@@ -234,6 +235,16 @@ pub const Inst = struct {
234 kw_args: struct {},235 kw_args: struct {},
235 };236 };
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
237 pub const Primitive = struct {248 pub const Primitive = struct {
238 pub const base_tag = Tag.primitive;249 pub const base_tag = Tag.primitive;
239 base: Inst,250 base: Inst,
...@@ -407,7 +418,7 @@ pub const ErrorMsg = struct {...@@ -407,7 +418,7 @@ pub const ErrorMsg = struct {
407418
408pub const Module = struct {419pub const Module = struct {
409 decls: []*Inst,420 decls: []*Inst,
410 arena: std.heap.ArenaAllocator.State,421 arena: std.heap.ArenaAllocator,
411 error_msg: ?ErrorMsg = null,422 error_msg: ?ErrorMsg = null,
412423
413 pub const Body = struct {424 pub const Body = struct {
...@@ -416,7 +427,7 @@ pub const Module = struct {...@@ -416,7 +427,7 @@ pub const Module = struct {
416427
417 pub fn deinit(self: *Module, allocator: *Allocator) void {428 pub fn deinit(self: *Module, allocator: *Allocator) void {
418 allocator.free(self.decls);429 allocator.free(self.decls);
419 self.arena.promote(allocator).deinit();430 self.arena.deinit();
420 self.* = undefined;431 self.* = undefined;
421 }432 }
422433
...@@ -475,6 +486,7 @@ pub const Module = struct {...@@ -475,6 +486,7 @@ pub const Module = struct {
475 .@"return" => return self.writeInstToStreamGeneric(stream, .@"return", decl, inst_table),486 .@"return" => return self.writeInstToStreamGeneric(stream, .@"return", decl, inst_table),
476 .@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", decl, inst_table),487 .@"fn" => return self.writeInstToStreamGeneric(stream, .@"fn", decl, inst_table),
477 .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", decl, inst_table),488 .@"export" => return self.writeInstToStreamGeneric(stream, .@"export", decl, inst_table),
489 .ref => return self.writeInstToStreamGeneric(stream, .ref, decl, inst_table),
478 .primitive => return self.writeInstToStreamGeneric(stream, .primitive, decl, inst_table),490 .primitive => return self.writeInstToStreamGeneric(stream, .primitive, decl, inst_table),
479 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, decl, inst_table),491 .fntype => return self.writeInstToStreamGeneric(stream, .fntype, decl, inst_table),
480 .intcast => return self.writeInstToStreamGeneric(stream, .intcast, decl, inst_table),492 .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...@@ -591,7 +603,7 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module
591603
592 return Module{604 return Module{
593 .decls = parser.decls.toOwnedSlice(allocator),605 .decls = parser.decls.toOwnedSlice(allocator),
594 .arena = parser.arena.state,606 .arena = parser.arena,
595 .error_msg = parser.error_msg,607 .error_msg = parser.error_msg,
596 };608 };
597}609}
...@@ -630,7 +642,7 @@ const Parser = struct {...@@ -630,7 +642,7 @@ const Parser = struct {
630 skipSpace(self);642 skipSpace(self);
631 try requireEatBytes(self, "=");643 try requireEatBytes(self, "=");
632 skipSpace(self);644 skipSpace(self);
633 const inst = try parseInstruction(self, &body_context, ident[1..]);645 const inst = try parseInstruction(self, &body_context, ident);
634 const ident_index = body_context.instructions.items.len;646 const ident_index = body_context.instructions.items.len;
635 if (try body_context.name_map.put(ident, ident_index)) |_| {647 if (try body_context.name_map.put(ident, ident_index)) |_| {
636 return self.fail("redefinition of identifier '{}'", .{ident});648 return self.fail("redefinition of identifier '{}'", .{ident});
...@@ -716,7 +728,7 @@ const Parser = struct {...@@ -716,7 +728,7 @@ const Parser = struct {
716 skipSpace(self);728 skipSpace(self);
717 try requireEatBytes(self, "=");729 try requireEatBytes(self, "=");
718 skipSpace(self);730 skipSpace(self);
719 const inst = try parseInstruction(self, null, ident[1..]);731 const inst = try parseInstruction(self, null, ident);
720 const ident_index = self.decls.items.len;732 const ident_index = self.decls.items.len;
721 if (try self.global_name_map.put(ident, ident_index)) |_| {733 if (try self.global_name_map.put(ident, ident_index)) |_| {
722 return self.fail("redefinition of identifier '{}'", .{ident});734 return self.fail("redefinition of identifier '{}'", .{ident});
...@@ -987,7 +999,7 @@ pub fn emit_zir(allocator: *Allocator, old_module: ir.Module) !Module {...@@ -987,7 +999,7 @@ pub fn emit_zir(allocator: *Allocator, old_module: ir.Module) !Module {
987999
988 return Module{1000 return Module{
989 .decls = ctx.decls.toOwnedSlice(allocator),1001 .decls = ctx.decls.toOwnedSlice(allocator),
990 .arena = ctx.arena.state,1002 .arena = ctx.arena,
991 };1003 };
992}1004}
9931005
...@@ -1056,6 +1068,7 @@ const EmitZIR = struct {...@@ -1056,6 +1068,7 @@ const EmitZIR = struct {
1056 }1068 }
10571069
1058 fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Inst {1070 fn emitTypedValue(self: *EmitZIR, src: usize, typed_value: TypedValue) Allocator.Error!*Inst {
1071 const allocator = &self.arena.allocator;
1059 switch (typed_value.ty.zigTypeTag()) {1072 switch (typed_value.ty.zigTypeTag()) {
1060 .Pointer => {1073 .Pointer => {
1061 const ptr_elem_type = typed_value.ty.elemType();1074 const ptr_elem_type = typed_value.ty.elemType();
...@@ -1067,7 +1080,10 @@ const EmitZIR = struct {...@@ -1067,7 +1080,10 @@ const EmitZIR = struct {
1067 // ptr_elem_type.hasSentinel(Value.initTag(.zero)))1080 // ptr_elem_type.hasSentinel(Value.initTag(.zero)))
1068 //{1081 //{
1069 //}1082 //}
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 };
1071 return self.emitStringLiteral(src, bytes);1087 return self.emitStringLiteral(src, bytes);
1072 },1088 },
1073 else => |t| std.debug.panic("TODO implement emitTypedValue for pointer to {}", .{@tagName(t)}),1089 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(...@@ -33,9 +33,11 @@ pub fn openBinFilePath(
33 options: Options,33 options: Options,
34) !ElfFile {34) !ElfFile {
35 const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(options) });35 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;
39}41}
4042
41/// Atomically overwrites the old file, if present.43/// Atomically overwrites the old file, if present.
...@@ -89,6 +91,7 @@ pub fn openBinFile(allocator: *Allocator, file: fs.File, options: Options) !ElfF...@@ -89,6 +91,7 @@ pub fn openBinFile(allocator: *Allocator, file: fs.File, options: Options) !ElfF
89pub const ElfFile = struct {91pub const ElfFile = struct {
90 allocator: *Allocator,92 allocator: *Allocator,
91 file: fs.File,93 file: fs.File,
94 owns_file_handle: bool,
92 options: Options,95 options: Options,
93 ptr_width: enum { p32, p64 },96 ptr_width: enum { p32, p64 },
9497
...@@ -162,6 +165,8 @@ pub const ElfFile = struct {...@@ -162,6 +165,8 @@ pub const ElfFile = struct {
162 self.shstrtab.deinit(self.allocator);165 self.shstrtab.deinit(self.allocator);
163 self.symbols.deinit(self.allocator);166 self.symbols.deinit(self.allocator);
164 self.offset_table.deinit(self.allocator);167 self.offset_table.deinit(self.allocator);
168 if (self.owns_file_handle)
169 self.file.close();
165 }170 }
166171
167 // `alloc_num / alloc_den` is the factor of padding when allocation172 // `alloc_num / alloc_den` is the factor of padding when allocation
...@@ -685,7 +690,7 @@ pub const ElfFile = struct {...@@ -685,7 +690,7 @@ pub const ElfFile = struct {
685 // TODO Also detect virtual address collisions.690 // TODO Also detect virtual address collisions.
686 const text_capacity = self.allocatedSize(shdr.sh_offset);691 const text_capacity = self.allocatedSize(shdr.sh_offset);
687 // TODO instead of looping here, maintain a free list and a pointer to the end.692 // 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;
689 var last_size: u64 = 0;694 var last_size: u64 = 0;
690 for (self.symbols.items) |sym| {695 for (self.symbols.items) |sym| {
691 if (sym.st_value > last_start) {696 if (sym.st_value > last_start) {
...@@ -738,19 +743,21 @@ pub const ElfFile = struct {...@@ -738,19 +743,21 @@ pub const ElfFile = struct {
738 }743 }
739744
740 pub fn updateDecl(self: *ElfFile, module: *ir.Module, decl: *ir.Module.Decl) !void {745 pub fn updateDecl(self: *ElfFile, module: *ir.Module, decl: *ir.Module.Decl) !void {
741 var code = std.ArrayList(u8).init(self.allocator);746 var code_buffer = std.ArrayList(u8).init(self.allocator);
742 defer code.deinit();747 defer code_buffer.deinit();
743748
744 const typed_value = decl.typed_value.most_recent.typed_value;749 const typed_value = decl.typed_value.most_recent.typed_value;
745 const err_msg = try codegen.generateSymbol(self, typed_value, &code);750 const code = switch (try codegen.generateSymbol(self, decl.src, typed_value, &code_buffer)) {
746 if (err_msg) |em| {751 .ok => |x| x,
747 decl.analysis = .codegen_failure;752 .fail => |em| {
748 _ = try module.failed_decls.put(decl, em);753 decl.analysis = .codegen_failure;
749 return;754 _ = try module.failed_decls.put(decl, em);
750 }755 return;
756 },
757 };
751758
752 const file_offset = blk: {759 const file_offset = blk: {
753 const code_size = code.items.len;760 const code_size = code.len;
754 const stt_bits: u8 = switch (typed_value.ty.zigTypeTag()) {761 const stt_bits: u8 = switch (typed_value.ty.zigTypeTag()) {
755 .Fn => elf.STT_FUNC,762 .Fn => elf.STT_FUNC,
756 else => elf.STT_OBJECT,763 else => elf.STT_OBJECT,
...@@ -793,11 +800,13 @@ pub const ElfFile = struct {...@@ -793,11 +800,13 @@ pub const ElfFile = struct {
793 errdefer self.symbols.shrink(self.allocator, self.symbols.items.len - 1);800 errdefer self.symbols.shrink(self.allocator, self.symbols.items.len - 1);
794 self.offset_table.appendAssumeCapacity(new_block.vaddr);801 self.offset_table.appendAssumeCapacity(new_block.vaddr);
795 errdefer self.offset_table.shrink(self.allocator, self.offset_table.items.len - 1);802 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
799 self.symbol_count_dirty = true;804 self.symbol_count_dirty = true;
800 self.offset_table_count_dirty = true;805 self.offset_table_count_dirty = true;
806
807 try self.writeSymbol(local_sym_index);
808 try self.writeOffsetTableEntry(offset_table_index);
809
801 decl.link = .{810 decl.link = .{
802 .local_sym_index = @intCast(u32, local_sym_index),811 .local_sym_index = @intCast(u32, local_sym_index),
803 .offset_table_index = @intCast(u32, offset_table_index),812 .offset_table_index = @intCast(u32, offset_table_index),
...@@ -807,7 +816,7 @@ pub const ElfFile = struct {...@@ -807,7 +816,7 @@ pub const ElfFile = struct {
807 }816 }
808 };817 };
809818
810 try self.file.pwriteAll(code.items, file_offset);819 try self.file.pwriteAll(code, file_offset);
811820
812 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.821 // Since we updated the vaddr and the size, each corresponding export symbol also needs to be updated.
813 const decl_exports = module.decl_exports.getValue(decl) orelse &[0]*ir.Module.Export{};822 const decl_exports = module.decl_exports.getValue(decl) orelse &[0]*ir.Module.Export{};
...@@ -823,7 +832,7 @@ pub const ElfFile = struct {...@@ -823,7 +832,7 @@ pub const ElfFile = struct {
823 ) !void {832 ) !void {
824 try self.symbols.ensureCapacity(self.allocator, self.symbols.items.len + exports.len);833 try self.symbols.ensureCapacity(self.allocator, self.symbols.items.len + exports.len);
825 const typed_value = decl.typed_value.most_recent.typed_value;834 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;
827 const decl_sym = self.symbols.items[decl.link.local_sym_index];836 const decl_sym = self.symbols.items[decl.link.local_sym_index];
828837
829 for (exports) |exp| {838 for (exports) |exp| {
...@@ -1112,6 +1121,7 @@ pub fn createElfFile(allocator: *Allocator, file: fs.File, options: Options) !El...@@ -1112,6 +1121,7 @@ pub fn createElfFile(allocator: *Allocator, file: fs.File, options: Options) !El
1112 else => return error.UnsupportedELFArchitecture,1121 else => return error.UnsupportedELFArchitecture,
1113 },1122 },
1114 .shdr_table_dirty = true,1123 .shdr_table_dirty = true,
1124 .owns_file_handle = false,
1115 };1125 };
1116 errdefer self.deinit();1126 errdefer self.deinit();
11171127
...@@ -1161,6 +1171,7 @@ fn openBinFileInner(allocator: *Allocator, file: fs.File, options: Options) !Elf...@@ -1161,6 +1171,7 @@ fn openBinFileInner(allocator: *Allocator, file: fs.File, options: Options) !Elf
1161 var self: ElfFile = .{1171 var self: ElfFile = .{
1162 .allocator = allocator,1172 .allocator = allocator,
1163 .file = file,1173 .file = file,
1174 .owns_file_handle = false,
1164 .options = options,1175 .options = options,
1165 .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {1176 .ptr_width = switch (options.target.cpu.arch.ptrBitWidth()) {
1166 32 => .p32,1177 32 => .p32,
src-self-hosted/type.zig+44
...@@ -262,6 +262,50 @@ pub const Type = extern union {...@@ -262,6 +262,50 @@ pub const Type = extern union {
262 }262 }
263 }263 }
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
265 pub fn isSinglePointer(self: Type) bool {309 pub fn isSinglePointer(self: Type) bool {
266 return switch (self.tag()) {310 return switch (self.tag()) {
267 .u8,311 .u8,
src-self-hosted/value.zig+8-1
...@@ -180,10 +180,17 @@ pub const Value = extern union {...@@ -180,10 +180,17 @@ pub const Value = extern union {
180180
181 /// Asserts that the value is representable as an array of bytes.181 /// Asserts that the value is representable as an array of bytes.
182 /// Copies the value into a freshly allocated slice of memory, which is owned by the caller.182 /// 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 {
184 if (self.cast(Payload.Bytes)) |bytes| {184 if (self.cast(Payload.Bytes)) |bytes| {
185 return std.mem.dupe(allocator, u8, bytes.data);185 return std.mem.dupe(allocator, u8, bytes.data);
186 }186 }
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 }
187 unreachable;194 unreachable;
188 }195 }
189196