| author | |
| committer | |
| log | 0986dcf1cf5b67ad2b2e606622bf9b2c22e01194 |
| tree | 0f2a6536a654932e15985717d2ddd78b944ccb66 |
| parent | fb947c365e95298a4619b8db2c0d40b9d69172f2 |
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 | } |
| 192 | 192 | ||
| 193 | /// Read the next item from the fifo | 193 | /// 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; |
| 196 | 196 | ||
| 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 fifo | 282 | /// 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 | } | ||
| 285 | 287 | ||
| 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 | } |
| 344 | 347 | ||
| 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); |
| 349 | 352 | ||
| 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 | } |
| 377 | 380 | ||
| 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()); |
| 386 | 389 | ||
| ... | @@ -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()); |
| 452 | 455 | ||
| 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 | } |
| 461 | 464 |
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"); |
| 9 | const Target = std.Target; | 9 | const Target = std.Target; |
| 10 | const Allocator = mem.Allocator; | 10 | const Allocator = mem.Allocator; |
| 11 | 11 | ||
| 12 | pub fn generateSymbol(bin_file: *link.ElfFile, typed_value: TypedValue, code: *std.ArrayList(u8)) !?*ir.ErrorMsg { | 12 | pub 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 | |||
| 18 | pub 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(); |
| 25 | 36 | ||
| 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 | } |
| 36 | 44 | ||
| 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 | } |
| 42 | 105 | ||
| ... | @@ -390,14 +453,18 @@ const Function = struct { | ... | @@ -390,14 +453,18 @@ const Function = struct { |
| 390 | } | 453 | } |
| 391 | 454 | ||
| 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 literal | 462 | // 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) catch | 468 | 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", .{}); |
| 403 | 470 |
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{}, |
| 193 | 193 | ||
| 194 | work_stack: ArrayListUnmanaged(WorkItem) = ArrayListUnmanaged(WorkItem){}, | 194 | work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic), |
| 195 | 195 | ||
| 196 | /// We optimize memory usage for a compilation with no compile errors by storing the | 196 | /// 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 | } |
| 335 | 335 | ||
| 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_decls | 370 | /// 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 | }, |
| 365 | 377 | ||
| ... | @@ -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 | } |
| 396 | 408 | ||
| ... | @@ -414,6 +426,18 @@ pub const Module = struct { | ... | @@ -414,6 +426,18 @@ pub const Module = struct { |
| 414 | } | 426 | } |
| 415 | } | 427 | } |
| 416 | 428 | ||
| 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 | }, |
| 443 | 468 | ||
| ... | @@ -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 | }; |
| 460 | 490 | ||
| 461 | /// This is a temporary structure, references to it are valid only | 491 | /// 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 { |
| 520 | 550 | ||
| 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 { |
| 587 | 617 | ||
| 588 | try self.performAllTheWork(); | 618 | try self.performAllTheWork(); |
| 589 | 619 | ||
| 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 }; |
| 655 | 687 | ||
| 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 | }, |
| 741 | 781 | ||
| 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 { |
| 756 | 799 | ||
| 757 | // Here we ensure enough queue capacity to store all the decls, so that later we can use | 800 | // 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 | ); | ||
| 763 | 803 | ||
| 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(); |
| 827 | 867 | ||
| 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); |
| 829 | 880 | ||
| 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; |
| 833 | 882 | ||
| 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 | } |
| 1022 | 1071 | ||
| 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) }; | ||
| 1029 | 1075 | ||
| 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 | } |
| 1169 | 1216 | ||
| 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 | } |
| 1173 | 1234 | ||
| 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 | } |
| 1177 | 1246 | ||
| 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. The | 27 | /// 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 | }; |
| 236 | 237 | ||
| 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 { |
| 407 | 418 | ||
| 408 | pub const Module = struct { | 419 | pub 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, |
| 412 | 423 | ||
| 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 { |
| 416 | 427 | ||
| 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 | } |
| 422 | 433 | ||
| ... | @@ -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 |
| 591 | 603 | ||
| 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 { |
| 987 | 999 | ||
| 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 | } |
| 993 | 1005 | ||
| ... | @@ -1056,6 +1068,7 @@ const EmitZIR = struct { | ... | @@ -1056,6 +1068,7 @@ const EmitZIR = struct { |
| 1056 | } | 1068 | } |
| 1057 | 1069 | ||
| 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(); |
| 37 | 37 | ||
| 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 | } |
| 40 | 42 | ||
| 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 |
| 89 | pub const ElfFile = struct { | 91 | pub 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 }, |
| 94 | 97 | ||
| ... | @@ -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 | } |
| 166 | 171 | ||
| 167 | // `alloc_num / alloc_den` is the factor of padding when allocation | 172 | // `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 | } |
| 739 | 744 | ||
| 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(); |
| 743 | 748 | ||
| 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 | }; | ||
| 751 | 758 | ||
| 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); | ||
| 798 | 803 | ||
| 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 | }; |
| 809 | 818 | ||
| 810 | try self.file.pwriteAll(code.items, file_offset); | 819 | try self.file.pwriteAll(code, file_offset); |
| 811 | 820 | ||
| 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]; |
| 828 | 837 | ||
| 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(); |
| 1117 | 1127 | ||
| ... | @@ -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 | } |
| 264 | 264 | ||
| 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 { |
| 180 | 180 | ||
| 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 | } |
| 189 | 196 |