authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-10 02:05:54-04:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-05-10 02:05:54-04:00
loga32d3a85d21d614e5960b9eadcd85374954b910f
tree8712bfc619205eaf23201215a4a19f7c0c108cfa
parentae080b5c217fbcfd350a5d52b8b4626a95540ab3

rework self-hosted compiler for incremental builds

* introduce std.ArrayListUnmanaged for when you have the allocator stored elsewhere * move std.heap.ArenaAllocator implementation to its own file. extract the main state into std.heap.ArenaAllocator.State, which can be stored as an alternative to storing the entire ArenaAllocator, saving 24 bytes per ArenaAllocator on 64 bit targets. * std.LinkedList.Node pointer field now defaults to being null initialized. * Rework self-hosted compiler Package API * Delete almost all the bitrotted self-hosted compiler code. The only bit rotted code left is in main.zig and compilation.zig * Add call instruction to ZIR * self-hosted compiler ir API and link API are reworked to support a long-running compiler that incrementally updates declarations * Introduce the concept of scopes to ZIR semantic analysis * ZIR text format supports referencing named decls that are declared later in the file * Figure out how memory management works for the long-running compiler and incremental compilation. The main roots are top level declarations. There is a table of decls. The key is a cryptographic hash of the fully qualified decl name. Each decl has an arena allocator where all of the memory related to that decl is stored. Each code block has its own arena allocator for the lifetime of the block. Values that want to survive when going out of scope in a block must get copied into the outer block. Finally, values must get copied into the Decl arena to be long-lived. * Delete the unused MemoryCell struct. Instead, comptime pointers are based on references to Decl structs. * Figure out how caching works. Each Decl will store a set of other Decls which must be recompiled when it changes. This branch is still work-in-progress; this commit breaks the build.

21 files changed, 1836 insertions(+), 1504 deletions(-)

lib/std/array_list.zig+236-7
...@@ -8,13 +8,13 @@ const Allocator = mem.Allocator;...@@ -8,13 +8,13 @@ const Allocator = mem.Allocator;
8/// A contiguous, growable list of items in memory.8/// A contiguous, growable list of items in memory.
9/// This is a wrapper around an array of T values. Initialize with `init`.9/// This is a wrapper around an array of T values. Initialize with `init`.
10pub fn ArrayList(comptime T: type) type {10pub fn ArrayList(comptime T: type) type {
11 return AlignedArrayList(T, null);11 return ArrayListAligned(T, null);
12}12}
1313
14pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {14pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
15 if (alignment) |a| {15 if (alignment) |a| {
16 if (a == @alignOf(T)) {16 if (a == @alignOf(T)) {
17 return AlignedArrayList(T, null);17 return ArrayListAligned(T, null);
18 }18 }
19 }19 }
20 return struct {20 return struct {
...@@ -76,6 +76,10 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {...@@ -76,6 +76,10 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
76 };76 };
77 }77 }
7878
79 pub fn toUnmanaged(self: Self) ArrayListAlignedUnmanaged(T, alignment) {
80 return .{ .items = self.items, .capacity = self.capacity };
81 }
82
79 /// The caller owns the returned memory. ArrayList becomes empty.83 /// The caller owns the returned memory. ArrayList becomes empty.
80 pub fn toOwnedSlice(self: *Self) Slice {84 pub fn toOwnedSlice(self: *Self) Slice {
81 const allocator = self.allocator;85 const allocator = self.allocator;
...@@ -84,8 +88,8 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {...@@ -84,8 +88,8 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
84 return result;88 return result;
85 }89 }
8690
87 /// Insert `item` at index `n`. Moves `list[n .. list.len]`91 /// Insert `item` at index `n` by moving `list[n .. list.len]` to make room.
88 /// to make room.92 /// This operation is O(N).
89 pub fn insert(self: *Self, n: usize, item: T) !void {93 pub fn insert(self: *Self, n: usize, item: T) !void {
90 try self.ensureCapacity(self.items.len + 1);94 try self.ensureCapacity(self.items.len + 1);
91 self.items.len += 1;95 self.items.len += 1;
...@@ -94,8 +98,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {...@@ -94,8 +98,7 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
94 self.items[n] = item;98 self.items[n] = item;
95 }99 }
96100
97 /// Insert slice `items` at index `i`. Moves101 /// Insert slice `items` at index `i` by moving `list[i .. list.len]` to make room.
98 /// `list[i .. list.len]` to make room.
99 /// This operation is O(N).102 /// This operation is O(N).
100 pub fn insertSlice(self: *Self, i: usize, items: SliceConst) !void {103 pub fn insertSlice(self: *Self, i: usize, items: SliceConst) !void {
101 try self.ensureCapacity(self.items.len + items.len);104 try self.ensureCapacity(self.items.len + items.len);
...@@ -259,6 +262,232 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {...@@ -259,6 +262,232 @@ pub fn AlignedArrayList(comptime T: type, comptime alignment: ?u29) type {
259 };262 };
260}263}
261264
265/// Bring-your-own allocator with every function call.
266/// Initialize directly and deinitialize with `deinit` or use `toOwnedSlice`.
267pub fn init() Self {
268 return .{
269 .items = &[_]T{},
270 .capacity = 0,
271 };
272}
273
274pub fn ArrayListUnmanaged(comptime T: type) type {
275 return ArrayListAlignedUnmanaged(T, null);
276}
277
278pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) type {
279 if (alignment) |a| {
280 if (a == @alignOf(T)) {
281 return ArrayListAlignedUnmanaged(T, null);
282 }
283 }
284 return struct {
285 const Self = @This();
286
287 /// Content of the ArrayList.
288 items: Slice = &[_]T{},
289 capacity: usize = 0,
290
291 pub const Slice = if (alignment) |a| ([]align(a) T) else []T;
292 pub const SliceConst = if (alignment) |a| ([]align(a) const T) else []const T;
293
294 /// Initialize with capacity to hold at least num elements.
295 /// Deinitialize with `deinit` or use `toOwnedSlice`.
296 pub fn initCapacity(allocator: *Allocator, num: usize) !Self {
297 var self = Self.init(allocator);
298 try self.ensureCapacity(allocator, num);
299 return self;
300 }
301
302 /// Release all allocated memory.
303 pub fn deinit(self: *Self, allocator: *Allocator) void {
304 allocator.free(self.allocatedSlice());
305 self.* = undefined;
306 }
307
308 pub fn toManaged(self: *Self, allocator: *Allocator) ArrayListAligned(T, alignment) {
309 return .{ .items = self.items, .capacity = self.capacity, .allocator = allocator };
310 }
311
312 /// The caller owns the returned memory. ArrayList becomes empty.
313 pub fn toOwnedSlice(self: *Self, allocator: *Allocator) Slice {
314 const result = allocator.shrink(self.allocatedSlice(), self.items.len);
315 self.* = init(allocator);
316 return result;
317 }
318
319 /// Insert `item` at index `n`. Moves `list[n .. list.len]`
320 /// to make room.
321 pub fn insert(self: *Self, allocator: *Allocator, n: usize, item: T) !void {
322 try self.ensureCapacity(allocator, self.items.len + 1);
323 self.items.len += 1;
324
325 mem.copyBackwards(T, self.items[n + 1 .. self.items.len], self.items[n .. self.items.len - 1]);
326 self.items[n] = item;
327 }
328
329 /// Insert slice `items` at index `i`. Moves
330 /// `list[i .. list.len]` to make room.
331 /// This operation is O(N).
332 pub fn insertSlice(self: *Self, allocator: *Allocator, i: usize, items: SliceConst) !void {
333 try self.ensureCapacity(allocator, self.items.len + items.len);
334 self.items.len += items.len;
335
336 mem.copyBackwards(T, self.items[i + items.len .. self.items.len], self.items[i .. self.items.len - items.len]);
337 mem.copy(T, self.items[i .. i + items.len], items);
338 }
339
340 /// Extend the list by 1 element. Allocates more memory as necessary.
341 pub fn append(self: *Self, allocator: *Allocator, item: T) !void {
342 const new_item_ptr = try self.addOne(allocator);
343 new_item_ptr.* = item;
344 }
345
346 /// Extend the list by 1 element, but asserting `self.capacity`
347 /// is sufficient to hold an additional item.
348 pub fn appendAssumeCapacity(self: *Self, item: T) void {
349 const new_item_ptr = self.addOneAssumeCapacity();
350 new_item_ptr.* = item;
351 }
352
353 /// Remove the element at index `i` from the list and return its value.
354 /// Asserts the array has at least one item.
355 /// This operation is O(N).
356 pub fn orderedRemove(self: *Self, i: usize) T {
357 const newlen = self.items.len - 1;
358 if (newlen == i) return self.pop();
359
360 const old_item = self.items[i];
361 for (self.items[i..newlen]) |*b, j| b.* = self.items[i + 1 + j];
362 self.items[newlen] = undefined;
363 self.items.len = newlen;
364 return old_item;
365 }
366
367 /// Removes the element at the specified index and returns it.
368 /// The empty slot is filled from the end of the list.
369 /// This operation is O(1).
370 pub fn swapRemove(self: *Self, i: usize) T {
371 if (self.items.len - 1 == i) return self.pop();
372
373 const old_item = self.items[i];
374 self.items[i] = self.pop();
375 return old_item;
376 }
377
378 /// Append the slice of items to the list. Allocates more
379 /// memory as necessary.
380 pub fn appendSlice(self: *Self, allocator: *Allocator, items: SliceConst) !void {
381 const oldlen = self.items.len;
382 const newlen = self.items.len + items.len;
383
384 try self.ensureCapacity(allocator, newlen);
385 self.items.len = newlen;
386 mem.copy(T, self.items[oldlen..], items);
387 }
388
389 /// Same as `append` except it returns the number of bytes written, which is always the same
390 /// as `m.len`. The purpose of this function existing is to match `std.io.OutStream` API.
391 /// This function may be called only when `T` is `u8`.
392 fn appendWrite(self: *Self, allocator: *Allocator, m: []const u8) !usize {
393 try self.appendSlice(allocator, m);
394 return m.len;
395 }
396
397 /// Append a value to the list `n` times.
398 /// Allocates more memory as necessary.
399 pub fn appendNTimes(self: *Self, allocator: *Allocator, value: T, n: usize) !void {
400 const old_len = self.items.len;
401 try self.resize(self.items.len + n);
402 mem.set(T, self.items[old_len..self.items.len], value);
403 }
404
405 /// Adjust the list's length to `new_len`.
406 /// Does not initialize added items if any.
407 pub fn resize(self: *Self, allocator: *Allocator, new_len: usize) !void {
408 try self.ensureCapacity(allocator, new_len);
409 self.items.len = new_len;
410 }
411
412 /// Reduce allocated capacity to `new_len`.
413 /// Invalidates element pointers.
414 pub fn shrink(self: *Self, allocator: *Allocator, new_len: usize) void {
415 assert(new_len <= self.items.len);
416
417 self.items = allocator.realloc(self.allocatedSlice(), new_len) catch |e| switch (e) {
418 error.OutOfMemory => { // no problem, capacity is still correct then.
419 self.items.len = new_len;
420 return;
421 },
422 };
423 self.capacity = new_len;
424 }
425
426 pub fn ensureCapacity(self: *Self, allocator: *Allocator, new_capacity: usize) !void {
427 var better_capacity = self.capacity;
428 if (better_capacity >= new_capacity) return;
429
430 while (true) {
431 better_capacity += better_capacity / 2 + 8;
432 if (better_capacity >= new_capacity) break;
433 }
434
435 const new_memory = try allocator.realloc(self.allocatedSlice(), better_capacity);
436 self.items.ptr = new_memory.ptr;
437 self.capacity = new_memory.len;
438 }
439
440 /// Increases the array's length to match the full capacity that is already allocated.
441 /// The new elements have `undefined` values.
442 /// This operation does not invalidate any element pointers.
443 pub fn expandToCapacity(self: *Self) void {
444 self.items.len = self.capacity;
445 }
446
447 /// Increase length by 1, returning pointer to the new item.
448 /// The returned pointer becomes invalid when the list is resized.
449 pub fn addOne(self: *Self, allocator: *Allocator) !*T {
450 const newlen = self.items.len + 1;
451 try self.ensureCapacity(allocator, newlen);
452 return self.addOneAssumeCapacity();
453 }
454
455 /// Increase length by 1, returning pointer to the new item.
456 /// Asserts that there is already space for the new item without allocating more.
457 /// The returned pointer becomes invalid when the list is resized.
458 /// This operation does not invalidate any element pointers.
459 pub fn addOneAssumeCapacity(self: *Self) *T {
460 assert(self.items.len < self.capacity);
461
462 self.items.len += 1;
463 return &self.items[self.items.len - 1];
464 }
465
466 /// Remove and return the last element from the list.
467 /// Asserts the list has at least one item.
468 /// This operation does not invalidate any element pointers.
469 pub fn pop(self: *Self) T {
470 const val = self.items[self.items.len - 1];
471 self.items.len -= 1;
472 return val;
473 }
474
475 /// Remove and return the last element from the list.
476 /// If the list is empty, returns `null`.
477 /// This operation does not invalidate any element pointers.
478 pub fn popOrNull(self: *Self) ?T {
479 if (self.items.len == 0) return null;
480 return self.pop();
481 }
482
483 /// For a nicer API, `items.len` is the length, not the capacity.
484 /// This requires "unsafe" slicing.
485 fn allocatedSlice(self: Self) Slice {
486 return self.items.ptr[0..self.capacity];
487 }
488 };
489}
490
262test "std.ArrayList.init" {491test "std.ArrayList.init" {
263 var list = ArrayList(i32).init(testing.allocator);492 var list = ArrayList(i32).init(testing.allocator);
264 defer list.deinit();493 defer list.deinit();
lib/std/heap.zig+1-89
...@@ -11,6 +11,7 @@ const maxInt = std.math.maxInt;...@@ -11,6 +11,7 @@ const maxInt = std.math.maxInt;
1111
12pub const LoggingAllocator = @import("heap/logging_allocator.zig").LoggingAllocator;12pub const LoggingAllocator = @import("heap/logging_allocator.zig").LoggingAllocator;
13pub const loggingAllocator = @import("heap/logging_allocator.zig").loggingAllocator;13pub const loggingAllocator = @import("heap/logging_allocator.zig").loggingAllocator;
14pub const ArenaAllocator = @import("heap/arena_allocator.zig").ArenaAllocator;
1415
15const Allocator = mem.Allocator;16const Allocator = mem.Allocator;
1617
...@@ -510,95 +511,6 @@ pub const HeapAllocator = switch (builtin.os.tag) {...@@ -510,95 +511,6 @@ pub const HeapAllocator = switch (builtin.os.tag) {
510 else => @compileError("Unsupported OS"),511 else => @compileError("Unsupported OS"),
511};512};
512513
513/// This allocator takes an existing allocator, wraps it, and provides an interface
514/// where you can allocate without freeing, and then free it all together.
515pub const ArenaAllocator = struct {
516 allocator: Allocator,
517
518 child_allocator: *Allocator,
519 buffer_list: std.SinglyLinkedList([]u8),
520 end_index: usize,
521
522 const BufNode = std.SinglyLinkedList([]u8).Node;
523
524 pub fn init(child_allocator: *Allocator) ArenaAllocator {
525 return ArenaAllocator{
526 .allocator = Allocator{
527 .reallocFn = realloc,
528 .shrinkFn = shrink,
529 },
530 .child_allocator = child_allocator,
531 .buffer_list = std.SinglyLinkedList([]u8).init(),
532 .end_index = 0,
533 };
534 }
535
536 pub fn deinit(self: ArenaAllocator) void {
537 var it = self.buffer_list.first;
538 while (it) |node| {
539 // this has to occur before the free because the free frees node
540 const next_it = node.next;
541 self.child_allocator.free(node.data);
542 it = next_it;
543 }
544 }
545
546 fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) !*BufNode {
547 const actual_min_size = minimum_size + @sizeOf(BufNode);
548 var len = prev_len;
549 while (true) {
550 len += len / 2;
551 len += mem.page_size - @rem(len, mem.page_size);
552 if (len >= actual_min_size) break;
553 }
554 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
555 const buf_node_slice = mem.bytesAsSlice(BufNode, buf[0..@sizeOf(BufNode)]);
556 const buf_node = &buf_node_slice[0];
557 buf_node.* = BufNode{
558 .data = buf,
559 .next = null,
560 };
561 self.buffer_list.prepend(buf_node);
562 self.end_index = 0;
563 return buf_node;
564 }
565
566 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
567 const self = @fieldParentPtr(ArenaAllocator, "allocator", allocator);
568
569 var cur_node = if (self.buffer_list.first) |first_node| first_node else try self.createNode(0, n + alignment);
570 while (true) {
571 const cur_buf = cur_node.data[@sizeOf(BufNode)..];
572 const addr = @ptrToInt(cur_buf.ptr) + self.end_index;
573 const adjusted_addr = mem.alignForward(addr, alignment);
574 const adjusted_index = self.end_index + (adjusted_addr - addr);
575 const new_end_index = adjusted_index + n;
576 if (new_end_index > cur_buf.len) {
577 cur_node = try self.createNode(cur_buf.len, n + alignment);
578 continue;
579 }
580 const result = cur_buf[adjusted_index..new_end_index];
581 self.end_index = new_end_index;
582 return result;
583 }
584 }
585
586 fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
587 if (new_size <= old_mem.len and new_align <= new_size) {
588 // We can't do anything with the memory, so tell the client to keep it.
589 return error.OutOfMemory;
590 } else {
591 const result = try alloc(allocator, new_size, new_align);
592 @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len));
593 return result;
594 }
595 }
596
597 fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
598 return old_mem[0..new_size];
599 }
600};
601
602pub const FixedBufferAllocator = struct {514pub const FixedBufferAllocator = struct {
603 allocator: Allocator,515 allocator: Allocator,
604 end_index: usize,516 end_index: usize,
lib/std/heap/arena_allocator.zig created+102
...@@ -0,0 +1,102 @@
1const std = @import("../std.zig");
2const assert = std.debug.assert;
3const mem = std.mem;
4const Allocator = std.mem.Allocator;
5
6/// This allocator takes an existing allocator, wraps it, and provides an interface
7/// where you can allocate without freeing, and then free it all together.
8pub const ArenaAllocator = struct {
9 allocator: Allocator,
10
11 child_allocator: *Allocator,
12 state: State,
13
14 /// Inner state of ArenaAllocator. Can be stored rather than the entire ArenaAllocator
15 /// as a memory-saving optimization.
16 pub const State = struct {
17 buffer_list: std.SinglyLinkedList([]u8) = @as(std.SinglyLinkedList([]u8), .{}),
18 end_index: usize = 0,
19
20 pub fn promote(self: State, child_allocator: *Allocator) ArenaAllocator {
21 return .{
22 .allocator = Allocator{
23 .reallocFn = realloc,
24 .shrinkFn = shrink,
25 },
26 .child_allocator = child_allocator,
27 .state = self,
28 };
29 }
30 };
31
32 const BufNode = std.SinglyLinkedList([]u8).Node;
33
34 pub fn init(child_allocator: *Allocator) ArenaAllocator {
35 return (State{}).promote(child_allocator);
36 }
37
38 pub fn deinit(self: ArenaAllocator) void {
39 var it = self.state.buffer_list.first;
40 while (it) |node| {
41 // this has to occur before the free because the free frees node
42 const next_it = node.next;
43 self.child_allocator.free(node.data);
44 it = next_it;
45 }
46 }
47
48 fn createNode(self: *ArenaAllocator, prev_len: usize, minimum_size: usize) !*BufNode {
49 const actual_min_size = minimum_size + @sizeOf(BufNode);
50 var len = prev_len;
51 while (true) {
52 len += len / 2;
53 len += mem.page_size - @rem(len, mem.page_size);
54 if (len >= actual_min_size) break;
55 }
56 const buf = try self.child_allocator.alignedAlloc(u8, @alignOf(BufNode), len);
57 const buf_node_slice = mem.bytesAsSlice(BufNode, buf[0..@sizeOf(BufNode)]);
58 const buf_node = &buf_node_slice[0];
59 buf_node.* = BufNode{
60 .data = buf,
61 .next = null,
62 };
63 self.state.buffer_list.prepend(buf_node);
64 self.state.end_index = 0;
65 return buf_node;
66 }
67
68 fn alloc(allocator: *Allocator, n: usize, alignment: u29) ![]u8 {
69 const self = @fieldParentPtr(ArenaAllocator, "allocator", allocator);
70
71 var cur_node = if (self.state.buffer_list.first) |first_node| first_node else try self.createNode(0, n + alignment);
72 while (true) {
73 const cur_buf = cur_node.data[@sizeOf(BufNode)..];
74 const addr = @ptrToInt(cur_buf.ptr) + self.state.end_index;
75 const adjusted_addr = mem.alignForward(addr, alignment);
76 const adjusted_index = self.state.end_index + (adjusted_addr - addr);
77 const new_end_index = adjusted_index + n;
78 if (new_end_index > cur_buf.len) {
79 cur_node = try self.createNode(cur_buf.len, n + alignment);
80 continue;
81 }
82 const result = cur_buf[adjusted_index..new_end_index];
83 self.state.end_index = new_end_index;
84 return result;
85 }
86 }
87
88 fn realloc(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) ![]u8 {
89 if (new_size <= old_mem.len and new_align <= new_size) {
90 // We can't do anything with the memory, so tell the client to keep it.
91 return error.OutOfMemory;
92 } else {
93 const result = try alloc(allocator, new_size, new_align);
94 @memcpy(result.ptr, old_mem.ptr, std.math.min(old_mem.len, result.len));
95 return result;
96 }
97 }
98
99 fn shrink(allocator: *Allocator, old_mem: []u8, old_align: u29, new_size: usize, new_align: u29) []u8 {
100 return old_mem[0..new_size];
101 }
102};
lib/std/linked_list.zig+1-1
...@@ -49,7 +49,7 @@ pub fn SinglyLinkedList(comptime T: type) type {...@@ -49,7 +49,7 @@ pub fn SinglyLinkedList(comptime T: type) type {
49 }49 }
50 };50 };
5151
52 first: ?*Node,52 first: ?*Node = null,
5353
54 /// Initialize a linked list.54 /// Initialize a linked list.
55 ///55 ///
lib/std/std.zig+3-1
...@@ -1,6 +1,8 @@...@@ -1,6 +1,8 @@
1pub const AlignedArrayList = @import("array_list.zig").AlignedArrayList;
2pub const ArrayList = @import("array_list.zig").ArrayList;1pub const ArrayList = @import("array_list.zig").ArrayList;
2pub const ArrayListAligned = @import("array_list.zig").ArrayListAligned;
3pub const ArrayListAlignedUnmanaged = @import("array_list.zig").ArrayListAlignedUnmanaged;
3pub const ArrayListSentineled = @import("array_list_sentineled.zig").ArrayListSentineled;4pub const ArrayListSentineled = @import("array_list_sentineled.zig").ArrayListSentineled;
5pub const ArrayListUnmanaged = @import("array_list.zig").ArrayListUnmanaged;
4pub const AutoHashMap = @import("hash_map.zig").AutoHashMap;6pub const AutoHashMap = @import("hash_map.zig").AutoHashMap;
5pub const BloomFilter = @import("bloom_filter.zig").BloomFilter;7pub const BloomFilter = @import("bloom_filter.zig").BloomFilter;
6pub const BufMap = @import("buf_map.zig").BufMap;8pub const BufMap = @import("buf_map.zig").BufMap;
src-self-hosted/Package.zig created+52
...@@ -0,0 +1,52 @@
1pub const Table = std.StringHashMap(*Package);
2
3root_src_dir: std.fs.Dir,
4/// Relative to `root_src_dir`.
5root_src_path: []const u8,
6table: Table,
7
8/// No references to `root_src_dir` and `root_src_path` are kept.
9pub fn create(
10 allocator: *mem.Allocator,
11 base_dir: std.fs.Dir,
12 /// Relative to `base_dir`.
13 root_src_dir: []const u8,
14 /// Relative to `root_src_dir`.
15 root_src_path: []const u8,
16) !*Package {
17 const ptr = try allocator.create(Package);
18 errdefer allocator.destroy(ptr);
19 const root_src_path_dupe = try mem.dupe(allocator, u8, root_src_path);
20 errdefer allocator.free(root_src_path_dupe);
21 ptr.* = .{
22 .root_src_dir = try base_dir.openDir(root_src_dir, .{}),
23 .root_src_path = root_src_path_dupe,
24 .table = Table.init(allocator),
25 };
26 return ptr;
27}
28
29pub fn destroy(self: *Package) void {
30 const allocator = self.table.allocator;
31 self.root_src_dir.close();
32 allocator.free(self.root_src_path);
33 {
34 var it = self.table.iterator();
35 while (it.next()) |kv| {
36 allocator.free(kv.key);
37 }
38 }
39 self.table.deinit();
40 allocator.destroy(self);
41}
42
43pub fn add(self: *Package, name: []const u8, package: *Package) !void {
44 const name_dupe = try mem.dupe(self.table.allocator, u8, name);
45 errdefer self.table.allocator.deinit(name_dupe);
46 const entry = try self.table.put(name_dupe, package);
47 assert(entry == null);
48}
49
50const std = @import("std");
51const mem = std.mem;
52const assert = std.debug.assert;
src-self-hosted/c.zig deleted-7
...@@ -1,7 +0,0 @@
1pub usingnamespace @cImport({
2 @cDefine("__STDC_CONSTANT_MACROS", "");
3 @cDefine("__STDC_LIMIT_MACROS", "");
4 @cInclude("inttypes.h");
5 @cInclude("config.h");
6 @cInclude("zig_llvm.h");
7});
src-self-hosted/codegen.zig+25-33
...@@ -6,38 +6,24 @@ const Type = @import("type.zig").Type;...@@ -6,38 +6,24 @@ const Type = @import("type.zig").Type;
6const Value = @import("value.zig").Value;6const Value = @import("value.zig").Value;
7const Target = std.Target;7const Target = std.Target;
88
9pub const ErrorMsg = struct {9pub fn generateSymbol(
10 byte_offset: usize,10 typed_value: ir.TypedValue,
11 msg: []const u8,11 module: ir.Module,
12};12 code: *std.ArrayList(u8),
1313 errors: *std.ArrayList(ir.ErrorMsg),
14pub const Symbol = struct {14) !void {
15 errors: []ErrorMsg,
16
17 pub fn deinit(self: *Symbol, allocator: *mem.Allocator) void {
18 for (self.errors) |err| {
19 allocator.free(err.msg);
20 }
21 allocator.free(self.errors);
22 self.* = undefined;
23 }
24};
25
26pub fn generateSymbol(typed_value: ir.TypedValue, module: ir.Module, code: *std.ArrayList(u8)) !Symbol {
27 switch (typed_value.ty.zigTypeTag()) {15 switch (typed_value.ty.zigTypeTag()) {
28 .Fn => {16 .Fn => {
29 const index = typed_value.val.cast(Value.Payload.Function).?.index;17 const module_fn = typed_value.val.cast(Value.Payload.Function).?.func;
30 const module_fn = module.fns[index];
3118
32 var function = Function{19 var function = Function{
33 .module = &module,20 .module = &module,
34 .mod_fn = &module_fn,21 .mod_fn = module_fn,
35 .code = code,22 .code = code,
36 .inst_table = std.AutoHashMap(*ir.Inst, Function.MCValue).init(code.allocator),23 .inst_table = std.AutoHashMap(*ir.Inst, Function.MCValue).init(code.allocator),
37 .errors = std.ArrayList(ErrorMsg).init(code.allocator),24 .errors = errors,
38 };25 };
39 defer function.inst_table.deinit();26 defer function.inst_table.deinit();
40 defer function.errors.deinit();
4127
42 for (module_fn.body.instructions) |inst| {28 for (module_fn.body.instructions) |inst| {
43 const new_inst = function.genFuncInst(inst) catch |err| switch (err) {29 const new_inst = function.genFuncInst(inst) catch |err| switch (err) {
...@@ -52,7 +38,7 @@ pub fn generateSymbol(typed_value: ir.TypedValue, module: ir.Module, code: *std....@@ -52,7 +38,7 @@ pub fn generateSymbol(typed_value: ir.TypedValue, module: ir.Module, code: *std.
5238
53 return Symbol{ .errors = function.errors.toOwnedSlice() };39 return Symbol{ .errors = function.errors.toOwnedSlice() };
54 },40 },
55 else => @panic("TODO implement generateSymbol for non-function types"),41 else => @panic("TODO implement generateSymbol for non-function decls"),
56 }42 }
57}43}
5844
...@@ -61,7 +47,7 @@ const Function = struct {...@@ -61,7 +47,7 @@ const Function = struct {
61 mod_fn: *const ir.Module.Fn,47 mod_fn: *const ir.Module.Fn,
62 code: *std.ArrayList(u8),48 code: *std.ArrayList(u8),
63 inst_table: std.AutoHashMap(*ir.Inst, MCValue),49 inst_table: std.AutoHashMap(*ir.Inst, MCValue),
64 errors: std.ArrayList(ErrorMsg),50 errors: *std.ArrayList(ir.ErrorMsg),
6551
66 const MCValue = union(enum) {52 const MCValue = union(enum) {
67 none,53 none,
...@@ -78,6 +64,7 @@ const Function = struct {...@@ -78,6 +64,7 @@ const Function = struct {
78 fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {64 fn genFuncInst(self: *Function, inst: *ir.Inst) !MCValue {
79 switch (inst.tag) {65 switch (inst.tag) {
80 .breakpoint => return self.genBreakpoint(inst.src),66 .breakpoint => return self.genBreakpoint(inst.src),
67 .call => return self.genCall(inst.cast(ir.Inst.Call).?),
81 .unreach => return MCValue{ .unreach = {} },68 .unreach => return MCValue{ .unreach = {} },
82 .constant => unreachable, // excluded from function bodies69 .constant => unreachable, // excluded from function bodies
83 .assembly => return self.genAsm(inst.cast(ir.Inst.Assembly).?),70 .assembly => return self.genAsm(inst.cast(ir.Inst.Assembly).?),
...@@ -101,6 +88,13 @@ const Function = struct {...@@ -101,6 +88,13 @@ const Function = struct {
101 return .unreach;88 return .unreach;
102 }89 }
10390
91 fn genCall(self: *Function, inst: *ir.Inst.Call) !MCValue {
92 switch (self.module.target.cpu.arch) {
93 else => return self.fail(inst.base.src, "TODO implement call for {}", .{self.module.target.cpu.arch}),
94 }
95 return .unreach;
96 }
97
104 fn genRet(self: *Function, inst: *ir.Inst.Ret) !MCValue {98 fn genRet(self: *Function, inst: *ir.Inst.Ret) !MCValue {
105 switch (self.module.target.cpu.arch) {99 switch (self.module.target.cpu.arch) {
106 .i386, .x86_64 => {100 .i386, .x86_64 => {
...@@ -140,6 +134,7 @@ const Function = struct {...@@ -140,6 +134,7 @@ const Function = struct {
140 fn genRelativeFwdJump(self: *Function, src: usize, amount: u32) !void {134 fn genRelativeFwdJump(self: *Function, src: usize, amount: u32) !void {
141 switch (self.module.target.cpu.arch) {135 switch (self.module.target.cpu.arch) {
142 .i386, .x86_64 => {136 .i386, .x86_64 => {
137 // TODO x86 treats the operands as signed
143 if (amount <= std.math.maxInt(u8)) {138 if (amount <= std.math.maxInt(u8)) {
144 try self.code.resize(self.code.items.len + 2);139 try self.code.resize(self.code.items.len + 2);
145 self.code.items[self.code.items.len - 2] = 0xeb;140 self.code.items[self.code.items.len - 2] = 0xeb;
...@@ -433,14 +428,11 @@ const Function = struct {...@@ -433,14 +428,11 @@ const Function = struct {
433428
434 fn fail(self: *Function, src: usize, comptime format: []const u8, args: var) error{ CodegenFail, OutOfMemory } {429 fn fail(self: *Function, src: usize, comptime format: []const u8, args: var) error{ CodegenFail, OutOfMemory } {
435 @setCold(true);430 @setCold(true);
436 const msg = try std.fmt.allocPrint(self.errors.allocator, format, args);431 try self.errors.ensureCapacity(self.errors.items.len + 1);
437 {432 self.errors.appendAssumeCapacity(.{
438 errdefer self.errors.allocator.free(msg);433 .byte_offset = src,
439 (try self.errors.addOne()).* = .{434 .msg = try std.fmt.allocPrint(self.errors.allocator, format, args),
440 .byte_offset = src,435 });
441 .msg = msg,
442 };
443 }
444 return error.CodegenFail;436 return error.CodegenFail;
445 }437 }
446};438};
src-self-hosted/compilation.zig+56-33
...@@ -19,7 +19,6 @@ const AtomicOrder = builtin.AtomicOrder;...@@ -19,7 +19,6 @@ const AtomicOrder = builtin.AtomicOrder;
19const Scope = @import("scope.zig").Scope;19const Scope = @import("scope.zig").Scope;
20const Decl = @import("decl.zig").Decl;20const Decl = @import("decl.zig").Decl;
21const ir = @import("ir.zig");21const ir = @import("ir.zig");
22const Visib = @import("visib.zig").Visib;
23const Value = @import("value.zig").Value;22const Value = @import("value.zig").Value;
24const Type = Value.Type;23const Type = Value.Type;
25const Span = errmsg.Span;24const Span = errmsg.Span;
...@@ -30,7 +29,11 @@ const link = @import("link.zig").link;...@@ -30,7 +29,11 @@ const link = @import("link.zig").link;
30const LibCInstallation = @import("libc_installation.zig").LibCInstallation;29const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
31const CInt = @import("c_int.zig").CInt;30const CInt = @import("c_int.zig").CInt;
32const fs = std.fs;31const fs = std.fs;
33const util = @import("util.zig");32
33pub const Visib = enum {
34 Private,
35 Pub,
36};
3437
35const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB38const max_src_size = 2 * 1024 * 1024 * 1024; // 2 GiB
3639
...@@ -45,7 +48,7 @@ pub const ZigCompiler = struct {...@@ -45,7 +48,7 @@ pub const ZigCompiler = struct {
4548
46 native_libc: event.Future(LibCInstallation),49 native_libc: event.Future(LibCInstallation),
4750
48 var lazy_init_targets = std.once(util.initializeAllTargets);51 var lazy_init_targets = std.once(initializeAllTargets);
4952
50 pub fn init(allocator: *Allocator) !ZigCompiler {53 pub fn init(allocator: *Allocator) !ZigCompiler {
51 lazy_init_targets.call();54 lazy_init_targets.call();
...@@ -119,6 +122,8 @@ pub const LlvmHandle = struct {...@@ -119,6 +122,8 @@ pub const LlvmHandle = struct {
119};122};
120123
121pub const Compilation = struct {124pub const Compilation = struct {
125 pub const FnLinkSet = std.TailQueue(?*Value.Fn);
126
122 zig_compiler: *ZigCompiler,127 zig_compiler: *ZigCompiler,
123 name: ArrayListSentineled(u8, 0),128 name: ArrayListSentineled(u8, 0),
124 llvm_triple: ArrayListSentineled(u8, 0),129 llvm_triple: ArrayListSentineled(u8, 0),
...@@ -152,8 +157,6 @@ pub const Compilation = struct {...@@ -152,8 +157,6 @@ pub const Compilation = struct {
152 /// it uses an optional pointer so that tombstone removals are possible157 /// it uses an optional pointer so that tombstone removals are possible
153 fn_link_set: event.Locked(FnLinkSet) = event.Locked(FnLinkSet).init(FnLinkSet.init()),158 fn_link_set: event.Locked(FnLinkSet) = event.Locked(FnLinkSet).init(FnLinkSet.init()),
154159
155 pub const FnLinkSet = std.TailQueue(?*Value.Fn);
156
157 link_libs_list: ArrayList(*LinkLib),160 link_libs_list: ArrayList(*LinkLib),
158 libc_link_lib: ?*LinkLib = null,161 libc_link_lib: ?*LinkLib = null,
159162
...@@ -361,8 +364,7 @@ pub const Compilation = struct {...@@ -361,8 +364,7 @@ pub const Compilation = struct {
361 return comp;364 return comp;
362 } else if (await frame) |_| unreachable else |err| return err;365 } else if (await frame) |_| unreachable else |err| return err;
363 }366 }
364367 fn createAsync(
365 async fn createAsync(
366 out_comp: *?*Compilation,368 out_comp: *?*Compilation,
367 zig_compiler: *ZigCompiler,369 zig_compiler: *ZigCompiler,
368 name: []const u8,370 name: []const u8,
...@@ -372,7 +374,7 @@ pub const Compilation = struct {...@@ -372,7 +374,7 @@ pub const Compilation = struct {
372 build_mode: builtin.Mode,374 build_mode: builtin.Mode,
373 is_static: bool,375 is_static: bool,
374 zig_lib_dir: []const u8,376 zig_lib_dir: []const u8,
375 ) !void {377 ) callconv(.Async) !void {
376 const allocator = zig_compiler.allocator;378 const allocator = zig_compiler.allocator;
377379
378 // TODO merge this line with stage2.zig crossTargetToTarget380 // TODO merge this line with stage2.zig crossTargetToTarget
...@@ -442,8 +444,8 @@ pub const Compilation = struct {...@@ -442,8 +444,8 @@ pub const Compilation = struct {
442 }444 }
443445
444 comp.name = try ArrayListSentineled(u8, 0).init(comp.arena(), name);446 comp.name = try ArrayListSentineled(u8, 0).init(comp.arena(), name);
445 comp.llvm_triple = try util.getLLVMTriple(comp.arena(), target);447 comp.llvm_triple = try getLLVMTriple(comp.arena(), target);
446 comp.llvm_target = try util.llvmTargetFromTriple(comp.llvm_triple);448 comp.llvm_target = try llvmTargetFromTriple(comp.llvm_triple);
447 comp.zig_std_dir = try fs.path.join(comp.arena(), &[_][]const u8{ zig_lib_dir, "std" });449 comp.zig_std_dir = try fs.path.join(comp.arena(), &[_][]const u8{ zig_lib_dir, "std" });
448450
449 const opt_level = switch (build_mode) {451 const opt_level = switch (build_mode) {
...@@ -726,8 +728,7 @@ pub const Compilation = struct {...@@ -726,8 +728,7 @@ pub const Compilation = struct {
726 fn start(self: *Compilation) void {728 fn start(self: *Compilation) void {
727 self.main_loop_future.resolve();729 self.main_loop_future.resolve();
728 }730 }
729731 fn mainLoop(self: *Compilation) callconv(.Async) void {
730 async fn mainLoop(self: *Compilation) void {
731 // wait until start() is called732 // wait until start() is called
732 _ = self.main_loop_future.get();733 _ = self.main_loop_future.get();
733734
...@@ -790,8 +791,7 @@ pub const Compilation = struct {...@@ -790,8 +791,7 @@ pub const Compilation = struct {
790 build_result = group.wait();791 build_result = group.wait();
791 }792 }
792 }793 }
793794 fn rebuildFile(self: *Compilation, root_scope: *Scope.Root) callconv(.Async) BuildError!void {
794 async fn rebuildFile(self: *Compilation, root_scope: *Scope.Root) BuildError!void {
795 const tree_scope = blk: {795 const tree_scope = blk: {
796 const source_code = fs.cwd().readFileAlloc(796 const source_code = fs.cwd().readFileAlloc(
797 self.gpa(),797 self.gpa(),
...@@ -964,15 +964,14 @@ pub const Compilation = struct {...@@ -964,15 +964,14 @@ pub const Compilation = struct {
964 try link(self);964 try link(self);
965 }965 }
966 }966 }
967
968 /// caller takes ownership of resulting Code967 /// caller takes ownership of resulting Code
969 async fn genAndAnalyzeCode(968 fn genAndAnalyzeCode(
970 comp: *Compilation,969 comp: *Compilation,
971 tree_scope: *Scope.AstTree,970 tree_scope: *Scope.AstTree,
972 scope: *Scope,971 scope: *Scope,
973 node: *ast.Node,972 node: *ast.Node,
974 expected_type: ?*Type,973 expected_type: ?*Type,
975 ) !*ir.Code {974 ) callconv(.Async) !*ir.Code {
976 const unanalyzed_code = try ir.gen(975 const unanalyzed_code = try ir.gen(
977 comp,976 comp,
978 node,977 node,
...@@ -1000,13 +999,12 @@ pub const Compilation = struct {...@@ -1000,13 +999,12 @@ pub const Compilation = struct {
1000999
1001 return analyzed_code;1000 return analyzed_code;
1002 }1001 }
10031002 fn addCompTimeBlock(
1004 async fn addCompTimeBlock(
1005 comp: *Compilation,1003 comp: *Compilation,
1006 tree_scope: *Scope.AstTree,1004 tree_scope: *Scope.AstTree,
1007 scope: *Scope,1005 scope: *Scope,
1008 comptime_node: *ast.Node.Comptime,1006 comptime_node: *ast.Node.Comptime,
1009 ) BuildError!void {1007 ) callconv(.Async) BuildError!void {
1010 const void_type = Type.Void.get(comp);1008 const void_type = Type.Void.get(comp);
1011 defer void_type.base.base.deref(comp);1009 defer void_type.base.base.deref(comp);
10121010
...@@ -1024,12 +1022,11 @@ pub const Compilation = struct {...@@ -1024,12 +1022,11 @@ pub const Compilation = struct {
1024 };1022 };
1025 analyzed_code.destroy(comp.gpa());1023 analyzed_code.destroy(comp.gpa());
1026 }1024 }
10271025 fn addTopLevelDecl(
1028 async fn addTopLevelDecl(
1029 self: *Compilation,1026 self: *Compilation,
1030 decl: *Decl,1027 decl: *Decl,
1031 locked_table: *Decl.Table,1028 locked_table: *Decl.Table,
1032 ) BuildError!void {1029 ) callconv(.Async) BuildError!void {
1033 const is_export = decl.isExported(decl.tree_scope.tree);1030 const is_export = decl.isExported(decl.tree_scope.tree);
10341031
1035 if (is_export) {1032 if (is_export) {
...@@ -1065,11 +1062,10 @@ pub const Compilation = struct {...@@ -1065,11 +1062,10 @@ pub const Compilation = struct {
10651062
1066 try self.prelink_group.call(addCompileErrorAsync, .{ self, msg });1063 try self.prelink_group.call(addCompileErrorAsync, .{ self, msg });
1067 }1064 }
10681065 fn addCompileErrorAsync(
1069 async fn addCompileErrorAsync(
1070 self: *Compilation,1066 self: *Compilation,
1071 msg: *Msg,1067 msg: *Msg,
1072 ) BuildError!void {1068 ) callconv(.Async) BuildError!void {
1073 errdefer msg.destroy();1069 errdefer msg.destroy();
10741070
1075 const compile_errors = self.compile_errors.acquire();1071 const compile_errors = self.compile_errors.acquire();
...@@ -1077,8 +1073,7 @@ pub const Compilation = struct {...@@ -1077,8 +1073,7 @@ pub const Compilation = struct {
10771073
1078 try compile_errors.value.append(msg);1074 try compile_errors.value.append(msg);
1079 }1075 }
10801076 fn verifyUniqueSymbol(self: *Compilation, decl: *Decl) callconv(.Async) BuildError!void {
1081 async fn verifyUniqueSymbol(self: *Compilation, decl: *Decl) BuildError!void {
1082 const exported_symbol_names = self.exported_symbol_names.acquire();1077 const exported_symbol_names = self.exported_symbol_names.acquire();
1083 defer exported_symbol_names.release();1078 defer exported_symbol_names.release();
10841079
...@@ -1129,8 +1124,7 @@ pub const Compilation = struct {...@@ -1129,8 +1124,7 @@ pub const Compilation = struct {
1129 }1124 }
1130 return link_lib;1125 return link_lib;
1131 }1126 }
11321127 fn startFindingNativeLibC(self: *Compilation) callconv(.Async) void {
1133 async fn startFindingNativeLibC(self: *Compilation) void {
1134 event.Loop.startCpuBoundOperation();1128 event.Loop.startCpuBoundOperation();
1135 // we don't care if it fails, we're just trying to kick off the future resolution1129 // we don't care if it fails, we're just trying to kick off the future resolution
1136 _ = self.zig_compiler.getNativeLibC() catch return;1130 _ = self.zig_compiler.getNativeLibC() catch return;
...@@ -1234,7 +1228,7 @@ pub const Compilation = struct {...@@ -1234,7 +1228,7 @@ pub const Compilation = struct {
1234 }1228 }
12351229
1236 /// This declaration has been blessed as going into the final code generation.1230 /// This declaration has been blessed as going into the final code generation.
1237 pub async fn resolveDecl(comp: *Compilation, decl: *Decl) BuildError!void {1231 pub fn resolveDecl(comp: *Compilation, decl: *Decl) callconv(.Async) BuildError!void {
1238 if (decl.resolution.start()) |ptr| return ptr.*;1232 if (decl.resolution.start()) |ptr| return ptr.*;
12391233
1240 decl.resolution.data = try generateDecl(comp, decl);1234 decl.resolution.data = try generateDecl(comp, decl);
...@@ -1335,8 +1329,7 @@ fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {...@@ -1335,8 +1329,7 @@ fn generateDeclFn(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1335 try comp.prelink_group.call(codegen.renderToLlvm, .{ comp, fn_val, analyzed_code });1329 try comp.prelink_group.call(codegen.renderToLlvm, .{ comp, fn_val, analyzed_code });
1336 try comp.prelink_group.call(addFnToLinkSet, .{ comp, fn_val });1330 try comp.prelink_group.call(addFnToLinkSet, .{ comp, fn_val });
1337}1331}
13381332fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) callconv(.Async) Compilation.BuildError!void {
1339async fn addFnToLinkSet(comp: *Compilation, fn_val: *Value.Fn) Compilation.BuildError!void {
1340 fn_val.base.ref();1333 fn_val.base.ref();
1341 defer fn_val.base.deref(comp);1334 defer fn_val.base.deref(comp);
13421335
...@@ -1432,3 +1425,33 @@ fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void {...@@ -1432,3 +1425,33 @@ fn generateDeclFnProto(comp: *Compilation, fn_decl: *Decl.Fn) !void {
1432 fn_decl.value = .{ .FnProto = fn_proto_val };1425 fn_decl.value = .{ .FnProto = fn_proto_val };
1433 symbol_name_consumed = true;1426 symbol_name_consumed = true;
1434}1427}
1428
1429pub fn llvmTargetFromTriple(triple: [:0]const u8) !*llvm.Target {
1430 var result: *llvm.Target = undefined;
1431 var err_msg: [*:0]u8 = undefined;
1432 if (llvm.GetTargetFromTriple(triple, &result, &err_msg) != 0) {
1433 std.debug.warn("triple: {s} error: {s}\n", .{ triple, err_msg });
1434 return error.UnsupportedTarget;
1435 }
1436 return result;
1437}
1438
1439pub fn initializeAllTargets() void {
1440 llvm.InitializeAllTargets();
1441 llvm.InitializeAllTargetInfos();
1442 llvm.InitializeAllTargetMCs();
1443 llvm.InitializeAllAsmPrinters();
1444 llvm.InitializeAllAsmParsers();
1445}
1446
1447pub fn getLLVMTriple(allocator: *std.mem.Allocator, target: std.Target) ![:0]u8 {
1448 var result = try std.ArrayListSentineled(u8, 0).initSize(allocator, 0);
1449 defer result.deinit();
1450
1451 try result.outStream().print(
1452 "{}-unknown-{}-{}",
1453 .{ @tagName(target.cpu.arch), @tagName(target.os.tag), @tagName(target.abi) },
1454 );
1455
1456 return result.toOwnedSlice();
1457}
src-self-hosted/decl.zig deleted-102
...@@ -1,102 +0,0 @@
1const std = @import("std");
2const Allocator = mem.Allocator;
3const mem = std.mem;
4const ast = std.zig.ast;
5const Visib = @import("visib.zig").Visib;
6const event = std.event;
7const Value = @import("value.zig").Value;
8const Token = std.zig.Token;
9const errmsg = @import("errmsg.zig");
10const Scope = @import("scope.zig").Scope;
11const Compilation = @import("compilation.zig").Compilation;
12
13pub const Decl = struct {
14 id: Id,
15 name: []const u8,
16 visib: Visib,
17 resolution: event.Future(Compilation.BuildError!void),
18 parent_scope: *Scope,
19
20 // TODO when we destroy the decl, deref the tree scope
21 tree_scope: *Scope.AstTree,
22
23 pub const Table = std.StringHashMap(*Decl);
24
25 pub fn cast(base: *Decl, comptime T: type) ?*T {
26 if (base.id != @field(Id, @typeName(T))) return null;
27 return @fieldParentPtr(T, "base", base);
28 }
29
30 pub fn isExported(base: *const Decl, tree: *ast.Tree) bool {
31 switch (base.id) {
32 .Fn => {
33 const fn_decl = @fieldParentPtr(Fn, "base", base);
34 return fn_decl.isExported(tree);
35 },
36 else => return false,
37 }
38 }
39
40 pub fn getSpan(base: *const Decl) errmsg.Span {
41 switch (base.id) {
42 .Fn => {
43 const fn_decl = @fieldParentPtr(Fn, "base", base);
44 const fn_proto = fn_decl.fn_proto;
45 const start = fn_proto.fn_token;
46 const end = fn_proto.name_token orelse start;
47 return errmsg.Span{
48 .first = start,
49 .last = end + 1,
50 };
51 },
52 else => @panic("TODO"),
53 }
54 }
55
56 pub fn findRootScope(base: *const Decl) *Scope.Root {
57 return base.parent_scope.findRoot();
58 }
59
60 pub const Id = enum {
61 Var,
62 Fn,
63 CompTime,
64 };
65
66 pub const Var = struct {
67 base: Decl,
68 };
69
70 pub const Fn = struct {
71 base: Decl,
72 value: union(enum) {
73 Unresolved,
74 Fn: *Value.Fn,
75 FnProto: *Value.FnProto,
76 },
77 fn_proto: *ast.Node.FnProto,
78
79 pub fn externLibName(self: Fn, tree: *ast.Tree) ?[]const u8 {
80 return if (self.fn_proto.extern_export_inline_token) |tok_index| x: {
81 const token = tree.tokens.at(tok_index);
82 break :x switch (token.id) {
83 .Extern => tree.tokenSlicePtr(token),
84 else => null,
85 };
86 } else null;
87 }
88
89 pub fn isExported(self: Fn, tree: *ast.Tree) bool {
90 if (self.fn_proto.extern_export_inline_token) |tok_index| {
91 const token = tree.tokens.at(tok_index);
92 return token.id == .Keyword_export;
93 } else {
94 return false;
95 }
96 }
97 };
98
99 pub const CompTime = struct {
100 base: Decl,
101 };
102};
src-self-hosted/ir.zig+716-352
...@@ -1,12 +1,16 @@...@@ -1,12 +1,16 @@
1const std = @import("std");1const std = @import("std");
2const mem = std.mem;2const mem = std.mem;
3const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
4const ArrayListUnmanaged = std.ArrayListUnmanaged;
5const LinkedList = std.TailQueue;
4const Value = @import("value.zig").Value;6const Value = @import("value.zig").Value;
5const Type = @import("type.zig").Type;7const Type = @import("type.zig").Type;
6const assert = std.debug.assert;8const assert = std.debug.assert;
7const BigIntConst = std.math.big.int.Const;9const BigIntConst = std.math.big.int.Const;
8const BigIntMutable = std.math.big.int.Mutable;10const BigIntMutable = std.math.big.int.Mutable;
9const Target = std.Target;11const Target = std.Target;
12const Package = @import("Package.zig");
13const link = @import("link.zig");
1014
11pub const text = @import("ir/text.zig");15pub const text = @import("ir/text.zig");
1216
...@@ -25,6 +29,7 @@ pub const Inst = struct {...@@ -25,6 +29,7 @@ pub const Inst = struct {
25 assembly,29 assembly,
26 bitcast,30 bitcast,
27 breakpoint,31 breakpoint,
32 call,
28 cmp,33 cmp,
29 condbr,34 condbr,
30 constant,35 constant,
...@@ -84,6 +89,15 @@ pub const Inst = struct {...@@ -84,6 +89,15 @@ pub const Inst = struct {
84 args: void,89 args: void,
85 };90 };
8691
92 pub const Call = struct {
93 pub const base_tag = Tag.call;
94 base: Inst,
95 args: struct {
96 func: *Inst,
97 args: []const *Inst,
98 },
99 };
100
87 pub const Cmp = struct {101 pub const Cmp = struct {
88 pub const base_tag = Tag.cmp;102 pub const base_tag = Tag.cmp;
89103
...@@ -158,170 +172,416 @@ pub const TypedValue = struct {...@@ -158,170 +172,416 @@ pub const TypedValue = struct {
158 val: Value,172 val: Value,
159};173};
160174
175fn swapRemoveElem(allocator: *Allocator, comptime T: type, item: T, list: *ArrayListUnmanaged(T)) void {
176 var i: usize = 0;
177 while (i < list.items.len) {
178 if (list.items[i] == item) {
179 list.swapRemove(allocator, i);
180 continue;
181 }
182 i += 1;
183 }
184}
185
161pub const Module = struct {186pub const Module = struct {
162 exports: []Export,187 /// General-purpose allocator.
163 errors: []ErrorMsg,188 allocator: *Allocator,
164 arena: std.heap.ArenaAllocator,189 /// Module owns this resource.
165 fns: []Fn,190 root_pkg: *Package,
166 target: Target,191 /// Module owns this resource.
167 link_mode: std.builtin.LinkMode,192 root_scope: *Scope.ZIRModule,
168 output_mode: std.builtin.OutputMode,193 /// Pointer to externally managed resource.
169 object_format: std.Target.ObjectFormat,194 bin_file: *link.ElfFile,
195 failed_decls: ArrayListUnmanaged(*Decl) = .{},
196 failed_fns: ArrayListUnmanaged(*Fn) = .{},
197 failed_files: ArrayListUnmanaged(*Scope.ZIRModule) = .{},
198 decl_table: std.AutoHashMap(Decl.Hash, *Decl),
170 optimize_mode: std.builtin.Mode,199 optimize_mode: std.builtin.Mode,
171200 link_error_flags: link.ElfFile.ErrorFlags = .{},
172 pub const Export = struct {201
173 name: []const u8,202 pub const Decl = struct {
174 typed_value: TypedValue,203 /// Contains the memory for `typed_value` and this `Decl` itself.
204 /// If the Decl is a function, also contains that memory.
205 /// If the decl has any export nodes, also contains that memory.
206 /// TODO look into using a more memory efficient arena that will cost less bytes per decl.
207 /// This one has a minimum allocation of 4096 bytes.
208 arena: std.heap.ArenaAllocator.State,
209 /// This name is relative to the containing namespace of the decl. It uses a null-termination
210 /// to save bytes, since there can be a lot of decls in a compilation. The null byte is not allowed
211 /// in symbol names, because executable file formats use null-terminated strings for symbol names.
212 name: [*:0]const u8,
213 /// It's rare for a decl to be exported, and it's even rarer for a decl to be mapped to more
214 /// than one export, so we use a linked list to save memory.
215 export_node: ?*LinkedList(std.builtin.ExportOptions).Node = null,
216 /// Byte offset into the source file that contains this declaration.
217 /// This is the base offset that src offsets within this Decl are relative to.
175 src: usize,218 src: usize,
219 /// Represents the "shallow" analysis status. For example, for decls that are functions,
220 /// the function type is analyzed with this set to `in_progress`, however, the semantic
221 /// analysis of the function body is performed with this value set to `success`. Functions
222 /// have their own analysis status field.
223 analysis: union(enum) {
224 in_progress,
225 failure: ErrorMsg,
226 success: TypedValue,
227 },
228 /// The direct container of the Decl. This field will need to get more fleshed out when
229 /// self-hosted supports proper struct types and Zig AST => ZIR.
230 scope: *Scope.ZIRModule,
231
232 pub fn destroy(self: *Decl, allocator: *Allocator) void {
233 var arena = self.arena.promote(allocator);
234 arena.deinit();
235 }
236
237 pub const Hash = [16]u8;
238
239 /// Must generate unique bytes with no collisions with other decls.
240 /// The point of hashing here is only to limit the number of bytes of
241 /// the unique identifier to a fixed size (16 bytes).
242 pub fn fullyQualifiedNameHash(self: Decl) Hash {
243 // Right now we only have ZIRModule as the source. So this is simply the
244 // relative name of the decl.
245 var out: Hash = undefined;
246 std.crypto.Blake3.hash(mem.spanZ(u8, self.name), &out);
247 return out;
248 }
176 };249 };
177250
251 /// Memory is managed by the arena of the owning Decl.
178 pub const Fn = struct {252 pub const Fn = struct {
179 analysis_status: enum { in_progress, failure, success },
180 body: Body,
181 fn_type: Type,253 fn_type: Type,
254 analysis: union(enum) {
255 in_progress: *Analysis,
256 failure: ErrorMsg,
257 success: Body,
258 },
259 /// The direct container of the Fn. This field will need to get more fleshed out when
260 /// self-hosted supports proper struct types and Zig AST => ZIR.
261 scope: *Scope.ZIRModule,
262
263 /// This memory managed by the general purpose allocator.
264 pub const Analysis = struct {
265 inner_block: Scope.Block,
266 /// null value means a semantic analysis error happened.
267 inst_table: std.AutoHashMap(*text.Inst, ?*Inst),
268 };
269 };
270
271 pub const Scope = struct {
272 tag: Tag,
273
274 pub fn cast(base: *Scope, comptime T: type) ?*T {
275 if (base.tag != T.base_tag)
276 return null;
277
278 return @fieldParentPtr(T, "base", base);
279 }
280
281 pub const Tag = enum {
282 zir_module,
283 block,
284 decl,
285 };
286
287 pub const ZIRModule = struct {
288 pub const base_tag: Tag = .zir_module;
289 base: Scope = Scope{ .tag = base_tag },
290 /// Relative to the owning package's root_src_dir.
291 /// Reference to external memory, not owned by ZIRModule.
292 sub_file_path: []const u8,
293 contents: union(enum) {
294 unloaded,
295 parse_failure: ParseFailure,
296 success: Contents,
297 },
298 pub const ParseFailure = struct {
299 source: [:0]const u8,
300 errors: []ErrorMsg,
301
302 pub fn deinit(self: *ParseFailure, allocator: *Allocator) void {
303 allocator.free(self.errors);
304 allocator.free(source);
305 }
306 };
307 pub const Contents = struct {
308 source: [:0]const u8,
309 module: *text.Module,
310 };
311
312 pub fn deinit(self: *ZIRModule, allocator: *Allocator) void {
313 switch (self.contents) {
314 .unloaded => {},
315 .parse_failure => |pf| pd.deinit(allocator),
316 .success => |contents| {
317 allocator.free(contents.source);
318 contents.src_zir_module.deinit(allocator);
319 },
320 }
321 self.* = undefined;
322 }
323
324 pub fn loadContents(self: *ZIRModule, allocator: *Allocator) !*Contents {
325 if (self.contents) |contents| return contents;
326
327 const max_size = std.math.maxInt(u32);
328 const source = try self.root_pkg_dir.readFileAllocOptions(allocator, self.root_src_path, max_size, 1, 0);
329 errdefer allocator.free(source);
330
331 var errors = std.ArrayList(ErrorMsg).init(allocator);
332 defer errors.deinit();
333
334 var src_zir_module = try text.parse(allocator, source, &errors);
335 errdefer src_zir_module.deinit(allocator);
336
337 switch (self.contents) {
338 .parse_failure => |pf| pf.deinit(allocator),
339 .unloaded => {},
340 .success => unreachable,
341 }
342
343 if (errors.items.len != 0) {
344 self.contents = .{ .parse_failure = errors.toOwnedSlice() };
345 return error.ParseFailure;
346 }
347 self.contents = .{
348 .success = .{
349 .source = source,
350 .module = src_zir_module,
351 },
352 };
353 return &self.contents.success;
354 }
355 };
356
357 /// This is a temporary structure, references to it are valid only
358 /// during semantic analysis of the block.
359 pub const Block = struct {
360 pub const base_tag: Tag = .block;
361 base: Scope = Scope{ .tag = base_tag },
362 func: *Fn,
363 instructions: ArrayListUnmanaged(*Inst),
364 };
365
366 /// This is a temporary structure, references to it are valid only
367 /// during semantic analysis of the decl.
368 pub const DeclAnalysis = struct {
369 pub const base_tag: Tag = .decl;
370 base: Scope = Scope{ .tag = base_tag },
371 decl: *Decl,
372 };
182 };373 };
183374
184 pub const Body = struct {375 pub const Body = struct {
185 instructions: []*Inst,376 instructions: []*Inst,
186 };377 };
187378
188 pub fn deinit(self: *Module, allocator: *Allocator) void {379 pub const AllErrors = struct {
189 allocator.free(self.exports);380 arena: std.heap.ArenaAllocator.State,
381 list: []const Message,
382
383 pub const Message = struct {
384 src_path: []const u8,
385 line: usize,
386 column: usize,
387 byte_offset: usize,
388 msg: []const u8,
389 };
390
391 pub fn deinit(self: *AllErrors, allocator: *Allocator) void {
392 self.arena.promote(allocator).deinit();
393 }
394
395 fn add(
396 arena: *std.heap.ArenaAllocator,
397 errors: *std.ArrayList(Message),
398 sub_file_path: []const u8,
399 source: []const u8,
400 simple_err_msg: ErrorMsg,
401 ) !void {
402 const loc = std.zig.findLineColumn(source, simple_err_msg.byte_offset);
403 try errors.append(.{
404 .src_path = try mem.dupe(u8, &arena.allocator, sub_file_path),
405 .msg = try mem.dupe(u8, &arena.allocator, simple_err_msg.msg),
406 .byte_offset = simple_err_msg.byte_offset,
407 .line = loc.line,
408 .column = loc.column,
409 });
410 }
411 };
412
413 pub fn deinit(self: *Module) void {
414 const allocator = self.allocator;
190 allocator.free(self.errors);415 allocator.free(self.errors);
191 for (self.fns) |f| {416 {
192 allocator.free(f.body.instructions);417 var it = self.decl_table.iterator();
418 while (it.next()) |kv| {
419 kv.value.destroy(allocator);
420 }
421 self.decl_table.deinit();
193 }422 }
194 allocator.free(self.fns);423 self.root_pkg.destroy();
195 self.arena.deinit();424 self.root_scope.deinit();
196 self.* = undefined;425 self.* = undefined;
197 }426 }
198};
199427
200pub const ErrorMsg = struct {428 pub fn target(self: Module) std.Target {
201 byte_offset: usize,429 return self.bin_file.options.target;
202 msg: []const u8,430 }
203};
204431
205pub const AnalyzeOptions = struct {432 /// Detect changes to source files, perform semantic analysis, and update the output files.
206 target: Target,433 pub fn update(self: *Module) !void {
207 output_mode: std.builtin.OutputMode,434 // TODO Use the cache hash file system to detect which source files changed.
208 link_mode: std.builtin.LinkMode,435 // Here we simulate a full cache miss.
209 object_format: ?std.Target.ObjectFormat = null,436 // Analyze the root source file now.
210 optimize_mode: std.builtin.Mode,437 self.analyzeRoot(self.root_scope) catch |err| switch (err) {
211};438 error.AnalysisFail => {
439 assert(self.totalErrorCount() != 0);
440 },
441 else => |e| return e,
442 };
212443
213pub fn analyze(allocator: *Allocator, old_module: text.Module, options: AnalyzeOptions) !Module {444 try self.bin_file.flush();
214 var ctx = Analyze{445 self.link_error_flags = self.bin_file.error_flags;
215 .allocator = allocator,446 }
216 .arena = std.heap.ArenaAllocator.init(allocator),
217 .old_module = &old_module,
218 .errors = std.ArrayList(ErrorMsg).init(allocator),
219 .decl_table = std.AutoHashMap(*text.Inst, Analyze.NewDecl).init(allocator),
220 .exports = std.ArrayList(Module.Export).init(allocator),
221 .fns = std.ArrayList(Module.Fn).init(allocator),
222 .target = options.target,
223 .optimize_mode = options.optimize_mode,
224 .link_mode = options.link_mode,
225 .output_mode = options.output_mode,
226 };
227 defer ctx.errors.deinit();
228 defer ctx.decl_table.deinit();
229 defer ctx.exports.deinit();
230 defer ctx.fns.deinit();
231 errdefer ctx.arena.deinit();
232
233 ctx.analyzeRoot() catch |err| switch (err) {
234 error.AnalysisFail => {
235 assert(ctx.errors.items.len != 0);
236 },
237 else => |e| return e,
238 };
239 return Module{
240 .exports = ctx.exports.toOwnedSlice(),
241 .errors = ctx.errors.toOwnedSlice(),
242 .fns = ctx.fns.toOwnedSlice(),
243 .arena = ctx.arena,
244 .target = ctx.target,
245 .link_mode = ctx.link_mode,
246 .output_mode = ctx.output_mode,
247 .object_format = options.object_format orelse ctx.target.getObjectFormat(),
248 .optimize_mode = ctx.optimize_mode,
249 };
250}
251447
252const Analyze = struct {448 pub fn totalErrorCount(self: *Module) usize {
253 allocator: *Allocator,449 return self.failed_decls.items.len +
254 arena: std.heap.ArenaAllocator,450 self.failed_fns.items.len +
255 old_module: *const text.Module,451 self.failed_decls.items.len +
256 errors: std.ArrayList(ErrorMsg),452 @boolToInt(self.link_error_flags.no_entry_point_found);
257 decl_table: std.AutoHashMap(*text.Inst, NewDecl),453 }
258 exports: std.ArrayList(Module.Export),
259 fns: std.ArrayList(Module.Fn),
260 target: Target,
261 link_mode: std.builtin.LinkMode,
262 optimize_mode: std.builtin.Mode,
263 output_mode: std.builtin.OutputMode,
264454
265 const NewDecl = struct {455 pub fn getAllErrorsAlloc(self: *Module) !AllErrors {
266 /// null means a semantic analysis error happened456 var arena = std.heap.ArenaAllocator.init(self.allocator);
267 ptr: ?*Inst,457 errdefer arena.deinit();
268 };
269458
270 const NewInst = struct {459 var errors = std.ArrayList(AllErrors.Message).init(self.allocator);
271 /// null means a semantic analysis error happened460 defer errors.deinit();
272 ptr: ?*Inst,
273 };
274461
275 const Fn = struct {462 for (self.failed_files.items) |scope| {
276 /// Index into Module fns array463 const source = scope.parse_failure.source;
277 fn_index: usize,464 for (scope.parse_failure.errors) |parse_error| {
278 inner_block: Block,465 AllErrors.add(&arena, &errors, scope.sub_file_path, source, parse_error);
279 inst_table: std.AutoHashMap(*text.Inst, NewInst),466 }
280 };467 }
281468
282 const Block = struct {469 for (self.failed_fns.items) |func| {
283 func: *Fn,470 const source = func.scope.success.source;
284 instructions: std.ArrayList(*Inst),471 for (func.analysis.failure) |err_msg| {
285 };472 AllErrors.add(&arena, &errors, func.scope.sub_file_path, source, err_msg);
473 }
474 }
475
476 for (self.failed_decls.items) |decl| {
477 const source = decl.scope.success.source;
478 for (decl.analysis.failure) |err_msg| {
479 AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg);
480 }
481 }
482
483 if (self.link_error_flags.no_entry_point_found) {
484 try errors.append(.{
485 .src_path = self.module.root_src_path,
486 .line = 0,
487 .column = 0,
488 .byte_offset = 0,
489 .msg = try std.fmt.allocPrint(&arena.allocator, "no entry point found", .{}),
490 });
491 }
492
493 assert(errors.items.len == self.totalErrorCount());
494
495 return AllErrors{
496 .arena = arena.state,
497 .list = try mem.dupe(&arena.allocator, AllErrors.Message, errors.items),
498 };
499 }
286500
287 const InnerError = error{ OutOfMemory, AnalysisFail };501 const InnerError = error{ OutOfMemory, AnalysisFail };
288502
289 fn analyzeRoot(self: *Analyze) !void {503 fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void {
290 for (self.old_module.decls) |decl| {504 // TODO use the cache to identify, from the modified source files, the decls which have
505 // changed based on the span of memory that represents the decl in the re-parsed source file.
506 // Use the cached dependency graph to recursively determine the set of decls which need
507 // regeneration.
508 // Here we simulate adding a source file which was previously not part of the compilation,
509 // which means scanning the decls looking for exports.
510 // TODO also identify decls that need to be deleted.
511 const contents = blk: {
512 // Clear parse errors.
513 swapRemoveElem(self.allocator, *Scope.ZIRModule, root_scope, self.failed_files);
514 try self.failed_files.ensureCapacity(self.allocator, self.failed_files.items.len + 1);
515 break :blk root_scope.loadContents(self.allocator) catch |err| switch (err) {
516 error.ParseFailure => {
517 self.failed_files.appendAssumeCapacity(root_scope);
518 return error.AnalysisFail;
519 },
520 else => |e| return e,
521 };
522 };
523 for (contents.module.decls) |decl| {
291 if (decl.cast(text.Inst.Export)) |export_inst| {524 if (decl.cast(text.Inst.Export)) |export_inst| {
292 try analyzeExport(self, null, export_inst);525 try analyzeExport(self, &root_scope.base, export_inst);
293 }526 }
294 }527 }
295 }528 }
296529
297 fn resolveInst(self: *Analyze, opt_block: ?*Block, old_inst: *text.Inst) InnerError!*Inst {530 fn resolveDecl(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Decl {
298 if (opt_block) |block| {531 const hash = old_inst.fullyQualifiedNameHash();
532 if (self.decl_table.get(hash)) |kv| {
533 return kv.value;
534 } else {
535 const new_decl = blk: {
536 var decl_arena = std.heap.ArenaAllocator.init(self.allocator);
537 errdefer decl_arena.deinit();
538 const new_decl = try decl_arena.allocator.create(Decl);
539 const name = try mem.dupeZ(&decl_arena.allocator, u8, old_inst.name);
540 new_decl.* = .{
541 .arena = decl_arena.state,
542 .name = name,
543 .src = old_inst.src,
544 .analysis = .in_progress,
545 .scope = scope.findZIRModule(),
546 };
547 try self.decl_table.putNoClobber(hash, new_decl);
548 break :blk new_decl;
549 };
550
551 var decl_scope: Scope.DeclAnalysis = .{ .decl = new_decl };
552 const typed_value = self.analyzeInstConst(&decl_scope.base, old_inst) catch |err| switch (err) {
553 error.AnalysisFail => return error.AnalysisFail,
554 else => |e| return e,
555 };
556 new_decl.analysis = .{ .success = typed_value };
557 if (try self.bin_file.updateDecl(self.*, typed_value, new_decl.export_node, hash)) |err_msg| {
558 new_decl.analysis = .{ .success = typed_value };
559 } else |err| {
560 return err;
561 }
562 return new_decl;
563 }
564 }
565
566 fn resolveInst(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Inst {
567 if (scope.cast(Scope.Block)) |block| {
299 if (block.func.inst_table.get(old_inst)) |kv| {568 if (block.func.inst_table.get(old_inst)) |kv| {
300 return kv.value.ptr orelse return error.AnalysisFail;569 return kv.value.ptr orelse return error.AnalysisFail;
301 }570 }
302 }571 }
303572
304 if (self.decl_table.get(old_inst)) |kv| {573 const decl = try self.resolveDecl(scope, old_inst);
305 return kv.value.ptr orelse return error.AnalysisFail;574 const decl_ref = try self.analyzeDeclRef(scope, old_inst.src, decl);
306 } else {575 return self.analyzeDeref(scope, old_inst.src, decl_ref);
307 const new_inst = self.analyzeInst(null, old_inst) catch |err| switch (err) {
308 error.AnalysisFail => {
309 try self.decl_table.putNoClobber(old_inst, .{ .ptr = null });
310 return error.AnalysisFail;
311 },
312 else => |e| return e,
313 };
314 try self.decl_table.putNoClobber(old_inst, .{ .ptr = new_inst });
315 return new_inst;
316 }
317 }576 }
318577
319 fn requireRuntimeBlock(self: *Analyze, block: ?*Block, src: usize) !*Block {578 fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
320 return block orelse return self.fail(src, "instruction illegal outside function body", .{});579 return scope.cast(Scope.Block) orelse
580 return self.fail(scope, src, "instruction illegal outside function body", .{});
321 }581 }
322582
323 fn resolveInstConst(self: *Analyze, block: ?*Block, old_inst: *text.Inst) InnerError!TypedValue {583 fn resolveInstConst(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!TypedValue {
324 const new_inst = try self.resolveInst(block, old_inst);584 const new_inst = try self.resolveInst(scope, old_inst);
325 const val = try self.resolveConstValue(new_inst);585 const val = try self.resolveConstValue(new_inst);
326 return TypedValue{586 return TypedValue{
327 .ty = new_inst.ty,587 .ty = new_inst.ty,
...@@ -329,60 +589,67 @@ const Analyze = struct {...@@ -329,60 +589,67 @@ const Analyze = struct {
329 };589 };
330 }590 }
331591
332 fn resolveConstValue(self: *Analyze, base: *Inst) !Value {592 fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value {
333 return (try self.resolveDefinedValue(base)) orelse593 return (try self.resolveDefinedValue(base)) orelse
334 return self.fail(base.src, "unable to resolve comptime value", .{});594 return self.fail(scope, base.src, "unable to resolve comptime value", .{});
335 }595 }
336596
337 fn resolveDefinedValue(self: *Analyze, base: *Inst) !?Value {597 fn resolveDefinedValue(self: *Module, scope: *Scope, base: *Inst) !?Value {
338 if (base.value()) |val| {598 if (base.value()) |val| {
339 if (val.isUndef()) {599 if (val.isUndef()) {
340 return self.fail(base.src, "use of undefined value here causes undefined behavior", .{});600 return self.fail(scope, base.src, "use of undefined value here causes undefined behavior", .{});
341 }601 }
342 return val;602 return val;
343 }603 }
344 return null;604 return null;
345 }605 }
346606
347 fn resolveConstString(self: *Analyze, block: ?*Block, old_inst: *text.Inst) ![]u8 {607 fn resolveConstString(self: *Module, scope: *Scope, old_inst: *text.Inst) ![]u8 {
348 const new_inst = try self.resolveInst(block, old_inst);608 const new_inst = try self.resolveInst(scope, old_inst);
349 const wanted_type = Type.initTag(.const_slice_u8);609 const wanted_type = Type.initTag(.const_slice_u8);
350 const coerced_inst = try self.coerce(block, wanted_type, new_inst);610 const coerced_inst = try self.coerce(scope, wanted_type, new_inst);
351 const val = try self.resolveConstValue(coerced_inst);611 const val = try self.resolveConstValue(coerced_inst);
352 return val.toAllocatedBytes(&self.arena.allocator);612 return val.toAllocatedBytes(&self.arena.allocator);
353 }613 }
354614
355 fn resolveType(self: *Analyze, block: ?*Block, old_inst: *text.Inst) !Type {615 fn resolveType(self: *Module, scope: *Scope, old_inst: *text.Inst) !Type {
356 const new_inst = try self.resolveInst(block, old_inst);616 const new_inst = try self.resolveInst(scope, old_inst);
357 const wanted_type = Type.initTag(.@"type");617 const wanted_type = Type.initTag(.@"type");
358 const coerced_inst = try self.coerce(block, wanted_type, new_inst);618 const coerced_inst = try self.coerce(scope, wanted_type, new_inst);
359 const val = try self.resolveConstValue(coerced_inst);619 const val = try self.resolveConstValue(coerced_inst);
360 return val.toType();620 return val.toType();
361 }621 }
362622
363 fn analyzeExport(self: *Analyze, block: ?*Block, export_inst: *text.Inst.Export) !void {623 fn analyzeExport(self: *Module, scope: *Scope, export_inst: *text.Inst.Export) !void {
364 const symbol_name = try self.resolveConstString(block, export_inst.positionals.symbol_name);624 const symbol_name = try self.resolveConstString(scope, export_inst.positionals.symbol_name);
365 const typed_value = try self.resolveInstConst(block, export_inst.positionals.value);625 const decl = try self.resolveDecl(scope, export_inst.positionals.value);
366626
367 switch (typed_value.ty.zigTypeTag()) {627 switch (decl.analysis) {
368 .Fn => {},628 .in_progress => unreachable,
369 else => return self.fail(629 .failure => return error.AnalysisFail,
370 export_inst.positionals.value.src,630 .success => |typed_value| switch (typed_value.ty.zigTypeTag()) {
371 "unable to export type '{}'",631 .Fn => {},
372 .{typed_value.ty},632 else => return self.fail(
373 ),633 scope,
634 export_inst.positionals.value.src,
635 "unable to export type '{}'",
636 .{typed_value.ty},
637 ),
638 },
374 }639 }
375 try self.exports.append(.{640 const Node = LinkedList(std.builtin.ExportOptions).Node;
376 .name = symbol_name,641 export_node = try decl.arena.promote(self.allocator).allocator.create(Node);
377 .typed_value = typed_value,642 export_node.* = .{ .data = .{ .name = symbol_name } };
378 .src = export_inst.base.src,643 decl.export_node = export_node;
379 });644
645 // TODO Avoid double update in the case of exporting a decl that we just created.
646 self.bin_file.updateDeclExports();
380 }647 }
381648
382 /// TODO should not need the cast on the last parameter at the callsites649 /// TODO should not need the cast on the last parameter at the callsites
383 fn addNewInstArgs(650 fn addNewInstArgs(
384 self: *Analyze,651 self: *Module,
385 block: *Block,652 block: *Scope.Block,
386 src: usize,653 src: usize,
387 ty: Type,654 ty: Type,
388 comptime T: type,655 comptime T: type,
...@@ -393,7 +660,7 @@ const Analyze = struct {...@@ -393,7 +660,7 @@ const Analyze = struct {
393 return &inst.base;660 return &inst.base;
394 }661 }
395662
396 fn addNewInst(self: *Analyze, block: *Block, src: usize, ty: Type, comptime T: type) !*T {663 fn addNewInst(self: *Module, block: *Scope.Block, src: usize, ty: Type, comptime T: type) !*T {
397 const inst = try self.arena.allocator.create(T);664 const inst = try self.arena.allocator.create(T);
398 inst.* = .{665 inst.* = .{
399 .base = .{666 .base = .{
...@@ -403,11 +670,11 @@ const Analyze = struct {...@@ -403,11 +670,11 @@ const Analyze = struct {
403 },670 },
404 .args = undefined,671 .args = undefined,
405 };672 };
406 try block.instructions.append(&inst.base);673 try block.instructions.append(self.allocator, &inst.base);
407 return inst;674 return inst;
408 }675 }
409676
410 fn constInst(self: *Analyze, src: usize, typed_value: TypedValue) !*Inst {677 fn constInst(self: *Module, src: usize, typed_value: TypedValue) !*Inst {
411 const const_inst = try self.arena.allocator.create(Inst.Constant);678 const const_inst = try self.arena.allocator.create(Inst.Constant);
412 const_inst.* = .{679 const_inst.* = .{
413 .base = .{680 .base = .{
...@@ -420,7 +687,7 @@ const Analyze = struct {...@@ -420,7 +687,7 @@ const Analyze = struct {
420 return &const_inst.base;687 return &const_inst.base;
421 }688 }
422689
423 fn constStr(self: *Analyze, src: usize, str: []const u8) !*Inst {690 fn constStr(self: *Module, src: usize, str: []const u8) !*Inst {
424 const array_payload = try self.arena.allocator.create(Type.Payload.Array_u8_Sentinel0);691 const array_payload = try self.arena.allocator.create(Type.Payload.Array_u8_Sentinel0);
425 array_payload.* = .{ .len = str.len };692 array_payload.* = .{ .len = str.len };
426693
...@@ -436,35 +703,35 @@ const Analyze = struct {...@@ -436,35 +703,35 @@ const Analyze = struct {
436 });703 });
437 }704 }
438705
439 fn constType(self: *Analyze, src: usize, ty: Type) !*Inst {706 fn constType(self: *Module, src: usize, ty: Type) !*Inst {
440 return self.constInst(src, .{707 return self.constInst(src, .{
441 .ty = Type.initTag(.type),708 .ty = Type.initTag(.type),
442 .val = try ty.toValue(&self.arena.allocator),709 .val = try ty.toValue(&self.arena.allocator),
443 });710 });
444 }711 }
445712
446 fn constVoid(self: *Analyze, src: usize) !*Inst {713 fn constVoid(self: *Module, src: usize) !*Inst {
447 return self.constInst(src, .{714 return self.constInst(src, .{
448 .ty = Type.initTag(.void),715 .ty = Type.initTag(.void),
449 .val = Value.initTag(.the_one_possible_value),716 .val = Value.initTag(.the_one_possible_value),
450 });717 });
451 }718 }
452719
453 fn constUndef(self: *Analyze, src: usize, ty: Type) !*Inst {720 fn constUndef(self: *Module, src: usize, ty: Type) !*Inst {
454 return self.constInst(src, .{721 return self.constInst(src, .{
455 .ty = ty,722 .ty = ty,
456 .val = Value.initTag(.undef),723 .val = Value.initTag(.undef),
457 });724 });
458 }725 }
459726
460 fn constBool(self: *Analyze, src: usize, v: bool) !*Inst {727 fn constBool(self: *Module, src: usize, v: bool) !*Inst {
461 return self.constInst(src, .{728 return self.constInst(src, .{
462 .ty = Type.initTag(.bool),729 .ty = Type.initTag(.bool),
463 .val = ([2]Value{ Value.initTag(.bool_false), Value.initTag(.bool_true) })[@boolToInt(v)],730 .val = ([2]Value{ Value.initTag(.bool_false), Value.initTag(.bool_true) })[@boolToInt(v)],
464 });731 });
465 }732 }
466733
467 fn constIntUnsigned(self: *Analyze, src: usize, ty: Type, int: u64) !*Inst {734 fn constIntUnsigned(self: *Module, src: usize, ty: Type, int: u64) !*Inst {
468 const int_payload = try self.arena.allocator.create(Value.Payload.Int_u64);735 const int_payload = try self.arena.allocator.create(Value.Payload.Int_u64);
469 int_payload.* = .{ .int = int };736 int_payload.* = .{ .int = int };
470737
...@@ -474,7 +741,7 @@ const Analyze = struct {...@@ -474,7 +741,7 @@ const Analyze = struct {
474 });741 });
475 }742 }
476743
477 fn constIntSigned(self: *Analyze, src: usize, ty: Type, int: i64) !*Inst {744 fn constIntSigned(self: *Module, src: usize, ty: Type, int: i64) !*Inst {
478 const int_payload = try self.arena.allocator.create(Value.Payload.Int_i64);745 const int_payload = try self.arena.allocator.create(Value.Payload.Int_i64);
479 int_payload.* = .{ .int = int };746 int_payload.* = .{ .int = int };
480747
...@@ -484,7 +751,7 @@ const Analyze = struct {...@@ -484,7 +751,7 @@ const Analyze = struct {
484 });751 });
485 }752 }
486753
487 fn constIntBig(self: *Analyze, src: usize, ty: Type, big_int: BigIntConst) !*Inst {754 fn constIntBig(self: *Module, src: usize, ty: Type, big_int: BigIntConst) !*Inst {
488 const val_payload = if (big_int.positive) blk: {755 const val_payload = if (big_int.positive) blk: {
489 if (big_int.to(u64)) |x| {756 if (big_int.to(u64)) |x| {
490 return self.constIntUnsigned(src, ty, x);757 return self.constIntUnsigned(src, ty, x);
...@@ -513,9 +780,18 @@ const Analyze = struct {...@@ -513,9 +780,18 @@ const Analyze = struct {
513 });780 });
514 }781 }
515782
516 fn analyzeInst(self: *Analyze, block: ?*Block, old_inst: *text.Inst) InnerError!*Inst {783 fn analyzeInstConst(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!TypedValue {
784 const new_inst = try self.analyzeInst(scope, old_inst);
785 return TypedValue{
786 .ty = new_inst.ty,
787 .val = try self.resolveConstValue(scope, new_inst),
788 };
789 }
790
791 fn analyzeInst(self: *Module, scope: *Scope, old_inst: *text.Inst) InnerError!*Inst {
517 switch (old_inst.tag) {792 switch (old_inst.tag) {
518 .breakpoint => return self.analyzeInstBreakpoint(block, old_inst.cast(text.Inst.Breakpoint).?),793 .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(text.Inst.Breakpoint).?),
794 .call => return self.analyzeInstCall(scope, old_inst.cast(text.Inst.Call).?),
519 .str => {795 .str => {
520 // We can use this reference because Inst.Const's Value is arena-allocated.796 // We can use this reference because Inst.Const's Value is arena-allocated.
521 // The value would get copied to a MemoryCell before the `text.Inst.Str` lifetime ends.797 // The value would get copied to a MemoryCell before the `text.Inst.Str` lifetime ends.
...@@ -526,53 +802,118 @@ const Analyze = struct {...@@ -526,53 +802,118 @@ const Analyze = struct {
526 const big_int = old_inst.cast(text.Inst.Int).?.positionals.int;802 const big_int = old_inst.cast(text.Inst.Int).?.positionals.int;
527 return self.constIntBig(old_inst.src, Type.initTag(.comptime_int), big_int);803 return self.constIntBig(old_inst.src, Type.initTag(.comptime_int), big_int);
528 },804 },
529 .ptrtoint => return self.analyzeInstPtrToInt(block, old_inst.cast(text.Inst.PtrToInt).?),805 .ptrtoint => return self.analyzeInstPtrToInt(scope, old_inst.cast(text.Inst.PtrToInt).?),
530 .fieldptr => return self.analyzeInstFieldPtr(block, old_inst.cast(text.Inst.FieldPtr).?),806 .fieldptr => return self.analyzeInstFieldPtr(scope, old_inst.cast(text.Inst.FieldPtr).?),
531 .deref => return self.analyzeInstDeref(block, old_inst.cast(text.Inst.Deref).?),807 .deref => return self.analyzeInstDeref(scope, old_inst.cast(text.Inst.Deref).?),
532 .as => return self.analyzeInstAs(block, old_inst.cast(text.Inst.As).?),808 .as => return self.analyzeInstAs(scope, old_inst.cast(text.Inst.As).?),
533 .@"asm" => return self.analyzeInstAsm(block, old_inst.cast(text.Inst.Asm).?),809 .@"asm" => return self.analyzeInstAsm(scope, old_inst.cast(text.Inst.Asm).?),
534 .@"unreachable" => return self.analyzeInstUnreachable(block, old_inst.cast(text.Inst.Unreachable).?),810 .@"unreachable" => return self.analyzeInstUnreachable(scope, old_inst.cast(text.Inst.Unreachable).?),
535 .@"return" => return self.analyzeInstRet(block, old_inst.cast(text.Inst.Return).?),811 .@"return" => return self.analyzeInstRet(scope, old_inst.cast(text.Inst.Return).?),
536 .@"fn" => return self.analyzeInstFn(block, old_inst.cast(text.Inst.Fn).?),812 // TODO postpone function analysis until later
813 .@"fn" => return self.analyzeInstFn(scope, old_inst.cast(text.Inst.Fn).?),
537 .@"export" => {814 .@"export" => {
538 try self.analyzeExport(block, old_inst.cast(text.Inst.Export).?);815 try self.analyzeExport(scope, old_inst.cast(text.Inst.Export).?);
539 return self.constVoid(old_inst.src);816 return self.constVoid(old_inst.src);
540 },817 },
541 .primitive => return self.analyzeInstPrimitive(old_inst.cast(text.Inst.Primitive).?),818 .primitive => return self.analyzeInstPrimitive(old_inst.cast(text.Inst.Primitive).?),
542 .fntype => return self.analyzeInstFnType(block, old_inst.cast(text.Inst.FnType).?),819 .fntype => return self.analyzeInstFnType(scope, old_inst.cast(text.Inst.FnType).?),
543 .intcast => return self.analyzeInstIntCast(block, old_inst.cast(text.Inst.IntCast).?),820 .intcast => return self.analyzeInstIntCast(scope, old_inst.cast(text.Inst.IntCast).?),
544 .bitcast => return self.analyzeInstBitCast(block, old_inst.cast(text.Inst.BitCast).?),821 .bitcast => return self.analyzeInstBitCast(scope, old_inst.cast(text.Inst.BitCast).?),
545 .elemptr => return self.analyzeInstElemPtr(block, old_inst.cast(text.Inst.ElemPtr).?),822 .elemptr => return self.analyzeInstElemPtr(scope, old_inst.cast(text.Inst.ElemPtr).?),
546 .add => return self.analyzeInstAdd(block, old_inst.cast(text.Inst.Add).?),823 .add => return self.analyzeInstAdd(scope, old_inst.cast(text.Inst.Add).?),
547 .cmp => return self.analyzeInstCmp(block, old_inst.cast(text.Inst.Cmp).?),824 .cmp => return self.analyzeInstCmp(scope, old_inst.cast(text.Inst.Cmp).?),
548 .condbr => return self.analyzeInstCondBr(block, old_inst.cast(text.Inst.CondBr).?),825 .condbr => return self.analyzeInstCondBr(scope, old_inst.cast(text.Inst.CondBr).?),
549 .isnull => return self.analyzeInstIsNull(block, old_inst.cast(text.Inst.IsNull).?),826 .isnull => return self.analyzeInstIsNull(scope, old_inst.cast(text.Inst.IsNull).?),
550 .isnonnull => return self.analyzeInstIsNonNull(block, old_inst.cast(text.Inst.IsNonNull).?),827 .isnonnull => return self.analyzeInstIsNonNull(scope, old_inst.cast(text.Inst.IsNonNull).?),
551 }828 }
552 }829 }
553830
554 fn analyzeInstBreakpoint(self: *Analyze, block: ?*Block, inst: *text.Inst.Breakpoint) InnerError!*Inst {831 fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *text.Inst.Breakpoint) InnerError!*Inst {
555 const b = try self.requireRuntimeBlock(block, inst.base.src);832 const b = try self.requireRuntimeBlock(scope, inst.base.src);
556 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){});833 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){});
557 }834 }
558835
559 fn analyzeInstFn(self: *Analyze, block: ?*Block, fn_inst: *text.Inst.Fn) InnerError!*Inst {836 fn analyzeInstCall(self: *Module, scope: *Scope, inst: *text.Inst.Call) InnerError!*Inst {
560 const fn_type = try self.resolveType(block, fn_inst.positionals.fn_type);837 const func = try self.resolveInst(scope, inst.positionals.func);
838 if (func.ty.zigTypeTag() != .Fn)
839 return self.fail(scope, inst.positionals.func.src, "type '{}' not a function", .{func.ty});
840
841 const cc = func.ty.fnCallingConvention();
842 if (cc == .Naked) {
843 // TODO add error note: declared here
844 return self.fail(
845 scope,
846 inst.positionals.func.src,
847 "unable to call function with naked calling convention",
848 .{},
849 );
850 }
851 const call_params_len = inst.positionals.args.len;
852 const fn_params_len = func.ty.fnParamLen();
853 if (func.ty.fnIsVarArgs()) {
854 if (call_params_len < fn_params_len) {
855 // TODO add error note: declared here
856 return self.fail(
857 scope,
858 inst.positionals.func.src,
859 "expected at least {} arguments, found {}",
860 .{ fn_params_len, call_params_len },
861 );
862 }
863 return self.fail(scope, inst.base.src, "TODO implement support for calling var args functions", .{});
864 } else if (fn_params_len != call_params_len) {
865 // TODO add error note: declared here
866 return self.fail(
867 scope,
868 inst.positionals.func.src,
869 "expected {} arguments, found {}",
870 .{ fn_params_len, call_params_len },
871 );
872 }
873
874 if (inst.kw_args.modifier == .compile_time) {
875 return self.fail(scope, inst.base.src, "TODO implement comptime function calls", .{});
876 }
877 if (inst.kw_args.modifier != .auto) {
878 return self.fail(scope, inst.base.src, "TODO implement call with modifier {}", .{inst.kw_args.modifier});
879 }
880
881 // TODO handle function calls of generic functions
882
883 const fn_param_types = try self.allocator.alloc(Type, fn_params_len);
884 defer self.allocator.free(fn_param_types);
885 func.ty.fnParamTypes(fn_param_types);
886
887 const casted_args = try self.arena.allocator.alloc(*Inst, fn_params_len);
888 for (inst.positionals.args) |src_arg, i| {
889 const uncasted_arg = try self.resolveInst(scope, src_arg);
890 casted_args[i] = try self.coerce(scope, fn_param_types[i], uncasted_arg);
891 }
892
893 const b = try self.requireRuntimeBlock(scope, inst.base.src);
894 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Call, Inst.Args(Inst.Call){
895 .func = func,
896 .args = casted_args,
897 });
898 }
899
900 fn analyzeInstFn(self: *Module, scope: *Scope, fn_inst: *text.Inst.Fn) InnerError!*Inst {
901 const fn_type = try self.resolveType(scope, fn_inst.positionals.fn_type);
561902
562 var new_func: Fn = .{903 var new_func: Fn = .{
563 .fn_index = self.fns.items.len,904 .fn_index = self.fns.items.len,
564 .inner_block = .{905 .inner_block = .{
565 .func = undefined,906 .func = undefined,
566 .instructions = std.ArrayList(*Inst).init(self.allocator),907 .instructions = .{},
567 },908 },
568 .inst_table = std.AutoHashMap(*text.Inst, NewInst).init(self.allocator),909 .inst_table = std.AutoHashMap(*text.Inst, ?*Inst).init(self.allocator),
569 };910 };
570 new_func.inner_block.func = &new_func;911 new_func.inner_block.func = &new_func;
571 defer new_func.inner_block.instructions.deinit();912 defer new_func.inner_block.instructions.deinit();
572 defer new_func.inst_table.deinit();913 defer new_func.inst_table.deinit();
573 // Don't hang on to a reference to this when analyzing body instructions, since the memory914 // Don't hang on to a reference to this when analyzing body instructions, since the memory
574 // could become invalid.915 // could become invalid.
575 (try self.fns.addOne()).* = .{916 (try self.fns.addOne(self.allocator)).* = .{
576 .analysis_status = .in_progress,917 .analysis_status = .in_progress,
577 .fn_type = fn_type,918 .fn_type = fn_type,
578 .body = undefined,919 .body = undefined,
...@@ -593,8 +934,15 @@ const Analyze = struct {...@@ -593,8 +934,15 @@ const Analyze = struct {
593 });934 });
594 }935 }
595936
596 fn analyzeInstFnType(self: *Analyze, block: ?*Block, fntype: *text.Inst.FnType) InnerError!*Inst {937 fn analyzeInstFnType(self: *Module, scope: *Scope, fntype: *text.Inst.FnType) InnerError!*Inst {
597 const return_type = try self.resolveType(block, fntype.positionals.return_type);938 const return_type = try self.resolveType(scope, fntype.positionals.return_type);
939
940 if (return_type.zigTypeTag() == .NoReturn and
941 fntype.positionals.param_types.len == 0 and
942 fntype.kw_args.cc == .Unspecified)
943 {
944 return self.constType(fntype.base.src, Type.initTag(.fn_noreturn_no_args));
945 }
598946
599 if (return_type.zigTypeTag() == .NoReturn and947 if (return_type.zigTypeTag() == .NoReturn and
600 fntype.positionals.param_types.len == 0 and948 fntype.positionals.param_types.len == 0 and
...@@ -610,37 +958,37 @@ const Analyze = struct {...@@ -610,37 +958,37 @@ const Analyze = struct {
610 return self.constType(fntype.base.src, Type.initTag(.fn_ccc_void_no_args));958 return self.constType(fntype.base.src, Type.initTag(.fn_ccc_void_no_args));
611 }959 }
612960
613 return self.fail(fntype.base.src, "TODO implement fntype instruction more", .{});961 return self.fail(scope, fntype.base.src, "TODO implement fntype instruction more", .{});
614 }962 }
615963
616 fn analyzeInstPrimitive(self: *Analyze, primitive: *text.Inst.Primitive) InnerError!*Inst {964 fn analyzeInstPrimitive(self: *Module, primitive: *text.Inst.Primitive) InnerError!*Inst {
617 return self.constType(primitive.base.src, primitive.positionals.tag.toType());965 return self.constType(primitive.base.src, primitive.positionals.tag.toType());
618 }966 }
619967
620 fn analyzeInstAs(self: *Analyze, block: ?*Block, as: *text.Inst.As) InnerError!*Inst {968 fn analyzeInstAs(self: *Module, scope: *Scope, as: *text.Inst.As) InnerError!*Inst {
621 const dest_type = try self.resolveType(block, as.positionals.dest_type);969 const dest_type = try self.resolveType(scope, as.positionals.dest_type);
622 const new_inst = try self.resolveInst(block, as.positionals.value);970 const new_inst = try self.resolveInst(scope, as.positionals.value);
623 return self.coerce(block, dest_type, new_inst);971 return self.coerce(scope, dest_type, new_inst);
624 }972 }
625973
626 fn analyzeInstPtrToInt(self: *Analyze, block: ?*Block, ptrtoint: *text.Inst.PtrToInt) InnerError!*Inst {974 fn analyzeInstPtrToInt(self: *Module, scope: *Scope, ptrtoint: *text.Inst.PtrToInt) InnerError!*Inst {
627 const ptr = try self.resolveInst(block, ptrtoint.positionals.ptr);975 const ptr = try self.resolveInst(scope, ptrtoint.positionals.ptr);
628 if (ptr.ty.zigTypeTag() != .Pointer) {976 if (ptr.ty.zigTypeTag() != .Pointer) {
629 return self.fail(ptrtoint.positionals.ptr.src, "expected pointer, found '{}'", .{ptr.ty});977 return self.fail(scope, ptrtoint.positionals.ptr.src, "expected pointer, found '{}'", .{ptr.ty});
630 }978 }
631 // TODO handle known-pointer-address979 // TODO handle known-pointer-address
632 const b = try self.requireRuntimeBlock(block, ptrtoint.base.src);980 const b = try self.requireRuntimeBlock(scope, ptrtoint.base.src);
633 const ty = Type.initTag(.usize);981 const ty = Type.initTag(.usize);
634 return self.addNewInstArgs(b, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr });982 return self.addNewInstArgs(b, ptrtoint.base.src, ty, Inst.PtrToInt, Inst.Args(Inst.PtrToInt){ .ptr = ptr });
635 }983 }
636984
637 fn analyzeInstFieldPtr(self: *Analyze, block: ?*Block, fieldptr: *text.Inst.FieldPtr) InnerError!*Inst {985 fn analyzeInstFieldPtr(self: *Module, scope: *Scope, fieldptr: *text.Inst.FieldPtr) InnerError!*Inst {
638 const object_ptr = try self.resolveInst(block, fieldptr.positionals.object_ptr);986 const object_ptr = try self.resolveInst(scope, fieldptr.positionals.object_ptr);
639 const field_name = try self.resolveConstString(block, fieldptr.positionals.field_name);987 const field_name = try self.resolveConstString(scope, fieldptr.positionals.field_name);
640988
641 const elem_ty = switch (object_ptr.ty.zigTypeTag()) {989 const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
642 .Pointer => object_ptr.ty.elemType(),990 .Pointer => object_ptr.ty.elemType(),
643 else => return self.fail(fieldptr.positionals.object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),991 else => return self.fail(scope, fieldptr.positionals.object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),
644 };992 };
645 switch (elem_ty.zigTypeTag()) {993 switch (elem_ty.zigTypeTag()) {
646 .Array => {994 .Array => {
...@@ -657,24 +1005,26 @@ const Analyze = struct {...@@ -657,24 +1005,26 @@ const Analyze = struct {
657 });1005 });
658 } else {1006 } else {
659 return self.fail(1007 return self.fail(
1008 scope,
660 fieldptr.positionals.field_name.src,1009 fieldptr.positionals.field_name.src,
661 "no member named '{}' in '{}'",1010 "no member named '{}' in '{}'",
662 .{ field_name, elem_ty },1011 .{ field_name, elem_ty },
663 );1012 );
664 }1013 }
665 },1014 },
666 else => return self.fail(fieldptr.base.src, "type '{}' does not support field access", .{elem_ty}),1015 else => return self.fail(scope, fieldptr.base.src, "type '{}' does not support field access", .{elem_ty}),
667 }1016 }
668 }1017 }
6691018
670 fn analyzeInstIntCast(self: *Analyze, block: ?*Block, intcast: *text.Inst.IntCast) InnerError!*Inst {1019 fn analyzeInstIntCast(self: *Module, scope: *Scope, intcast: *text.Inst.IntCast) InnerError!*Inst {
671 const dest_type = try self.resolveType(block, intcast.positionals.dest_type);1020 const dest_type = try self.resolveType(scope, intcast.positionals.dest_type);
672 const new_inst = try self.resolveInst(block, intcast.positionals.value);1021 const new_inst = try self.resolveInst(scope, intcast.positionals.value);
6731022
674 const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {1023 const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {
675 .ComptimeInt => true,1024 .ComptimeInt => true,
676 .Int => false,1025 .Int => false,
677 else => return self.fail(1026 else => return self.fail(
1027 scope,
678 intcast.positionals.dest_type.src,1028 intcast.positionals.dest_type.src,
679 "expected integer type, found '{}'",1029 "expected integer type, found '{}'",
680 .{1030 .{
...@@ -686,6 +1036,7 @@ const Analyze = struct {...@@ -686,6 +1036,7 @@ const Analyze = struct {
686 switch (new_inst.ty.zigTypeTag()) {1036 switch (new_inst.ty.zigTypeTag()) {
687 .ComptimeInt, .Int => {},1037 .ComptimeInt, .Int => {},
688 else => return self.fail(1038 else => return self.fail(
1039 scope,
689 intcast.positionals.value.src,1040 intcast.positionals.value.src,
690 "expected integer type, found '{}'",1041 "expected integer type, found '{}'",
691 .{new_inst.ty},1042 .{new_inst.ty},
...@@ -693,22 +1044,22 @@ const Analyze = struct {...@@ -693,22 +1044,22 @@ const Analyze = struct {
693 }1044 }
6941045
695 if (dest_is_comptime_int or new_inst.value() != null) {1046 if (dest_is_comptime_int or new_inst.value() != null) {
696 return self.coerce(block, dest_type, new_inst);1047 return self.coerce(scope, dest_type, new_inst);
697 }1048 }
6981049
699 return self.fail(intcast.base.src, "TODO implement analyze widen or shorten int", .{});1050 return self.fail(scope, intcast.base.src, "TODO implement analyze widen or shorten int", .{});
700 }1051 }
7011052
702 fn analyzeInstBitCast(self: *Analyze, block: ?*Block, inst: *text.Inst.BitCast) InnerError!*Inst {1053 fn analyzeInstBitCast(self: *Module, scope: *Scope, inst: *text.Inst.BitCast) InnerError!*Inst {
703 const dest_type = try self.resolveType(block, inst.positionals.dest_type);1054 const dest_type = try self.resolveType(scope, inst.positionals.dest_type);
704 const operand = try self.resolveInst(block, inst.positionals.operand);1055 const operand = try self.resolveInst(scope, inst.positionals.operand);
705 return self.bitcast(block, dest_type, operand);1056 return self.bitcast(scope, dest_type, operand);
706 }1057 }
7071058
708 fn analyzeInstElemPtr(self: *Analyze, block: ?*Block, inst: *text.Inst.ElemPtr) InnerError!*Inst {1059 fn analyzeInstElemPtr(self: *Module, scope: *Scope, inst: *text.Inst.ElemPtr) InnerError!*Inst {
709 const array_ptr = try self.resolveInst(block, inst.positionals.array_ptr);1060 const array_ptr = try self.resolveInst(scope, inst.positionals.array_ptr);
710 const uncasted_index = try self.resolveInst(block, inst.positionals.index);1061 const uncasted_index = try self.resolveInst(scope, inst.positionals.index);
711 const elem_index = try self.coerce(block, Type.initTag(.usize), uncasted_index);1062 const elem_index = try self.coerce(scope, Type.initTag(.usize), uncasted_index);
7121063
713 if (array_ptr.ty.isSinglePointer() and array_ptr.ty.elemType().zigTypeTag() == .Array) {1064 if (array_ptr.ty.isSinglePointer() and array_ptr.ty.elemType().zigTypeTag() == .Array) {
714 if (array_ptr.value()) |array_ptr_val| {1065 if (array_ptr.value()) |array_ptr_val| {
...@@ -717,28 +1068,25 @@ const Analyze = struct {...@@ -717,28 +1068,25 @@ const Analyze = struct {
717 const index_u64 = index_val.toUnsignedInt();1068 const index_u64 = index_val.toUnsignedInt();
718 // @intCast here because it would have been impossible to construct a value that1069 // @intCast here because it would have been impossible to construct a value that
719 // required a larger index.1070 // required a larger index.
720 const elem_val = try array_ptr_val.elemValueAt(&self.arena.allocator, @intCast(usize, index_u64));1071 const elem_ptr = try array_ptr_val.elemPtr(&self.arena.allocator, @intCast(usize, index_u64));
721
722 const ref_payload = try self.arena.allocator.create(Value.Payload.RefVal);
723 ref_payload.* = .{ .val = elem_val };
7241072
725 const type_payload = try self.arena.allocator.create(Type.Payload.SingleConstPointer);1073 const type_payload = try self.arena.allocator.create(Type.Payload.SingleConstPointer);
726 type_payload.* = .{ .pointee_type = array_ptr.ty.elemType().elemType() };1074 type_payload.* = .{ .pointee_type = array_ptr.ty.elemType().elemType() };
7271075
728 return self.constInst(inst.base.src, .{1076 return self.constInst(inst.base.src, .{
729 .ty = Type.initPayload(&type_payload.base),1077 .ty = Type.initPayload(&type_payload.base),
730 .val = Value.initPayload(&ref_payload.base),1078 .val = elem_ptr,
731 });1079 });
732 }1080 }
733 }1081 }
734 }1082 }
7351083
736 return self.fail(inst.base.src, "TODO implement more analyze elemptr", .{});1084 return self.fail(scope, inst.base.src, "TODO implement more analyze elemptr", .{});
737 }1085 }
7381086
739 fn analyzeInstAdd(self: *Analyze, block: ?*Block, inst: *text.Inst.Add) InnerError!*Inst {1087 fn analyzeInstAdd(self: *Module, scope: *Scope, inst: *text.Inst.Add) InnerError!*Inst {
740 const lhs = try self.resolveInst(block, inst.positionals.lhs);1088 const lhs = try self.resolveInst(scope, inst.positionals.lhs);
741 const rhs = try self.resolveInst(block, inst.positionals.rhs);1089 const rhs = try self.resolveInst(scope, inst.positionals.rhs);
7421090
743 if (lhs.ty.zigTypeTag() == .Int and rhs.ty.zigTypeTag() == .Int) {1091 if (lhs.ty.zigTypeTag() == .Int and rhs.ty.zigTypeTag() == .Int) {
744 if (lhs.value()) |lhs_val| {1092 if (lhs.value()) |lhs_val| {
...@@ -758,7 +1106,7 @@ const Analyze = struct {...@@ -758,7 +1106,7 @@ const Analyze = struct {
758 const result_limbs = result_bigint.limbs[0..result_bigint.len];1106 const result_limbs = result_bigint.limbs[0..result_bigint.len];
7591107
760 if (!lhs.ty.eql(rhs.ty)) {1108 if (!lhs.ty.eql(rhs.ty)) {
761 return self.fail(inst.base.src, "TODO implement peer type resolution", .{});1109 return self.fail(scope, inst.base.src, "TODO implement peer type resolution", .{});
762 }1110 }
7631111
764 const val_payload = if (result_bigint.positive) blk: {1112 const val_payload = if (result_bigint.positive) blk: {
...@@ -779,14 +1127,14 @@ const Analyze = struct {...@@ -779,14 +1127,14 @@ const Analyze = struct {
779 }1127 }
780 }1128 }
7811129
782 return self.fail(inst.base.src, "TODO implement more analyze add", .{});1130 return self.fail(scope, inst.base.src, "TODO implement more analyze add", .{});
783 }1131 }
7841132
785 fn analyzeInstDeref(self: *Analyze, block: ?*Block, deref: *text.Inst.Deref) InnerError!*Inst {1133 fn analyzeInstDeref(self: *Module, scope: *Scope, deref: *text.Inst.Deref) InnerError!*Inst {
786 const ptr = try self.resolveInst(block, deref.positionals.ptr);1134 const ptr = try self.resolveInst(scope, deref.positionals.ptr);
787 const elem_ty = switch (ptr.ty.zigTypeTag()) {1135 const elem_ty = switch (ptr.ty.zigTypeTag()) {
788 .Pointer => ptr.ty.elemType(),1136 .Pointer => ptr.ty.elemType(),
789 else => return self.fail(deref.positionals.ptr.src, "expected pointer, found '{}'", .{ptr.ty}),1137 else => return self.fail(scope, deref.positionals.ptr.src, "expected pointer, found '{}'", .{ptr.ty}),
790 };1138 };
791 if (ptr.value()) |val| {1139 if (ptr.value()) |val| {
792 return self.constInst(deref.base.src, .{1140 return self.constInst(deref.base.src, .{
...@@ -795,30 +1143,30 @@ const Analyze = struct {...@@ -795,30 +1143,30 @@ const Analyze = struct {
795 });1143 });
796 }1144 }
7971145
798 return self.fail(deref.base.src, "TODO implement runtime deref", .{});1146 return self.fail(scope, deref.base.src, "TODO implement runtime deref", .{});
799 }1147 }
8001148
801 fn analyzeInstAsm(self: *Analyze, block: ?*Block, assembly: *text.Inst.Asm) InnerError!*Inst {1149 fn analyzeInstAsm(self: *Module, scope: *Scope, assembly: *text.Inst.Asm) InnerError!*Inst {
802 const return_type = try self.resolveType(block, assembly.positionals.return_type);1150 const return_type = try self.resolveType(scope, assembly.positionals.return_type);
803 const asm_source = try self.resolveConstString(block, assembly.positionals.asm_source);1151 const asm_source = try self.resolveConstString(scope, assembly.positionals.asm_source);
804 const output = if (assembly.kw_args.output) |o| try self.resolveConstString(block, o) else null;1152 const output = if (assembly.kw_args.output) |o| try self.resolveConstString(scope, o) else null;
8051153
806 const inputs = try self.arena.allocator.alloc([]const u8, assembly.kw_args.inputs.len);1154 const inputs = try self.arena.allocator.alloc([]const u8, assembly.kw_args.inputs.len);
807 const clobbers = try self.arena.allocator.alloc([]const u8, assembly.kw_args.clobbers.len);1155 const clobbers = try self.arena.allocator.alloc([]const u8, assembly.kw_args.clobbers.len);
808 const args = try self.arena.allocator.alloc(*Inst, assembly.kw_args.args.len);1156 const args = try self.arena.allocator.alloc(*Inst, assembly.kw_args.args.len);
8091157
810 for (inputs) |*elem, i| {1158 for (inputs) |*elem, i| {
811 elem.* = try self.resolveConstString(block, assembly.kw_args.inputs[i]);1159 elem.* = try self.resolveConstString(scope, assembly.kw_args.inputs[i]);
812 }1160 }
813 for (clobbers) |*elem, i| {1161 for (clobbers) |*elem, i| {
814 elem.* = try self.resolveConstString(block, assembly.kw_args.clobbers[i]);1162 elem.* = try self.resolveConstString(scope, assembly.kw_args.clobbers[i]);
815 }1163 }
816 for (args) |*elem, i| {1164 for (args) |*elem, i| {
817 const arg = try self.resolveInst(block, assembly.kw_args.args[i]);1165 const arg = try self.resolveInst(scope, assembly.kw_args.args[i]);
818 elem.* = try self.coerce(block, Type.initTag(.usize), arg);1166 elem.* = try self.coerce(scope, Type.initTag(.usize), arg);
819 }1167 }
8201168
821 const b = try self.requireRuntimeBlock(block, assembly.base.src);1169 const b = try self.requireRuntimeBlock(scope, assembly.base.src);
822 return self.addNewInstArgs(b, assembly.base.src, return_type, Inst.Assembly, Inst.Args(Inst.Assembly){1170 return self.addNewInstArgs(b, assembly.base.src, return_type, Inst.Assembly, Inst.Args(Inst.Assembly){
823 .asm_source = asm_source,1171 .asm_source = asm_source,
824 .is_volatile = assembly.kw_args.@"volatile",1172 .is_volatile = assembly.kw_args.@"volatile",
...@@ -829,9 +1177,9 @@ const Analyze = struct {...@@ -829,9 +1177,9 @@ const Analyze = struct {
829 });1177 });
830 }1178 }
8311179
832 fn analyzeInstCmp(self: *Analyze, block: ?*Block, inst: *text.Inst.Cmp) InnerError!*Inst {1180 fn analyzeInstCmp(self: *Module, scope: *Scope, inst: *text.Inst.Cmp) InnerError!*Inst {
833 const lhs = try self.resolveInst(block, inst.positionals.lhs);1181 const lhs = try self.resolveInst(scope, inst.positionals.lhs);
834 const rhs = try self.resolveInst(block, inst.positionals.rhs);1182 const rhs = try self.resolveInst(scope, inst.positionals.rhs);
835 const op = inst.positionals.op;1183 const op = inst.positionals.op;
8361184
837 const is_equality_cmp = switch (op) {1185 const is_equality_cmp = switch (op) {
...@@ -853,7 +1201,7 @@ const Analyze = struct {...@@ -853,7 +1201,7 @@ const Analyze = struct {
853 const is_null = opt_val.isNull();1201 const is_null = opt_val.isNull();
854 return self.constBool(inst.base.src, if (op == .eq) is_null else !is_null);1202 return self.constBool(inst.base.src, if (op == .eq) is_null else !is_null);
855 }1203 }
856 const b = try self.requireRuntimeBlock(block, inst.base.src);1204 const b = try self.requireRuntimeBlock(scope, inst.base.src);
857 switch (op) {1205 switch (op) {
858 .eq => return self.addNewInstArgs(1206 .eq => return self.addNewInstArgs(
859 b,1207 b,
...@@ -874,64 +1222,64 @@ const Analyze = struct {...@@ -874,64 +1222,64 @@ const Analyze = struct {
874 } else if (is_equality_cmp and1222 } else if (is_equality_cmp and
875 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))1223 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))
876 {1224 {
877 return self.fail(inst.base.src, "TODO implement C pointer cmp", .{});1225 return self.fail(scope, inst.base.src, "TODO implement C pointer cmp", .{});
878 } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {1226 } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
879 const non_null_type = if (lhs_ty_tag == .Null) rhs.ty else lhs.ty;1227 const non_null_type = if (lhs_ty_tag == .Null) rhs.ty else lhs.ty;
880 return self.fail(inst.base.src, "comparison of '{}' with null", .{non_null_type});1228 return self.fail(scope, inst.base.src, "comparison of '{}' with null", .{non_null_type});
881 } else if (is_equality_cmp and1229 } else if (is_equality_cmp and
882 ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or1230 ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or
883 (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))1231 (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))
884 {1232 {
885 return self.fail(inst.base.src, "TODO implement equality comparison between a union's tag value and an enum literal", .{});1233 return self.fail(scope, inst.base.src, "TODO implement equality comparison between a union's tag value and an enum literal", .{});
886 } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {1234 } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {
887 if (!is_equality_cmp) {1235 if (!is_equality_cmp) {
888 return self.fail(inst.base.src, "{} operator not allowed for errors", .{@tagName(op)});1236 return self.fail(scope, inst.base.src, "{} operator not allowed for errors", .{@tagName(op)});
889 }1237 }
890 return self.fail(inst.base.src, "TODO implement equality comparison between errors", .{});1238 return self.fail(scope, inst.base.src, "TODO implement equality comparison between errors", .{});
891 } else if (lhs.ty.isNumeric() and rhs.ty.isNumeric()) {1239 } else if (lhs.ty.isNumeric() and rhs.ty.isNumeric()) {
892 // This operation allows any combination of integer and float types, regardless of the1240 // This operation allows any combination of integer and float types, regardless of the
893 // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for1241 // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for
894 // numeric types.1242 // numeric types.
895 return self.cmpNumeric(block, inst.base.src, lhs, rhs, op);1243 return self.cmpNumeric(scope, inst.base.src, lhs, rhs, op);
896 }1244 }
897 return self.fail(inst.base.src, "TODO implement more cmp analysis", .{});1245 return self.fail(scope, inst.base.src, "TODO implement more cmp analysis", .{});
898 }1246 }
8991247
900 fn analyzeInstIsNull(self: *Analyze, block: ?*Block, inst: *text.Inst.IsNull) InnerError!*Inst {1248 fn analyzeInstIsNull(self: *Module, scope: *Scope, inst: *text.Inst.IsNull) InnerError!*Inst {
901 const operand = try self.resolveInst(block, inst.positionals.operand);1249 const operand = try self.resolveInst(scope, inst.positionals.operand);
902 return self.analyzeIsNull(block, inst.base.src, operand, true);1250 return self.analyzeIsNull(scope, inst.base.src, operand, true);
903 }1251 }
9041252
905 fn analyzeInstIsNonNull(self: *Analyze, block: ?*Block, inst: *text.Inst.IsNonNull) InnerError!*Inst {1253 fn analyzeInstIsNonNull(self: *Module, scope: *Scope, inst: *text.Inst.IsNonNull) InnerError!*Inst {
906 const operand = try self.resolveInst(block, inst.positionals.operand);1254 const operand = try self.resolveInst(scope, inst.positionals.operand);
907 return self.analyzeIsNull(block, inst.base.src, operand, false);1255 return self.analyzeIsNull(scope, inst.base.src, operand, false);
908 }1256 }
9091257
910 fn analyzeInstCondBr(self: *Analyze, block: ?*Block, inst: *text.Inst.CondBr) InnerError!*Inst {1258 fn analyzeInstCondBr(self: *Module, scope: *Scope, inst: *text.Inst.CondBr) InnerError!*Inst {
911 const uncasted_cond = try self.resolveInst(block, inst.positionals.condition);1259 const uncasted_cond = try self.resolveInst(scope, inst.positionals.condition);
912 const cond = try self.coerce(block, Type.initTag(.bool), uncasted_cond);1260 const cond = try self.coerce(scope, Type.initTag(.bool), uncasted_cond);
9131261
914 if (try self.resolveDefinedValue(cond)) |cond_val| {1262 if (try self.resolveDefinedValue(cond)) |cond_val| {
915 const body = if (cond_val.toBool()) &inst.positionals.true_body else &inst.positionals.false_body;1263 const body = if (cond_val.toBool()) &inst.positionals.true_body else &inst.positionals.false_body;
916 try self.analyzeBody(block, body.*);1264 try self.analyzeBody(scope, body.*);
917 return self.constVoid(inst.base.src);1265 return self.constVoid(inst.base.src);
918 }1266 }
9191267
920 const parent_block = try self.requireRuntimeBlock(block, inst.base.src);1268 const parent_block = try self.requireRuntimeBlock(scope, inst.base.src);
9211269
922 var true_block: Block = .{1270 var true_block: Scope.Block = .{
923 .func = parent_block.func,1271 .func = parent_block.func,
924 .instructions = std.ArrayList(*Inst).init(self.allocator),1272 .instructions = .{},
925 };1273 };
926 defer true_block.instructions.deinit();1274 defer true_block.instructions.deinit();
927 try self.analyzeBody(&true_block, inst.positionals.true_body);1275 try self.analyzeBody(&true_block.base, inst.positionals.true_body);
9281276
929 var false_block: Block = .{1277 var false_block: Scope.Block = .{
930 .func = parent_block.func,1278 .func = parent_block.func,
931 .instructions = std.ArrayList(*Inst).init(self.allocator),1279 .instructions = .{},
932 };1280 };
933 defer false_block.instructions.deinit();1281 defer false_block.instructions.deinit();
934 try self.analyzeBody(&false_block, inst.positionals.false_body);1282 try self.analyzeBody(&false_block.base, inst.positionals.false_body);
9351283
936 // Copy the instruction pointers to the arena memory1284 // Copy the instruction pointers to the arena memory
937 const true_instructions = try self.arena.allocator.alloc(*Inst, true_block.instructions.items.len);1285 const true_instructions = try self.arena.allocator.alloc(*Inst, true_block.instructions.items.len);
...@@ -947,7 +1295,7 @@ const Analyze = struct {...@@ -947,7 +1295,7 @@ const Analyze = struct {
947 });1295 });
948 }1296 }
9491297
950 fn wantSafety(self: *Analyze, block: ?*Block) bool {1298 fn wantSafety(self: *Module, scope: *Scope) bool {
951 return switch (self.optimize_mode) {1299 return switch (self.optimize_mode) {
952 .Debug => true,1300 .Debug => true,
953 .ReleaseSafe => true,1301 .ReleaseSafe => true,
...@@ -956,47 +1304,47 @@ const Analyze = struct {...@@ -956,47 +1304,47 @@ const Analyze = struct {
956 };1304 };
957 }1305 }
9581306
959 fn analyzeInstUnreachable(self: *Analyze, block: ?*Block, unreach: *text.Inst.Unreachable) InnerError!*Inst {1307 fn analyzeInstUnreachable(self: *Module, scope: *Scope, unreach: *text.Inst.Unreachable) InnerError!*Inst {
960 const b = try self.requireRuntimeBlock(block, unreach.base.src);1308 const b = try self.requireRuntimeBlock(scope, unreach.base.src);
961 if (self.wantSafety(block)) {1309 if (self.wantSafety(scope)) {
962 // TODO Once we have a panic function to call, call it here instead of this.1310 // TODO Once we have a panic function to call, call it here instead of this.
963 _ = try self.addNewInstArgs(b, unreach.base.src, Type.initTag(.void), Inst.Breakpoint, {});1311 _ = try self.addNewInstArgs(b, unreach.base.src, Type.initTag(.void), Inst.Breakpoint, {});
964 }1312 }
965 return self.addNewInstArgs(b, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {});1313 return self.addNewInstArgs(b, unreach.base.src, Type.initTag(.noreturn), Inst.Unreach, {});
966 }1314 }
9671315
968 fn analyzeInstRet(self: *Analyze, block: ?*Block, inst: *text.Inst.Return) InnerError!*Inst {1316 fn analyzeInstRet(self: *Module, scope: *Scope, inst: *text.Inst.Return) InnerError!*Inst {
969 const b = try self.requireRuntimeBlock(block, inst.base.src);1317 const b = try self.requireRuntimeBlock(scope, inst.base.src);
970 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.Ret, {});1318 return self.addNewInstArgs(b, inst.base.src, Type.initTag(.noreturn), Inst.Ret, {});
971 }1319 }
9721320
973 fn analyzeBody(self: *Analyze, block: ?*Block, body: text.Module.Body) !void {1321 fn analyzeBody(self: *Module, scope: *Scope, body: text.Module.Body) !void {
974 for (body.instructions) |src_inst| {1322 for (body.instructions) |src_inst| {
975 const new_inst = self.analyzeInst(block, src_inst) catch |err| {1323 const new_inst = self.analyzeInst(scope, src_inst) catch |err| {
976 if (block) |b| {1324 if (scope.cast(Scope.Block)) |b| {
977 self.fns.items[b.func.fn_index].analysis_status = .failure;1325 self.fns.items[b.func.fn_index].analysis_status = .failure;
978 try b.func.inst_table.putNoClobber(src_inst, .{ .ptr = null });1326 try b.func.inst_table.putNoClobber(src_inst, .{ .ptr = null });
979 }1327 }
980 return err;1328 return err;
981 };1329 };
982 if (block) |b| try b.func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst });1330 if (scope.cast(Scope.Block)) |b| try b.func.inst_table.putNoClobber(src_inst, .{ .ptr = new_inst });
983 }1331 }
984 }1332 }
9851333
986 fn analyzeIsNull(1334 fn analyzeIsNull(
987 self: *Analyze,1335 self: *Module,
988 block: ?*Block,1336 scope: *Scope,
989 src: usize,1337 src: usize,
990 operand: *Inst,1338 operand: *Inst,
991 invert_logic: bool,1339 invert_logic: bool,
992 ) InnerError!*Inst {1340 ) InnerError!*Inst {
993 return self.fail(src, "TODO implement analysis of isnull and isnotnull", .{});1341 return self.fail(scope, src, "TODO implement analysis of isnull and isnotnull", .{});
994 }1342 }
9951343
996 /// Asserts that lhs and rhs types are both numeric.1344 /// Asserts that lhs and rhs types are both numeric.
997 fn cmpNumeric(1345 fn cmpNumeric(
998 self: *Analyze,1346 self: *Module,
999 block: ?*Block,1347 scope: *Scope,
1000 src: usize,1348 src: usize,
1001 lhs: *Inst,1349 lhs: *Inst,
1002 rhs: *Inst,1350 rhs: *Inst,
...@@ -1010,14 +1358,14 @@ const Analyze = struct {...@@ -1010,14 +1358,14 @@ const Analyze = struct {
10101358
1011 if (lhs_ty_tag == .Vector and rhs_ty_tag == .Vector) {1359 if (lhs_ty_tag == .Vector and rhs_ty_tag == .Vector) {
1012 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {1360 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
1013 return self.fail(src, "vector length mismatch: {} and {}", .{1361 return self.fail(scope, src, "vector length mismatch: {} and {}", .{
1014 lhs.ty.arrayLen(),1362 lhs.ty.arrayLen(),
1015 rhs.ty.arrayLen(),1363 rhs.ty.arrayLen(),
1016 });1364 });
1017 }1365 }
1018 return self.fail(src, "TODO implement support for vectors in cmpNumeric", .{});1366 return self.fail(scope, src, "TODO implement support for vectors in cmpNumeric", .{});
1019 } else if (lhs_ty_tag == .Vector or rhs_ty_tag == .Vector) {1367 } else if (lhs_ty_tag == .Vector or rhs_ty_tag == .Vector) {
1020 return self.fail(src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{1368 return self.fail(scope, src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{
1021 lhs.ty,1369 lhs.ty,
1022 rhs.ty,1370 rhs.ty,
1023 });1371 });
...@@ -1036,7 +1384,7 @@ const Analyze = struct {...@@ -1036,7 +1384,7 @@ const Analyze = struct {
1036 // of this function if we don't need to.1384 // of this function if we don't need to.
10371385
1038 // It must be a runtime comparison.1386 // It must be a runtime comparison.
1039 const b = try self.requireRuntimeBlock(block, src);1387 const b = try self.requireRuntimeBlock(scope, src);
1040 // For floats, emit a float comparison instruction.1388 // For floats, emit a float comparison instruction.
1041 const lhs_is_float = switch (lhs_ty_tag) {1389 const lhs_is_float = switch (lhs_ty_tag) {
1042 .Float, .ComptimeFloat => true,1390 .Float, .ComptimeFloat => true,
...@@ -1054,14 +1402,14 @@ const Analyze = struct {...@@ -1054,14 +1402,14 @@ const Analyze = struct {
1054 } else if (rhs_ty_tag == .ComptimeFloat) {1402 } else if (rhs_ty_tag == .ComptimeFloat) {
1055 break :x lhs.ty;1403 break :x lhs.ty;
1056 }1404 }
1057 if (lhs.ty.floatBits(self.target) >= rhs.ty.floatBits(self.target)) {1405 if (lhs.ty.floatBits(self.target()) >= rhs.ty.floatBits(self.target())) {
1058 break :x lhs.ty;1406 break :x lhs.ty;
1059 } else {1407 } else {
1060 break :x rhs.ty;1408 break :x rhs.ty;
1061 }1409 }
1062 };1410 };
1063 const casted_lhs = try self.coerce(block, dest_type, lhs);1411 const casted_lhs = try self.coerce(scope, dest_type, lhs);
1064 const casted_rhs = try self.coerce(block, dest_type, rhs);1412 const casted_rhs = try self.coerce(scope, dest_type, rhs);
1065 return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, Inst.Args(Inst.Cmp){1413 return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, Inst.Args(Inst.Cmp){
1066 .lhs = casted_lhs,1414 .lhs = casted_lhs,
1067 .rhs = casted_rhs,1415 .rhs = casted_rhs,
...@@ -1117,7 +1465,7 @@ const Analyze = struct {...@@ -1117,7 +1465,7 @@ const Analyze = struct {
1117 } else if (lhs_is_float) {1465 } else if (lhs_is_float) {
1118 dest_float_type = lhs.ty;1466 dest_float_type = lhs.ty;
1119 } else {1467 } else {
1120 const int_info = lhs.ty.intInfo(self.target);1468 const int_info = lhs.ty.intInfo(self.target());
1121 lhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);1469 lhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);
1122 }1470 }
11231471
...@@ -1152,19 +1500,19 @@ const Analyze = struct {...@@ -1152,19 +1500,19 @@ const Analyze = struct {
1152 } else if (rhs_is_float) {1500 } else if (rhs_is_float) {
1153 dest_float_type = rhs.ty;1501 dest_float_type = rhs.ty;
1154 } else {1502 } else {
1155 const int_info = rhs.ty.intInfo(self.target);1503 const int_info = rhs.ty.intInfo(self.target());
1156 rhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);1504 rhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);
1157 }1505 }
11581506
1159 const dest_type = if (dest_float_type) |ft| ft else blk: {1507 const dest_type = if (dest_float_type) |ft| ft else blk: {
1160 const max_bits = std.math.max(lhs_bits, rhs_bits);1508 const max_bits = std.math.max(lhs_bits, rhs_bits);
1161 const casted_bits = std.math.cast(u16, max_bits) catch |err| switch (err) {1509 const casted_bits = std.math.cast(u16, max_bits) catch |err| switch (err) {
1162 error.Overflow => return self.fail(src, "{} exceeds maximum integer bit count", .{max_bits}),1510 error.Overflow => return self.fail(scope, src, "{} exceeds maximum integer bit count", .{max_bits}),
1163 };1511 };
1164 break :blk try self.makeIntType(dest_int_is_signed, casted_bits);1512 break :blk try self.makeIntType(dest_int_is_signed, casted_bits);
1165 };1513 };
1166 const casted_lhs = try self.coerce(block, dest_type, lhs);1514 const casted_lhs = try self.coerce(scope, dest_type, lhs);
1167 const casted_rhs = try self.coerce(block, dest_type, lhs);1515 const casted_rhs = try self.coerce(scope, dest_type, lhs);
11681516
1169 return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, Inst.Args(Inst.Cmp){1517 return self.addNewInstArgs(b, src, dest_type, Inst.Cmp, Inst.Args(Inst.Cmp){
1170 .lhs = casted_lhs,1518 .lhs = casted_lhs,
...@@ -1173,7 +1521,7 @@ const Analyze = struct {...@@ -1173,7 +1521,7 @@ const Analyze = struct {
1173 });1521 });
1174 }1522 }
11751523
1176 fn makeIntType(self: *Analyze, signed: bool, bits: u16) !Type {1524 fn makeIntType(self: *Module, signed: bool, bits: u16) !Type {
1177 if (signed) {1525 if (signed) {
1178 const int_payload = try self.arena.allocator.create(Type.Payload.IntSigned);1526 const int_payload = try self.arena.allocator.create(Type.Payload.IntSigned);
1179 int_payload.* = .{ .bits = bits };1527 int_payload.* = .{ .bits = bits };
...@@ -1185,14 +1533,14 @@ const Analyze = struct {...@@ -1185,14 +1533,14 @@ const Analyze = struct {
1185 }1533 }
1186 }1534 }
11871535
1188 fn coerce(self: *Analyze, block: ?*Block, dest_type: Type, inst: *Inst) !*Inst {1536 fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
1189 // If the types are the same, we can return the operand.1537 // If the types are the same, we can return the operand.
1190 if (dest_type.eql(inst.ty))1538 if (dest_type.eql(inst.ty))
1191 return inst;1539 return inst;
11921540
1193 const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);1541 const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);
1194 if (in_memory_result == .ok) {1542 if (in_memory_result == .ok) {
1195 return self.bitcast(block, dest_type, inst);1543 return self.bitcast(scope, dest_type, inst);
1196 }1544 }
11971545
1198 // *[N]T to []T1546 // *[N]T to []T
...@@ -1212,55 +1560,61 @@ const Analyze = struct {...@@ -1212,55 +1560,61 @@ const Analyze = struct {
1212 if (inst.ty.zigTypeTag() == .ComptimeInt and dest_type.zigTypeTag() == .Int) {1560 if (inst.ty.zigTypeTag() == .ComptimeInt and dest_type.zigTypeTag() == .Int) {
1213 // The representation is already correct; we only need to make sure it fits in the destination type.1561 // The representation is already correct; we only need to make sure it fits in the destination type.
1214 const val = inst.value().?; // comptime_int always has comptime known value1562 const val = inst.value().?; // comptime_int always has comptime known value
1215 if (!val.intFitsInType(dest_type, self.target)) {1563 if (!val.intFitsInType(dest_type, self.target())) {
1216 return self.fail(inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });1564 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
1217 }1565 }
1218 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });1566 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });
1219 }1567 }
12201568
1221 // integer widening1569 // integer widening
1222 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {1570 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
1223 const src_info = inst.ty.intInfo(self.target);1571 const src_info = inst.ty.intInfo(self.target());
1224 const dst_info = dest_type.intInfo(self.target);1572 const dst_info = dest_type.intInfo(self.target());
1225 if (src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) {1573 if (src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) {
1226 if (inst.value()) |val| {1574 if (inst.value()) |val| {
1227 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });1575 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });
1228 } else {1576 } else {
1229 return self.fail(inst.src, "TODO implement runtime integer widening", .{});1577 return self.fail(scope, inst.src, "TODO implement runtime integer widening", .{});
1230 }1578 }
1231 } else {1579 } else {
1232 return self.fail(inst.src, "TODO implement more int widening {} to {}", .{ inst.ty, dest_type });1580 return self.fail(scope, inst.src, "TODO implement more int widening {} to {}", .{ inst.ty, dest_type });
1233 }1581 }
1234 }1582 }
12351583
1236 return self.fail(inst.src, "TODO implement type coercion from {} to {}", .{ inst.ty, dest_type });1584 return self.fail(scope, inst.src, "TODO implement type coercion from {} to {}", .{ inst.ty, dest_type });
1237 }1585 }
12381586
1239 fn bitcast(self: *Analyze, block: ?*Block, dest_type: Type, inst: *Inst) !*Inst {1587 fn bitcast(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
1240 if (inst.value()) |val| {1588 if (inst.value()) |val| {
1241 // Keep the comptime Value representation; take the new type.1589 // Keep the comptime Value representation; take the new type.
1242 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });1590 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });
1243 }1591 }
1244 // TODO validate the type size and other compile errors1592 // TODO validate the type size and other compile errors
1245 const b = try self.requireRuntimeBlock(block, inst.src);1593 const b = try self.requireRuntimeBlock(scope, inst.src);
1246 return self.addNewInstArgs(b, inst.src, dest_type, Inst.BitCast, Inst.Args(Inst.BitCast){ .operand = inst });1594 return self.addNewInstArgs(b, inst.src, dest_type, Inst.BitCast, Inst.Args(Inst.BitCast){ .operand = inst });
1247 }1595 }
12481596
1249 fn coerceArrayPtrToSlice(self: *Analyze, dest_type: Type, inst: *Inst) !*Inst {1597 fn coerceArrayPtrToSlice(self: *Module, dest_type: Type, inst: *Inst) !*Inst {
1250 if (inst.value()) |val| {1598 if (inst.value()) |val| {
1251 // The comptime Value representation is compatible with both types.1599 // The comptime Value representation is compatible with both types.
1252 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });1600 return self.constInst(inst.src, .{ .ty = dest_type, .val = val });
1253 }1601 }
1254 return self.fail(inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});1602 return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});
1255 }1603 }
12561604
1257 fn fail(self: *Analyze, src: usize, comptime format: []const u8, args: var) InnerError {1605 fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: var) InnerError {
1258 @setCold(true);1606 @setCold(true);
1259 const msg = try std.fmt.allocPrint(&self.arena.allocator, format, args);1607 const err_msg = ErrorMsg{
1260 (try self.errors.addOne()).* = .{
1261 .byte_offset = src,1608 .byte_offset = src,
1262 .msg = msg,1609 .msg = try std.fmt.allocPrint(self.allocator, format, args),
1263 };1610 };
1611 if (scope.cast(Scope.Block)) |block| {
1612 block.func.analysis = .{ .failure = err_msg };
1613 } else if (scope.cast(Scope.Decl)) |scope_decl| {
1614 scope_decl.decl.analysis = .{ .failure = err_msg };
1615 } else {
1616 unreachable;
1617 }
1264 return error.AnalysisFail;1618 return error.AnalysisFail;
1265 }1619 }
12661620
...@@ -1279,6 +1633,11 @@ const Analyze = struct {...@@ -1279,6 +1633,11 @@ const Analyze = struct {
1279 }1633 }
1280};1634};
12811635
1636pub const ErrorMsg = struct {
1637 byte_offset: usize,
1638 msg: []const u8,
1639};
1640
1282pub fn main() anyerror!void {1641pub fn main() anyerror!void {
1283 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);1642 var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
1284 defer arena.deinit();1643 defer arena.deinit();
...@@ -1288,63 +1647,68 @@ pub fn main() anyerror!void {...@@ -1288,63 +1647,68 @@ pub fn main() anyerror!void {
1288 defer std.process.argsFree(allocator, args);1647 defer std.process.argsFree(allocator, args);
12891648
1290 const src_path = args[1];1649 const src_path = args[1];
1650 const bin_path = args[2];
1291 const debug_error_trace = true;1651 const debug_error_trace = true;
12921652 const output_zir = true;
1293 const source = try std.fs.cwd().readFileAllocOptions(allocator, src_path, std.math.maxInt(u32), 1, 0);
1294 defer allocator.free(source);
1295
1296 var zir_module = try text.parse(allocator, source);
1297 defer zir_module.deinit(allocator);
1298
1299 if (zir_module.errors.len != 0) {
1300 for (zir_module.errors) |err_msg| {
1301 const loc = std.zig.findLineColumn(source, err_msg.byte_offset);
1302 std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
1303 }
1304 if (debug_error_trace) return error.ParseFailure;
1305 std.process.exit(1);
1306 }
13071653
1308 const native_info = try std.zig.system.NativeTargetInfo.detect(allocator, .{});1654 const native_info = try std.zig.system.NativeTargetInfo.detect(allocator, .{});
13091655
1310 var analyzed_module = try analyze(allocator, zir_module, .{1656 var bin_file = try link.openBinFilePath(allocator, std.fs.cwd(), bin_path, .{
1311 .target = native_info.target,1657 .target = native_info.target,
1312 .output_mode = .Obj,1658 .output_mode = .Exe,
1313 .link_mode = .Static,1659 .link_mode = .Static,
1314 .optimize_mode = .Debug,1660 .object_format = options.object_format orelse native_info.target.getObjectFormat(),
1315 });1661 });
1316 defer analyzed_module.deinit(allocator);1662 defer bin_file.deinit(allocator);
1663
1664 var module = blk: {
1665 const root_pkg = try Package.create(allocator, std.fs.cwd(), ".", src_path);
1666 errdefer root_pkg.destroy();
1667
1668 const root_scope = try allocator.create(Module.Scope.ZIRModule);
1669 errdefer allocator.destroy(root_scope);
1670 root_scope.* = .{
1671 .sub_file_path = root_pkg.root_src_path,
1672 .contents = .unloaded,
1673 };
13171674
1318 if (analyzed_module.errors.len != 0) {1675 break :blk Module{
1319 for (analyzed_module.errors) |err_msg| {1676 .allocator = allocator,
1320 const loc = std.zig.findLineColumn(source, err_msg.byte_offset);1677 .root_pkg = root_pkg,
1321 std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });1678 .root_scope = root_scope,
1679 .bin_file = &bin_file,
1680 .optimize_mode = .Debug,
1681 .decl_table = std.AutoHashMap(Decl.Hash, *Decl).init(allocator),
1682 };
1683 };
1684 defer module.deinit();
1685
1686 try module.update();
1687
1688 const errors = try module.getAllErrorsAlloc();
1689 defer errors.deinit();
1690
1691 if (errors.list.len != 0) {
1692 for (errors.list) |full_err_msg| {
1693 std.debug.warn("{}:{}:{}: error: {}\n", .{
1694 full_err_msg.src_path,
1695 full_err_msg.line + 1,
1696 full_err_msg.column + 1,
1697 full_err_msg.msg,
1698 });
1322 }1699 }
1323 if (debug_error_trace) return error.AnalysisFail;1700 if (debug_error_trace) return error.AnalysisFail;
1324 std.process.exit(1);1701 std.process.exit(1);
1325 }1702 }
13261703
1327 const output_zir = true;
1328 if (output_zir) {1704 if (output_zir) {
1329 var new_zir_module = try text.emit_zir(allocator, analyzed_module);1705 var new_zir_module = try text.emit_zir(allocator, module);
1330 defer new_zir_module.deinit(allocator);1706 defer new_zir_module.deinit(allocator);
13311707
1332 var bos = std.io.bufferedOutStream(std.io.getStdOut().outStream());1708 var bos = std.io.bufferedOutStream(std.io.getStdOut().outStream());
1333 try new_zir_module.writeToStream(allocator, bos.outStream());1709 try new_zir_module.writeToStream(allocator, bos.outStream());
1334 try bos.flush();1710 try bos.flush();
1335 }1711 }
1336
1337 const link = @import("link.zig");
1338 var result = try link.updateFilePath(allocator, analyzed_module, std.fs.cwd(), "zir.o");
1339 defer result.deinit(allocator);
1340 if (result.errors.len != 0) {
1341 for (result.errors) |err_msg| {
1342 const loc = std.zig.findLineColumn(source, err_msg.byte_offset);
1343 std.debug.warn("{}:{}:{}: error: {}\n", .{ src_path, loc.line + 1, loc.column + 1, err_msg.msg });
1344 }
1345 if (debug_error_trace) return error.LinkFailure;
1346 std.process.exit(1);
1347 }
1348}1712}
13491713
1350// Performance optimization ideas:1714// Performance optimization ideas:
src-self-hosted/ir/text.zig+125-57
...@@ -16,10 +16,16 @@ pub const Inst = struct {...@@ -16,10 +16,16 @@ pub const Inst = struct {
16 tag: Tag,16 tag: Tag,
17 /// Byte offset into the source.17 /// Byte offset into the source.
18 src: usize,18 src: usize,
19 name: []const u8,
1920
20 /// These names are used directly as the instruction names in the text format.21 /// These names are used directly as the instruction names in the text format.
21 pub const Tag = enum {22 pub const Tag = enum {
22 breakpoint,23 breakpoint,
24 call,
25 /// Represents a reference to a global decl by name.
26 /// Canonicalized ZIR will not have any of these. The
27 /// syntax `@foo` is equivalent to `declref("foo")`.
28 declref,
23 str,29 str,
24 int,30 int,
25 ptrtoint,31 ptrtoint,
...@@ -46,6 +52,8 @@ pub const Inst = struct {...@@ -46,6 +52,8 @@ pub const Inst = struct {
46 pub fn TagToType(tag: Tag) type {52 pub fn TagToType(tag: Tag) type {
47 return switch (tag) {53 return switch (tag) {
48 .breakpoint => Breakpoint,54 .breakpoint => Breakpoint,
55 .call => Call,
56 .declref => DeclRef,
49 .str => Str,57 .str => Str,
50 .int => Int,58 .int => Int,
51 .ptrtoint => PtrToInt,59 .ptrtoint => PtrToInt,
...@@ -85,6 +93,29 @@ pub const Inst = struct {...@@ -85,6 +93,29 @@ pub const Inst = struct {
85 kw_args: struct {},93 kw_args: struct {},
86 };94 };
8795
96 pub const Call = struct {
97 pub const base_tag = Tag.call;
98 base: Inst,
99
100 positionals: struct {
101 func: *Inst,
102 args: []*Inst,
103 },
104 kw_args: struct {
105 modifier: std.builtin.CallOptions.Modifier = .auto,
106 },
107 };
108
109 pub const DeclRef = struct {
110 pub const base_tag = Tag.declref;
111 base: Inst,
112
113 positionals: struct {
114 name: *Inst,
115 },
116 kw_args: struct {},
117 };
118
88 pub const Str = struct {119 pub const Str = struct {
89 pub const base_tag = Tag.str;120 pub const base_tag = Tag.str;
90 base: Inst,121 base: Inst,
...@@ -212,55 +243,55 @@ pub const Inst = struct {...@@ -212,55 +243,55 @@ pub const Inst = struct {
212 kw_args: struct {},243 kw_args: struct {},
213244
214 pub const BuiltinType = enum {245 pub const BuiltinType = enum {
215 @"isize",246 isize,
216 @"usize",247 usize,
217 @"c_short",248 c_short,
218 @"c_ushort",249 c_ushort,
219 @"c_int",250 c_int,
220 @"c_uint",251 c_uint,
221 @"c_long",252 c_long,
222 @"c_ulong",253 c_ulong,
223 @"c_longlong",254 c_longlong,
224 @"c_ulonglong",255 c_ulonglong,
225 @"c_longdouble",256 c_longdouble,
226 @"c_void",257 c_void,
227 @"f16",258 f16,
228 @"f32",259 f32,
229 @"f64",260 f64,
230 @"f128",261 f128,
231 @"bool",262 bool,
232 @"void",263 void,
233 @"noreturn",264 noreturn,
234 @"type",265 type,
235 @"anyerror",266 anyerror,
236 @"comptime_int",267 comptime_int,
237 @"comptime_float",268 comptime_float,
238269
239 fn toType(self: BuiltinType) Type {270 fn toType(self: BuiltinType) Type {
240 return switch (self) {271 return switch (self) {
241 .@"isize" => Type.initTag(.@"isize"),272 .isize => Type.initTag(.isize),
242 .@"usize" => Type.initTag(.@"usize"),273 .usize => Type.initTag(.usize),
243 .@"c_short" => Type.initTag(.@"c_short"),274 .c_short => Type.initTag(.c_short),
244 .@"c_ushort" => Type.initTag(.@"c_ushort"),275 .c_ushort => Type.initTag(.c_ushort),
245 .@"c_int" => Type.initTag(.@"c_int"),276 .c_int => Type.initTag(.c_int),
246 .@"c_uint" => Type.initTag(.@"c_uint"),277 .c_uint => Type.initTag(.c_uint),
247 .@"c_long" => Type.initTag(.@"c_long"),278 .c_long => Type.initTag(.c_long),
248 .@"c_ulong" => Type.initTag(.@"c_ulong"),279 .c_ulong => Type.initTag(.c_ulong),
249 .@"c_longlong" => Type.initTag(.@"c_longlong"),280 .c_longlong => Type.initTag(.c_longlong),
250 .@"c_ulonglong" => Type.initTag(.@"c_ulonglong"),281 .c_ulonglong => Type.initTag(.c_ulonglong),
251 .@"c_longdouble" => Type.initTag(.@"c_longdouble"),282 .c_longdouble => Type.initTag(.c_longdouble),
252 .@"c_void" => Type.initTag(.@"c_void"),283 .c_void => Type.initTag(.c_void),
253 .@"f16" => Type.initTag(.@"f16"),284 .f16 => Type.initTag(.f16),
254 .@"f32" => Type.initTag(.@"f32"),285 .f32 => Type.initTag(.f32),
255 .@"f64" => Type.initTag(.@"f64"),286 .f64 => Type.initTag(.f64),
256 .@"f128" => Type.initTag(.@"f128"),287 .f128 => Type.initTag(.f128),
257 .@"bool" => Type.initTag(.@"bool"),288 .bool => Type.initTag(.bool),
258 .@"void" => Type.initTag(.@"void"),289 .void => Type.initTag(.void),
259 .@"noreturn" => Type.initTag(.@"noreturn"),290 .noreturn => Type.initTag(.noreturn),
260 .@"type" => Type.initTag(.@"type"),291 .type => Type.initTag(.type),
261 .@"anyerror" => Type.initTag(.@"anyerror"),292 .anyerror => Type.initTag(.anyerror),
262 .@"comptime_int" => Type.initTag(.@"comptime_int"),293 .comptime_int => Type.initTag(.comptime_int),
263 .@"comptime_float" => Type.initTag(.@"comptime_float"),294 .comptime_float => Type.initTag(.comptime_float),
264 };295 };
265 }296 }
266 };297 };
...@@ -376,7 +407,7 @@ pub const ErrorMsg = struct {...@@ -376,7 +407,7 @@ pub const ErrorMsg = struct {
376pub const Module = struct {407pub const Module = struct {
377 decls: []*Inst,408 decls: []*Inst,
378 errors: []ErrorMsg,409 errors: []ErrorMsg,
379 arena: std.heap.ArenaAllocator,410 arena: std.heap.ArenaAllocator.State,
380411
381 pub const Body = struct {412 pub const Body = struct {
382 instructions: []*Inst,413 instructions: []*Inst,
...@@ -385,7 +416,7 @@ pub const Module = struct {...@@ -385,7 +416,7 @@ pub const Module = struct {
385 pub fn deinit(self: *Module, allocator: *Allocator) void {416 pub fn deinit(self: *Module, allocator: *Allocator) void {
386 allocator.free(self.decls);417 allocator.free(self.decls);
387 allocator.free(self.errors);418 allocator.free(self.errors);
388 self.arena.deinit();419 self.arena.promote(allocator).deinit();
389 self.* = undefined;420 self.* = undefined;
390 }421 }
391422
...@@ -431,6 +462,7 @@ pub const Module = struct {...@@ -431,6 +462,7 @@ pub const Module = struct {
431 // TODO I tried implementing this with an inline for loop and hit a compiler bug462 // TODO I tried implementing this with an inline for loop and hit a compiler bug
432 switch (decl.tag) {463 switch (decl.tag) {
433 .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, decl, inst_table),464 .breakpoint => return self.writeInstToStreamGeneric(stream, .breakpoint, decl, inst_table),
465 .call => return self.writeInstToStreamGeneric(stream, .call, decl, inst_table),
434 .str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table),466 .str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table),
435 .int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table),467 .int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table),
436 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table),468 .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table),
...@@ -543,9 +575,9 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module...@@ -543,9 +575,9 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module
543 .arena = std.heap.ArenaAllocator.init(allocator),575 .arena = std.heap.ArenaAllocator.init(allocator),
544 .i = 0,576 .i = 0,
545 .source = source,577 .source = source,
546 .decls = std.ArrayList(*Inst).init(allocator),
547 .errors = std.ArrayList(ErrorMsg).init(allocator),
548 .global_name_map = &global_name_map,578 .global_name_map = &global_name_map,
579 .errors = .{},
580 .decls = .{},
549 };581 };
550 errdefer parser.arena.deinit();582 errdefer parser.arena.deinit();
551583
...@@ -555,10 +587,11 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module...@@ -555,10 +587,11 @@ pub fn parse(allocator: *Allocator, source: [:0]const u8) Allocator.Error!Module
555 },587 },
556 else => |e| return e,588 else => |e| return e,
557 };589 };
590
558 return Module{591 return Module{
559 .decls = parser.decls.toOwnedSlice(),592 .decls = parser.decls.toOwnedSlice(allocator),
560 .errors = parser.errors.toOwnedSlice(),593 .errors = parser.errors.toOwnedSlice(allocator),
561 .arena = parser.arena,594 .arena = parser.arena.state,
562 };595 };
563}596}
564597
...@@ -567,8 +600,8 @@ const Parser = struct {...@@ -567,8 +600,8 @@ const Parser = struct {
567 arena: std.heap.ArenaAllocator,600 arena: std.heap.ArenaAllocator,
568 i: usize,601 i: usize,
569 source: [:0]const u8,602 source: [:0]const u8,
570 errors: std.ArrayList(ErrorMsg),603 errors: std.ArrayListUnmanaged(ErrorMsg),
571 decls: std.ArrayList(*Inst),604 decls: std.ArrayListUnmanaged(*Inst),
572 global_name_map: *std.StringHashMap(usize),605 global_name_map: *std.StringHashMap(usize),
573606
574 const Body = struct {607 const Body = struct {
...@@ -893,8 +926,25 @@ const Parser = struct {...@@ -893,8 +926,25 @@ const Parser = struct {
893 const ident = self.source[name_start..self.i];926 const ident = self.source[name_start..self.i];
894 const kv = map.get(ident) orelse {927 const kv = map.get(ident) orelse {
895 const bad_name = self.source[name_start - 1 .. self.i];928 const bad_name = self.source[name_start - 1 .. self.i];
896 self.i = name_start - 1;929 const src = name_start - 1;
897 return self.fail("unrecognized identifier: {}", .{bad_name});930 if (local_ref) {
931 self.i = src;
932 return self.fail("unrecognized identifier: {}", .{bad_name});
933 } else {
934 const name = try self.arena.allocator.create(Inst.Str);
935 name.* = .{
936 .base = .{ .src = src, .tag = Inst.Str.base_tag },
937 .positionals = .{ .bytes = ident },
938 .kw_args = .{},
939 };
940 const declref = try self.arena.allocator.create(Inst.DeclRef);
941 declref.* = .{
942 .base = .{ .src = src, .tag = Inst.DeclRef.base_tag },
943 .positionals = .{ .name = &name.base },
944 .kw_args = .{},
945 };
946 return &declref.base;
947 }
898 };948 };
899 if (local_ref) {949 if (local_ref) {
900 return body_ctx.?.instructions.items[kv.value];950 return body_ctx.?.instructions.items[kv.value];
...@@ -1065,6 +1115,24 @@ const EmitZIR = struct {...@@ -1065,6 +1115,24 @@ const EmitZIR = struct {
1065 for (body.instructions) |inst| {1115 for (body.instructions) |inst| {
1066 const new_inst = switch (inst.tag) {1116 const new_inst = switch (inst.tag) {
1067 .breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),1117 .breakpoint => try self.emitTrivial(inst.src, Inst.Breakpoint),
1118 .call => blk: {
1119 const old_inst = inst.cast(ir.Inst.Call).?;
1120 const new_inst = try self.arena.allocator.create(Inst.Call);
1121
1122 const args = try self.arena.allocator.alloc(*Inst, old_inst.args.args.len);
1123 for (args) |*elem, i| {
1124 elem.* = try self.resolveInst(inst_table, old_inst.args.args[i]);
1125 }
1126 new_inst.* = .{
1127 .base = .{ .src = inst.src, .tag = Inst.Call.base_tag },
1128 .positionals = .{
1129 .func = try self.resolveInst(inst_table, old_inst.args.func),
1130 .args = args,
1131 },
1132 .kw_args = .{},
1133 };
1134 break :blk &new_inst.base;
1135 },
1068 .unreach => try self.emitTrivial(inst.src, Inst.Unreachable),1136 .unreach => try self.emitTrivial(inst.src, Inst.Unreachable),
1069 .ret => try self.emitTrivial(inst.src, Inst.Return),1137 .ret => try self.emitTrivial(inst.src, Inst.Return),
1070 .constant => unreachable, // excluded from function bodies1138 .constant => unreachable, // excluded from function bodies
src-self-hosted/libc_installation.zig-1
...@@ -1,6 +1,5 @@...@@ -1,6 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const util = @import("util.zig");
4const Target = std.Target;3const Target = std.Target;
5const fs = std.fs;4const fs = std.fs;
6const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
src-self-hosted/link.zig+356-224
...@@ -9,50 +9,65 @@ const codegen = @import("codegen.zig");...@@ -9,50 +9,65 @@ const codegen = @import("codegen.zig");
99
10const default_entry_addr = 0x8000000;10const default_entry_addr = 0x8000000;
1111
12pub const ErrorMsg = struct {12pub const Options = struct {
13 byte_offset: usize,13 target: std.Target,
14 msg: []const u8,14 output_mode: std.builtin.OutputMode,
15};15 link_mode: std.builtin.LinkMode,
1616 object_format: std.builtin.ObjectFormat,
17pub const Result = struct {17 /// Used for calculating how much space to reserve for symbols in case the binary file
18 errors: []ErrorMsg,18 /// does not already have a symbol table.
1919 symbol_count_hint: u64 = 32,
20 pub fn deinit(self: *Result, allocator: *mem.Allocator) void {20 /// Used for calculating how much space to reserve for executable program code in case
21 for (self.errors) |err| {21 /// the binary file deos not already have such a section.
22 allocator.free(err.msg);22 program_code_size_hint: u64 = 256 * 1024,
23 }
24 allocator.free(self.errors);
25 self.* = undefined;
26 }
27};23};
2824
29/// Attempts incremental linking, if the file already exists.25/// Attempts incremental linking, if the file already exists.
30/// If incremental linking fails, falls back to truncating the file and rewriting it.26/// If incremental linking fails, falls back to truncating the file and rewriting it.
31/// A malicious file is detected as incremental link failure and does not cause Illegal Behavior.27/// A malicious file is detected as incremental link failure and does not cause Illegal Behavior.
32/// This operation is not atomic.28/// This operation is not atomic.
33pub fn updateFilePath(29pub fn openBinFilePath(
34 allocator: *Allocator,30 allocator: *Allocator,
35 module: ir.Module,
36 dir: fs.Dir,31 dir: fs.Dir,
37 sub_path: []const u8,32 sub_path: []const u8,
38) !Result {33 options: Options,
39 const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(module) });34) !ElfFile {
35 const file = try dir.createFile(sub_path, .{ .truncate = false, .read = true, .mode = determineMode(options) });
40 defer file.close();36 defer file.close();
4137
42 return updateFile(allocator, module, file);38 return openBinFile(allocator, file, options);
43}39}
4440
45/// Atomically overwrites the old file, if present.41/// Atomically overwrites the old file, if present.
46pub fn writeFilePath(42pub fn writeFilePath(
47 allocator: *Allocator,43 allocator: *Allocator,
48 module: ir.Module,
49 dir: fs.Dir,44 dir: fs.Dir,
50 sub_path: []const u8,45 sub_path: []const u8,
51) !Result {46 module: ir.Module,
52 const af = try dir.atomicFile(sub_path, .{ .mode = determineMode(module) });47 errors: *std.ArrayList(ir.ErrorMsg),
48) !void {
49 const options: Options = .{
50 .target = module.target,
51 .output_mode = module.output_mode,
52 .link_mode = module.link_mode,
53 .object_format = module.object_format,
54 .symbol_count_hint = module.decls.items.len,
55 };
56 const af = try dir.atomicFile(sub_path, .{ .mode = determineMode(options) });
53 defer af.deinit();57 defer af.deinit();
5458
55 const result = try writeFile(allocator, module, af.file);59 const elf_file = try createElfFile(allocator, af.file, options);
60 for (module.decls.items) |decl| {
61 try elf_file.updateDecl(module, decl, errors);
62 }
63 try elf_file.flush();
64 if (elf_file.error_flags.no_entry_point_found) {
65 try errors.ensureCapacity(errors.items.len + 1);
66 errors.appendAssumeCapacity(.{
67 .byte_offset = 0,
68 .msg = try std.fmt.allocPrint(errors.allocator, "no entry point found", .{}),
69 });
70 }
56 try af.finish();71 try af.finish();
57 return result;72 return result;
58}73}
...@@ -62,49 +77,65 @@ pub fn writeFilePath(...@@ -62,49 +77,65 @@ pub fn writeFilePath(
62/// Returns an error if `file` is not already open with +read +write +seek abilities.77/// Returns an error if `file` is not already open with +read +write +seek abilities.
63/// A malicious file is detected as incremental link failure and does not cause Illegal Behavior.78/// A malicious file is detected as incremental link failure and does not cause Illegal Behavior.
64/// This operation is not atomic.79/// This operation is not atomic.
65pub fn updateFile(allocator: *Allocator, module: ir.Module, file: fs.File) !Result {80pub fn openBinFile(allocator: *Allocator, file: fs.File, options: Options) !ElfFile {
66 return updateFileInner(allocator, module, file) catch |err| switch (err) {81 return openBinFileInner(allocator, file, options) catch |err| switch (err) {
67 error.IncrFailed => {82 error.IncrFailed => {
68 return writeFile(allocator, module, file);83 return createElfFile(allocator, file, options);
69 },84 },
70 else => |e| return e,85 else => |e| return e,
71 };86 };
72}87}
7388
74const Update = struct {89pub const ElfFile = struct {
90 allocator: *Allocator,
75 file: fs.File,91 file: fs.File,
76 module: *const ir.Module,92 options: Options,
93 ptr_width: enum { p32, p64 },
7794
78 /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.95 /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
79 /// Same order as in the file.96 /// Same order as in the file.
80 sections: std.ArrayList(elf.Elf64_Shdr),97 sections: std.ArrayListUnmanaged(elf.Elf64_Shdr) = .{},
81 shdr_table_offset: ?u64,98 shdr_table_offset: ?u64 = null,
8299
83 /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.100 /// Stored in native-endian format, depending on target endianness needs to be bswapped on read/write.
84 /// Same order as in the file.101 /// Same order as in the file.
85 program_headers: std.ArrayList(elf.Elf64_Phdr),102 program_headers: std.ArrayListUnmanaged(elf.Elf64_Phdr) = .{},
86 phdr_table_offset: ?u64,103 phdr_table_offset: ?u64 = null,
87 /// The index into the program headers of a PT_LOAD program header with Read and Execute flags104 /// The index into the program headers of a PT_LOAD program header with Read and Execute flags
88 phdr_load_re_index: ?u16,105 phdr_load_re_index: ?u16 = null,
89 entry_addr: ?u64,106 entry_addr: ?u64 = null,
90107
91 shstrtab: std.ArrayList(u8),108 shstrtab: std.ArrayListUnmanaged(u8) = .{},
92 shstrtab_index: ?u16,109 shstrtab_index: ?u16 = null,
93110
94 text_section_index: ?u16,111 text_section_index: ?u16 = null,
95 symtab_section_index: ?u16,112 symtab_section_index: ?u16 = null,
96113
97 /// The same order as in the file114 /// The same order as in the file
98 symbols: std.ArrayList(elf.Elf64_Sym),115 symbols: std.ArrayListUnmanaged(elf.Elf64_Sym) = .{},
99116
100 errors: std.ArrayList(ErrorMsg),117 /// Same order as in the file.
118 offset_table: std.ArrayListUnmanaged(aoeu) = .{},
119
120 /// This means the entire read-only executable program code needs to be rewritten.
121 phdr_load_re_dirty: bool = false,
122 phdr_table_dirty: bool = false,
123 shdr_table_dirty: bool = false,
124 shstrtab_dirty: bool = false,
125 symtab_dirty: bool = false,
126
127 error_flags: ErrorFlags = ErrorFlags{},
101128
102 fn deinit(self: *Update) void {129 pub const ErrorFlags = struct {
103 self.sections.deinit();130 no_entry_point_found: bool = false,
104 self.program_headers.deinit();131 };
105 self.shstrtab.deinit();132
106 self.symbols.deinit();133 pub fn deinit(self: *ElfFile) void {
107 self.errors.deinit();134 self.sections.deinit(self.allocator);
135 self.program_headers.deinit(self.allocator);
136 self.shstrtab.deinit(self.allocator);
137 self.symbols.deinit(self.allocator);
138 self.offset_table.deinit(self.allocator);
108 }139 }
109140
110 // `expand_num / expand_den` is the factor of padding when allocation141 // `expand_num / expand_den` is the factor of padding when allocation
...@@ -112,8 +143,8 @@ const Update = struct {...@@ -112,8 +143,8 @@ const Update = struct {
112 const alloc_den = 3;143 const alloc_den = 3;
113144
114 /// Returns end pos of collision, if any.145 /// Returns end pos of collision, if any.
115 fn detectAllocCollision(self: *Update, start: u64, size: u64) ?u64 {146 fn detectAllocCollision(self: *ElfFile, start: u64, size: u64) ?u64 {
116 const small_ptr = self.module.target.cpu.arch.ptrBitWidth() == 32;147 const small_ptr = self.options.target.cpu.arch.ptrBitWidth() == 32;
117 const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr);148 const ehdr_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Ehdr) else @sizeOf(elf.Elf64_Ehdr);
118 if (start < ehdr_size)149 if (start < ehdr_size)
119 return ehdr_size;150 return ehdr_size;
...@@ -157,7 +188,7 @@ const Update = struct {...@@ -157,7 +188,7 @@ const Update = struct {
157 return null;188 return null;
158 }189 }
159190
160 fn allocatedSize(self: *Update, start: u64) u64 {191 fn allocatedSize(self: *ElfFile, start: u64) u64 {
161 var min_pos: u64 = std.math.maxInt(u64);192 var min_pos: u64 = std.math.maxInt(u64);
162 if (self.shdr_table_offset) |off| {193 if (self.shdr_table_offset) |off| {
163 if (off > start and off < min_pos) min_pos = off;194 if (off > start and off < min_pos) min_pos = off;
...@@ -176,7 +207,7 @@ const Update = struct {...@@ -176,7 +207,7 @@ const Update = struct {
176 return min_pos - start;207 return min_pos - start;
177 }208 }
178209
179 fn findFreeSpace(self: *Update, object_size: u64, min_alignment: u16) u64 {210 fn findFreeSpace(self: *ElfFile, object_size: u64, min_alignment: u16) u64 {
180 var start: u64 = 0;211 var start: u64 = 0;
181 while (self.detectAllocCollision(start, object_size)) |item_end| {212 while (self.detectAllocCollision(start, object_size)) |item_end| {
182 start = mem.alignForwardGeneric(u64, item_end, min_alignment);213 start = mem.alignForwardGeneric(u64, item_end, min_alignment);
...@@ -184,33 +215,21 @@ const Update = struct {...@@ -184,33 +215,21 @@ const Update = struct {
184 return start;215 return start;
185 }216 }
186217
187 fn makeString(self: *Update, bytes: []const u8) !u32 {218 fn makeString(self: *ElfFile, bytes: []const u8) !u32 {
188 const result = self.shstrtab.items.len;219 const result = self.shstrtab.items.len;
189 try self.shstrtab.appendSlice(bytes);220 try self.shstrtab.appendSlice(bytes);
190 try self.shstrtab.append(0);221 try self.shstrtab.append(0);
191 return @intCast(u32, result);222 return @intCast(u32, result);
192 }223 }
193224
194 fn perform(self: *Update) !void {225 pub fn populateMissingMetadata(self: *ElfFile) !void {
195 const ptr_width: enum { p32, p64 } = switch (self.module.target.cpu.arch.ptrBitWidth()) {226 const small_ptr = switch (self.ptr_width) {
196 32 => .p32,
197 64 => .p64,
198 else => return error.UnsupportedArchitecture,
199 };
200 const small_ptr = switch (ptr_width) {
201 .p32 => true,227 .p32 => true,
202 .p64 => false,228 .p64 => false,
203 };229 };
204 // This means the entire read-only executable program code needs to be rewritten.
205 var phdr_load_re_dirty = false;
206 var phdr_table_dirty = false;
207 var shdr_table_dirty = false;
208 var shstrtab_dirty = false;
209 var symtab_dirty = false;
210
211 if (self.phdr_load_re_index == null) {230 if (self.phdr_load_re_index == null) {
212 self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);231 self.phdr_load_re_index = @intCast(u16, self.program_headers.items.len);
213 const file_size = 256 * 1024;232 const file_size = self.options.program_code_size_hint;
214 const p_align = 0x1000;233 const p_align = 0x1000;
215 const off = self.findFreeSpace(file_size, p_align);234 const off = self.findFreeSpace(file_size, p_align);
216 //std.debug.warn("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });235 //std.debug.warn("found PT_LOAD free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
...@@ -225,24 +244,8 @@ const Update = struct {...@@ -225,24 +244,8 @@ const Update = struct {
225 .p_flags = elf.PF_X | elf.PF_R,244 .p_flags = elf.PF_X | elf.PF_R,
226 });245 });
227 self.entry_addr = null;246 self.entry_addr = null;
228 phdr_load_re_dirty = true;247 self.phdr_load_re_dirty = true;
229 phdr_table_dirty = true;248 self.phdr_table_dirty = true;
230 }
231 if (self.sections.items.len == 0) {
232 // There must always be a null section in index 0
233 try self.sections.append(.{
234 .sh_name = 0,
235 .sh_type = elf.SHT_NULL,
236 .sh_flags = 0,
237 .sh_addr = 0,
238 .sh_offset = 0,
239 .sh_size = 0,
240 .sh_link = 0,
241 .sh_info = 0,
242 .sh_addralign = 0,
243 .sh_entsize = 0,
244 });
245 shdr_table_dirty = true;
246 }249 }
247 if (self.shstrtab_index == null) {250 if (self.shstrtab_index == null) {
248 self.shstrtab_index = @intCast(u16, self.sections.items.len);251 self.shstrtab_index = @intCast(u16, self.sections.items.len);
...@@ -262,8 +265,8 @@ const Update = struct {...@@ -262,8 +265,8 @@ const Update = struct {
262 .sh_addralign = 1,265 .sh_addralign = 1,
263 .sh_entsize = 0,266 .sh_entsize = 0,
264 });267 });
265 shstrtab_dirty = true;268 self.shstrtab_dirty = true;
266 shdr_table_dirty = true;269 self.shdr_table_dirty = true;
267 }270 }
268 if (self.text_section_index == null) {271 if (self.text_section_index == null) {
269 self.text_section_index = @intCast(u16, self.sections.items.len);272 self.text_section_index = @intCast(u16, self.sections.items.len);
...@@ -281,13 +284,13 @@ const Update = struct {...@@ -281,13 +284,13 @@ const Update = struct {
281 .sh_addralign = phdr.p_align,284 .sh_addralign = phdr.p_align,
282 .sh_entsize = 0,285 .sh_entsize = 0,
283 });286 });
284 shdr_table_dirty = true;287 self.shdr_table_dirty = true;
285 }288 }
286 if (self.symtab_section_index == null) {289 if (self.symtab_section_index == null) {
287 self.symtab_section_index = @intCast(u16, self.sections.items.len);290 self.symtab_section_index = @intCast(u16, self.sections.items.len);
288 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);291 const min_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
289 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);292 const each_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
290 const file_size = self.module.exports.len * each_size;293 const file_size = self.options.symbol_count_hint * each_size;
291 const off = self.findFreeSpace(file_size, min_align);294 const off = self.findFreeSpace(file_size, min_align);
292 //std.debug.warn("found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size });295 //std.debug.warn("found symtab free space 0x{x} to 0x{x}\n", .{ off, off + file_size });
293296
...@@ -300,12 +303,12 @@ const Update = struct {...@@ -300,12 +303,12 @@ const Update = struct {
300 .sh_size = file_size,303 .sh_size = file_size,
301 // The section header index of the associated string table.304 // The section header index of the associated string table.
302 .sh_link = self.shstrtab_index.?,305 .sh_link = self.shstrtab_index.?,
303 .sh_info = @intCast(u32, self.module.exports.len),306 .sh_info = @intCast(u32, self.symbols.items.len),
304 .sh_addralign = min_align,307 .sh_addralign = min_align,
305 .sh_entsize = each_size,308 .sh_entsize = each_size,
306 });309 });
307 symtab_dirty = true;310 self.symtab_dirty = true;
308 shdr_table_dirty = true;311 self.shdr_table_dirty = true;
309 }312 }
310 const shsize: u64 = switch (ptr_width) {313 const shsize: u64 = switch (ptr_width) {
311 .p32 => @sizeOf(elf.Elf32_Shdr),314 .p32 => @sizeOf(elf.Elf32_Shdr),
...@@ -317,7 +320,7 @@ const Update = struct {...@@ -317,7 +320,7 @@ const Update = struct {
317 };320 };
318 if (self.shdr_table_offset == null) {321 if (self.shdr_table_offset == null) {
319 self.shdr_table_offset = self.findFreeSpace(self.sections.items.len * shsize, shalign);322 self.shdr_table_offset = self.findFreeSpace(self.sections.items.len * shsize, shalign);
320 shdr_table_dirty = true;323 self.shdr_table_dirty = true;
321 }324 }
322 const phsize: u64 = switch (ptr_width) {325 const phsize: u64 = switch (ptr_width) {
323 .p32 => @sizeOf(elf.Elf32_Phdr),326 .p32 => @sizeOf(elf.Elf32_Phdr),
...@@ -329,13 +332,15 @@ const Update = struct {...@@ -329,13 +332,15 @@ const Update = struct {
329 };332 };
330 if (self.phdr_table_offset == null) {333 if (self.phdr_table_offset == null) {
331 self.phdr_table_offset = self.findFreeSpace(self.program_headers.items.len * phsize, phalign);334 self.phdr_table_offset = self.findFreeSpace(self.program_headers.items.len * phsize, phalign);
332 phdr_table_dirty = true;335 self.phdr_table_dirty = true;
333 }336 }
334 const foreign_endian = self.module.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();337 }
335338
336 try self.writeCodeAndSymbols(phdr_table_dirty, shdr_table_dirty);339 /// Commit pending changes and write headers.
340 pub fn flush(self: *ElfFile) !void {
341 const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
337342
338 if (phdr_table_dirty) {343 if (self.phdr_table_dirty) {
339 const allocated_size = self.allocatedSize(self.phdr_table_offset.?);344 const allocated_size = self.allocatedSize(self.phdr_table_offset.?);
340 const needed_size = self.program_headers.items.len * phsize;345 const needed_size = self.program_headers.items.len * phsize;
341346
...@@ -345,7 +350,7 @@ const Update = struct {...@@ -345,7 +350,7 @@ const Update = struct {
345 }350 }
346351
347 const allocator = self.program_headers.allocator;352 const allocator = self.program_headers.allocator;
348 switch (ptr_width) {353 switch (self.ptr_width) {
349 .p32 => {354 .p32 => {
350 const buf = try allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len);355 const buf = try allocator.alloc(elf.Elf32_Phdr, self.program_headers.items.len);
351 defer allocator.free(buf);356 defer allocator.free(buf);
...@@ -371,11 +376,12 @@ const Update = struct {...@@ -371,11 +376,12 @@ const Update = struct {
371 try self.file.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);376 try self.file.pwriteAll(mem.sliceAsBytes(buf), self.phdr_table_offset.?);
372 },377 },
373 }378 }
379 self.phdr_table_offset = false;
374 }380 }
375381
376 {382 {
377 const shstrtab_sect = &self.sections.items[self.shstrtab_index.?];383 const shstrtab_sect = &self.sections.items[self.shstrtab_index.?];
378 if (shstrtab_dirty or self.shstrtab.items.len != shstrtab_sect.sh_size) {384 if (self.shstrtab_dirty or self.shstrtab.items.len != shstrtab_sect.sh_size) {
379 const allocated_size = self.allocatedSize(shstrtab_sect.sh_offset);385 const allocated_size = self.allocatedSize(shstrtab_sect.sh_offset);
380 const needed_size = self.shstrtab.items.len;386 const needed_size = self.shstrtab.items.len;
381387
...@@ -387,13 +393,14 @@ const Update = struct {...@@ -387,13 +393,14 @@ const Update = struct {
387 //std.debug.warn("shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });393 //std.debug.warn("shstrtab start=0x{x} end=0x{x}\n", .{ shstrtab_sect.sh_offset, shstrtab_sect.sh_offset + needed_size });
388394
389 try self.file.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);395 try self.file.pwriteAll(self.shstrtab.items, shstrtab_sect.sh_offset);
390 if (!shdr_table_dirty) {396 if (!self.shdr_table_dirty) {
391 // Then it won't get written with the others and we need to do it.397 // Then it won't get written with the others and we need to do it.
392 try self.writeSectHeader(self.shstrtab_index.?);398 try self.writeSectHeader(self.shstrtab_index.?);
393 }399 }
400 self.shstrtab_dirty = false;
394 }401 }
395 }402 }
396 if (shdr_table_dirty) {403 if (self.shdr_table_dirty) {
397 const allocated_size = self.allocatedSize(self.shdr_table_offset.?);404 const allocated_size = self.allocatedSize(self.shdr_table_offset.?);
398 const needed_size = self.sections.items.len * phsize;405 const needed_size = self.sections.items.len * phsize;
399406
...@@ -403,7 +410,7 @@ const Update = struct {...@@ -403,7 +410,7 @@ const Update = struct {
403 }410 }
404411
405 const allocator = self.sections.allocator;412 const allocator = self.sections.allocator;
406 switch (ptr_width) {413 switch (self.ptr_width) {
407 .p32 => {414 .p32 => {
408 const buf = try allocator.alloc(elf.Elf32_Shdr, self.sections.items.len);415 const buf = try allocator.alloc(elf.Elf32_Shdr, self.sections.items.len);
409 defer allocator.free(buf);416 defer allocator.free(buf);
...@@ -431,38 +438,36 @@ const Update = struct {...@@ -431,38 +438,36 @@ const Update = struct {
431 },438 },
432 }439 }
433 }440 }
434 if (self.entry_addr == null and self.module.output_mode == .Exe) {441 if (self.entry_addr == null and self.options.output_mode == .Exe) {
435 const msg = try std.fmt.allocPrint(self.errors.allocator, "no entry point found", .{});442 self.error_flags.no_entry_point_found = true;
436 errdefer self.errors.allocator.free(msg);
437 try self.errors.append(.{
438 .byte_offset = 0,
439 .msg = msg,
440 });
441 } else {443 } else {
444 self.error_flags.no_entry_point_found = false;
442 try self.writeElfHeader();445 try self.writeElfHeader();
443 }446 }
444 // TODO find end pos and truncate447 // TODO find end pos and truncate
448
449 // The point of flush() is to commit changes, so nothing should be dirty after this.
450 assert(!self.phdr_load_re_dirty);
451 assert(!self.phdr_table_dirty);
452 assert(!self.shdr_table_dirty);
453 assert(!self.shstrtab_dirty);
454 assert(!self.symtab_dirty);
445 }455 }
446456
447 fn writeElfHeader(self: *Update) !void {457 fn writeElfHeader(self: *ElfFile) !void {
448 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;458 var hdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;
449459
450 var index: usize = 0;460 var index: usize = 0;
451 hdr_buf[0..4].* = "\x7fELF".*;461 hdr_buf[0..4].* = "\x7fELF".*;
452 index += 4;462 index += 4;
453463
454 const ptr_width: enum { p32, p64 } = switch (self.module.target.cpu.arch.ptrBitWidth()) {464 hdr_buf[index] = switch (self.ptr_width) {
455 32 => .p32,
456 64 => .p64,
457 else => return error.UnsupportedArchitecture,
458 };
459 hdr_buf[index] = switch (ptr_width) {
460 .p32 => elf.ELFCLASS32,465 .p32 => elf.ELFCLASS32,
461 .p64 => elf.ELFCLASS64,466 .p64 => elf.ELFCLASS64,
462 };467 };
463 index += 1;468 index += 1;
464469
465 const endian = self.module.target.cpu.arch.endian();470 const endian = self.options.target.cpu.arch.endian();
466 hdr_buf[index] = switch (endian) {471 hdr_buf[index] = switch (endian) {
467 .Little => elf.ELFDATA2LSB,472 .Little => elf.ELFDATA2LSB,
468 .Big => elf.ELFDATA2MSB,473 .Big => elf.ELFDATA2MSB,
...@@ -480,10 +485,10 @@ const Update = struct {...@@ -480,10 +485,10 @@ const Update = struct {
480485
481 assert(index == 16);486 assert(index == 16);
482487
483 const elf_type = switch (self.module.output_mode) {488 const elf_type = switch (self.options.output_mode) {
484 .Exe => elf.ET.EXEC,489 .Exe => elf.ET.EXEC,
485 .Obj => elf.ET.REL,490 .Obj => elf.ET.REL,
486 .Lib => switch (self.module.link_mode) {491 .Lib => switch (self.options.link_mode) {
487 .Static => elf.ET.REL,492 .Static => elf.ET.REL,
488 .Dynamic => elf.ET.DYN,493 .Dynamic => elf.ET.DYN,
489 },494 },
...@@ -491,7 +496,7 @@ const Update = struct {...@@ -491,7 +496,7 @@ const Update = struct {
491 mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf_type), endian);496 mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(elf_type), endian);
492 index += 2;497 index += 2;
493498
494 const machine = self.module.target.cpu.arch.toElfMachine();499 const machine = self.options.target.cpu.arch.toElfMachine();
495 mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(machine), endian);500 mem.writeInt(u16, hdr_buf[index..][0..2], @enumToInt(machine), endian);
496 index += 2;501 index += 2;
497502
...@@ -501,7 +506,7 @@ const Update = struct {...@@ -501,7 +506,7 @@ const Update = struct {
501506
502 const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?;507 const e_entry = if (elf_type == .REL) 0 else self.entry_addr.?;
503508
504 switch (ptr_width) {509 switch (self.ptr_width) {
505 .p32 => {510 .p32 => {
506 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian);511 mem.writeInt(u32, hdr_buf[index..][0..4], @intCast(u32, e_entry), endian);
507 index += 4;512 index += 4;
...@@ -533,14 +538,14 @@ const Update = struct {...@@ -533,14 +538,14 @@ const Update = struct {
533 mem.writeInt(u32, hdr_buf[index..][0..4], e_flags, endian);538 mem.writeInt(u32, hdr_buf[index..][0..4], e_flags, endian);
534 index += 4;539 index += 4;
535540
536 const e_ehsize: u16 = switch (ptr_width) {541 const e_ehsize: u16 = switch (self.ptr_width) {
537 .p32 => @sizeOf(elf.Elf32_Ehdr),542 .p32 => @sizeOf(elf.Elf32_Ehdr),
538 .p64 => @sizeOf(elf.Elf64_Ehdr),543 .p64 => @sizeOf(elf.Elf64_Ehdr),
539 };544 };
540 mem.writeInt(u16, hdr_buf[index..][0..2], e_ehsize, endian);545 mem.writeInt(u16, hdr_buf[index..][0..2], e_ehsize, endian);
541 index += 2;546 index += 2;
542547
543 const e_phentsize: u16 = switch (ptr_width) {548 const e_phentsize: u16 = switch (self.ptr_width) {
544 .p32 => @sizeOf(elf.Elf32_Phdr),549 .p32 => @sizeOf(elf.Elf32_Phdr),
545 .p64 => @sizeOf(elf.Elf64_Phdr),550 .p64 => @sizeOf(elf.Elf64_Phdr),
546 };551 };
...@@ -551,7 +556,7 @@ const Update = struct {...@@ -551,7 +556,7 @@ const Update = struct {
551 mem.writeInt(u16, hdr_buf[index..][0..2], e_phnum, endian);556 mem.writeInt(u16, hdr_buf[index..][0..2], e_phnum, endian);
552 index += 2;557 index += 2;
553558
554 const e_shentsize: u16 = switch (ptr_width) {559 const e_shentsize: u16 = switch (self.ptr_width) {
555 .p32 => @sizeOf(elf.Elf32_Shdr),560 .p32 => @sizeOf(elf.Elf32_Shdr),
556 .p64 => @sizeOf(elf.Elf64_Shdr),561 .p64 => @sizeOf(elf.Elf64_Shdr),
557 };562 };
...@@ -570,81 +575,172 @@ const Update = struct {...@@ -570,81 +575,172 @@ const Update = struct {
570 try self.file.pwriteAll(hdr_buf[0..index], 0);575 try self.file.pwriteAll(hdr_buf[0..index], 0);
571 }576 }
572577
573 fn writeCodeAndSymbols(self: *Update, phdr_table_dirty: bool, shdr_table_dirty: bool) !void {578 /// TODO Look into making this smaller to save memory.
574 // index 0 is always a null symbol579 /// Lots of redundant info here with the data stored in symbol structs.
575 try self.symbols.resize(1);580 const DeclSymbol = struct {
576 self.symbols.items[0] = .{581 symbol_indexes: []usize,
577 .st_name = 0,582 vaddr: u64,
578 .st_info = 0,583 file_offset: u64,
579 .st_other = 0,584 size: u64,
580 .st_shndx = 0,585 };
581 .st_value = 0,
582 .st_size = 0,
583 };
584586
587 const AllocatedBlock = struct {
588 vaddr: u64,
589 file_offset: u64,
590 size_capacity: u64,
591 };
592
593 fn allocateDeclSymbol(self: *ElfFile, size: u64) AllocatedBlock {
585 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];594 const phdr = &self.program_headers.items[self.phdr_load_re_index.?];
586 var vaddr: u64 = phdr.p_vaddr;595 todo();
587 var file_off: u64 = phdr.p_offset;596 //{
597 // // Now that we know the code size, we need to update the program header for executable code
598 // phdr.p_memsz = vaddr - phdr.p_vaddr;
599 // phdr.p_filesz = phdr.p_memsz;
600
601 // const shdr = &self.sections.items[self.text_section_index.?];
602 // shdr.sh_size = phdr.p_filesz;
603
604 // self.phdr_table_dirty = true; // TODO look into making only the one program header dirty
605 // self.shdr_table_dirty = true; // TODO look into making only the one section dirty
606 //}
607
608 //return self.writeSymbols();
609 }
610
611 fn findAllocatedBlock(self: *ElfFile, vaddr: u64) AllocatedBlock {
612 todo();
613 }
588614
589 var code = std.ArrayList(u8).init(self.sections.allocator);615 pub fn updateDecl(
616 self: *ElfFile,
617 module: ir.Module,
618 typed_value: ir.TypedValue,
619 decl_export_node: ?*std.LinkedList(std.builtin.ExportOptions).Node,
620 hash: ir.Module.Decl.Hash,
621 err_msg_allocator: *Allocator,
622 ) !?ir.ErrorMsg {
623 var code = std.ArrayList(u8).init(self.allocator);
590 defer code.deinit();624 defer code.deinit();
591625
592 for (self.module.exports) |exp| {626 const err_msg = try codegen.generateSymbol(typed_value, module, &code, err_msg_allocator);
593 code.shrink(0);627 if (err_msg != null) |em| return em;
594 var symbol = try codegen.generateSymbol(exp.typed_value, self.module.*, &code);628
595 defer symbol.deinit(code.allocator);629 const export_count = blk: {
596 if (symbol.errors.len != 0) {630 var export_node = decl_export_node;
597 for (symbol.errors) |err| {631 var i: usize = 0;
598 const msg = try mem.dupe(self.errors.allocator, u8, err.msg);632 while (export_node) |node| : (export_node = node.next) i += 1;
599 errdefer self.errors.allocator.free(msg);633 break :blk i;
600 try self.errors.append(.{634 };
601 .byte_offset = err.byte_offset,635
602 .msg = msg,636 // Find or create a symbol from the decl
603 });637 var valid_sym_index_len: usize = 0;
638 const decl_symbol = blk: {
639 if (self.decl_table.getValue(hash)) |decl_symbol| {
640 valid_sym_index_len = decl_symbol.symbol_indexes.len;
641 decl_symbol.symbol_indexes = try self.allocator.realloc(usize, export_count);
642
643 const existing_block = self.findAllocatedBlock(decl_symbol.vaddr);
644 if (code.items.len > existing_block.size_capacity) {
645 const new_block = self.allocateDeclSymbol(code.items.len);
646 decl_symbol.vaddr = new_block.vaddr;
647 decl_symbol.file_offset = new_block.file_offset;
648 decl_symbol.size = code.items.len;
604 }649 }
605 continue;650 break :blk decl_symbol;
651 } else {
652 const new_block = self.allocateDeclSymbol(code.items.len);
653
654 const decl_symbol = try self.allocator.create(DeclSymbol);
655 errdefer self.allocator.destroy(decl_symbol);
656
657 decl_symbol.* = .{
658 .symbol_indexes = try self.allocator.alloc(usize, export_count),
659 .vaddr = new_block.vaddr,
660 .file_offset = new_block.file_offset,
661 .size = code.items.len,
662 };
663 errdefer self.allocator.free(decl_symbol.symbol_indexes);
664
665 try self.decl_table.put(hash, decl_symbol);
666 break :blk decl_symbol;
667 }
668 };
669
670 // Allocate new symbols.
671 {
672 var i: usize = valid_sym_index_len;
673 const old_len = self.symbols.items.len;
674 try self.symbols.resize(old_len + (decl_symbol.symbol_indexes.len - i));
675 while (i < decl_symbol.symbol_indexes) : (i += 1) {
676 decl_symbol.symbol_indexes[i] = old_len + i;
606 }677 }
607 try self.file.pwriteAll(code.items, file_off);678 }
608679
609 if (mem.eql(u8, exp.name, "_start")) {680 var export_node = decl_export_node;
610 self.entry_addr = vaddr;681 var export_index: usize = 0;
682 while (export_node) |node| : ({
683 export_node = node.next;
684 export_index += 1;
685 }) {
686 if (node.data.section) |section_name| {
687 if (!mem.eql(u8, section_name, ".text")) {
688 try errors.ensureCapacity(errors.items.len + 1);
689 errors.appendAssumeCapacity(.{
690 .byte_offset = 0,
691 .msg = try std.fmt.allocPrint(errors.allocator, "Unimplemented: ExportOptions.section", .{}),
692 });
693 }
611 }694 }
612 (try self.symbols.addOne()).* = .{695 const stb_bits = switch (node.data.linkage) {
613 .st_name = try self.makeString(exp.name),696 .Internal => elf.STB_LOCAL,
614 .st_info = (elf.STB_LOCAL << 4) | elf.STT_FUNC,697 .Strong => blk: {
698 if (mem.eql(u8, node.data.name, "_start")) {
699 self.entry_addr = decl_symbol.vaddr;
700 }
701 break :blk elf.STB_GLOBAL;
702 },
703 .Weak => elf.STB_WEAK,
704 .LinkOnce => {
705 try errors.ensureCapacity(errors.items.len + 1);
706 errors.appendAssumeCapacity(.{
707 .byte_offset = 0,
708 .msg = try std.fmt.allocPrint(errors.allocator, "Unimplemented: GlobalLinkage.LinkOnce", .{}),
709 });
710 },
711 };
712 const stt_bits = switch (typed_value.ty.zigTypeTag()) {
713 .Fn => elf.STT_FUNC,
714 else => elf.STT_OBJECT,
715 };
716 const sym_index = decl_symbol.symbol_indexes[export_index];
717 const name = blk: {
718 if (i < valid_sym_index_len) {
719 const name_stroff = self.symbols.items[sym_index].st_name;
720 const existing_name = self.getString(name_stroff);
721 if (mem.eql(u8, existing_name, node.data.name)) {
722 break :blk name_stroff;
723 }
724 }
725 break :blk try self.makeString(node.data.name);
726 };
727 self.symbols.items[sym_index] = .{
728 .st_name = name,
729 .st_info = (stb_bits << 4) | stt_bits,
615 .st_other = 0,730 .st_other = 0,
616 .st_shndx = self.text_section_index.?,731 .st_shndx = self.text_section_index.?,
617 .st_value = vaddr,732 .st_value = decl_symbol.vaddr,
618 .st_size = code.items.len,733 .st_size = code.items.len,
619 };734 };
620 vaddr += code.items.len;
621 }735 }
622736
623 {737 try self.file.pwriteAll(code.items, decl_symbol.file_offset);
624 // Now that we know the code size, we need to update the program header for executable code
625 phdr.p_memsz = vaddr - phdr.p_vaddr;
626 phdr.p_filesz = phdr.p_memsz;
627
628 const shdr = &self.sections.items[self.text_section_index.?];
629 shdr.sh_size = phdr.p_filesz;
630
631 if (!phdr_table_dirty) {
632 // Then it won't get written with the others and we need to do it.
633 try self.writeProgHeader(self.phdr_load_re_index.?);
634 }
635 if (!shdr_table_dirty) {
636 // Then it won't get written with the others and we need to do it.
637 try self.writeSectHeader(self.text_section_index.?);
638 }
639 }
640
641 return self.writeSymbols();
642 }738 }
643739
644 fn writeProgHeader(self: *Update, index: usize) !void {740 fn writeProgHeader(self: *ElfFile, index: usize) !void {
645 const foreign_endian = self.module.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();741 const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
646 const offset = self.program_headers.items[index].p_offset;742 const offset = self.program_headers.items[index].p_offset;
647 switch (self.module.target.cpu.arch.ptrBitWidth()) {743 switch (self.options.target.cpu.arch.ptrBitWidth()) {
648 32 => {744 32 => {
649 var phdr = [1]elf.Elf32_Phdr{progHeaderTo32(self.program_headers.items[index])};745 var phdr = [1]elf.Elf32_Phdr{progHeaderTo32(self.program_headers.items[index])};
650 if (foreign_endian) {746 if (foreign_endian) {
...@@ -663,10 +759,10 @@ const Update = struct {...@@ -663,10 +759,10 @@ const Update = struct {
663 }759 }
664 }760 }
665761
666 fn writeSectHeader(self: *Update, index: usize) !void {762 fn writeSectHeader(self: *ElfFile, index: usize) !void {
667 const foreign_endian = self.module.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();763 const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
668 const offset = self.sections.items[index].sh_offset;764 const offset = self.sections.items[index].sh_offset;
669 switch (self.module.target.cpu.arch.ptrBitWidth()) {765 switch (self.options.target.cpu.arch.ptrBitWidth()) {
670 32 => {766 32 => {
671 var shdr: [1]elf.Elf32_Shdr = undefined;767 var shdr: [1]elf.Elf32_Shdr = undefined;
672 shdr[0] = sectHeaderTo32(self.sections.items[index]);768 shdr[0] = sectHeaderTo32(self.sections.items[index]);
...@@ -686,13 +782,8 @@ const Update = struct {...@@ -686,13 +782,8 @@ const Update = struct {
686 }782 }
687 }783 }
688784
689 fn writeSymbols(self: *Update) !void {785 fn writeSymbols(self: *ElfFile) !void {
690 const ptr_width: enum { p32, p64 } = switch (self.module.target.cpu.arch.ptrBitWidth()) {786 const small_ptr = self.ptr_width == .p32;
691 32 => .p32,
692 64 => .p64,
693 else => return error.UnsupportedArchitecture,
694 };
695 const small_ptr = ptr_width == .p32;
696 const syms_sect = &self.sections.items[self.symtab_section_index.?];787 const syms_sect = &self.sections.items[self.symtab_section_index.?];
697 const sym_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);788 const sym_align: u16 = if (small_ptr) @alignOf(elf.Elf32_Sym) else @alignOf(elf.Elf64_Sym);
698 const sym_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);789 const sym_size: u64 = if (small_ptr) @sizeOf(elf.Elf32_Sym) else @sizeOf(elf.Elf64_Sym);
...@@ -708,8 +799,8 @@ const Update = struct {...@@ -708,8 +799,8 @@ const Update = struct {
708 syms_sect.sh_size = needed_size;799 syms_sect.sh_size = needed_size;
709 syms_sect.sh_info = @intCast(u32, self.symbols.items.len);800 syms_sect.sh_info = @intCast(u32, self.symbols.items.len);
710 const allocator = self.symbols.allocator;801 const allocator = self.symbols.allocator;
711 const foreign_endian = self.module.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();802 const foreign_endian = self.options.target.cpu.arch.endian() != std.Target.current.cpu.arch.endian();
712 switch (ptr_width) {803 switch (self.ptr_width) {
713 .p32 => {804 .p32 => {
714 const buf = try allocator.alloc(elf.Elf32_Sym, self.symbols.items.len);805 const buf = try allocator.alloc(elf.Elf32_Sym, self.symbols.items.len);
715 defer allocator.free(buf);806 defer allocator.free(buf);
...@@ -754,13 +845,13 @@ const Update = struct {...@@ -754,13 +845,13 @@ const Update = struct {
754845
755/// Truncates the existing file contents and overwrites the contents.846/// Truncates the existing file contents and overwrites the contents.
756/// Returns an error if `file` is not already open with +read +write +seek abilities.847/// Returns an error if `file` is not already open with +read +write +seek abilities.
757pub fn writeFile(allocator: *Allocator, module: ir.Module, file: fs.File) !Result {848pub fn createElfFile(allocator: *Allocator, file: fs.File, options: Options) !ElfFile {
758 switch (module.output_mode) {849 switch (options.output_mode) {
759 .Exe => {},850 .Exe => {},
760 .Obj => {},851 .Obj => {},
761 .Lib => return error.TODOImplementWritingLibFiles,852 .Lib => return error.TODOImplementWritingLibFiles,
762 }853 }
763 switch (module.object_format) {854 switch (options.object_format) {
764 .unknown => unreachable, // TODO remove this tag from the enum855 .unknown => unreachable, // TODO remove this tag from the enum
765 .coff => return error.TODOImplementWritingCOFF,856 .coff => return error.TODOImplementWritingCOFF,
766 .elf => {},857 .elf => {},
...@@ -768,38 +859,79 @@ pub fn writeFile(allocator: *Allocator, module: ir.Module, file: fs.File) !Resul...@@ -768,38 +859,79 @@ pub fn writeFile(allocator: *Allocator, module: ir.Module, file: fs.File) !Resul
768 .wasm => return error.TODOImplementWritingWasmObjects,859 .wasm => return error.TODOImplementWritingWasmObjects,
769 }860 }
770861
771 var update = Update{862 var self: ElfFile = .{
863 .allocator = allocator,
772 .file = file,864 .file = file,
773 .module = &module,865 .options = options,
774 .sections = std.ArrayList(elf.Elf64_Shdr).init(allocator),866 .ptr_width = switch (self.options.target.cpu.arch.ptrBitWidth()) {
775 .shdr_table_offset = null,867 32 => .p32,
776 .program_headers = std.ArrayList(elf.Elf64_Phdr).init(allocator),868 64 => .p64,
777 .phdr_table_offset = null,869 else => return error.UnsupportedELFArchitecture,
778 .phdr_load_re_index = null,870 },
779 .entry_addr = null,871 .symtab_dirty = true,
780 .shstrtab = std.ArrayList(u8).init(allocator),872 .shdr_table_dirty = true,
781 .shstrtab_index = null,
782 .text_section_index = null,
783 .symtab_section_index = null,
784
785 .symbols = std.ArrayList(elf.Elf64_Sym).init(allocator),
786
787 .errors = std.ArrayList(ErrorMsg).init(allocator),
788 };
789 defer update.deinit();
790
791 try update.perform();
792 return Result{
793 .errors = update.errors.toOwnedSlice(),
794 };873 };
874 errdefer self.deinit();
875
876 // Index 0 is always a null symbol.
877 try self.symbols.append(allocator, .{
878 .st_name = 0,
879 .st_info = 0,
880 .st_other = 0,
881 .st_shndx = 0,
882 .st_value = 0,
883 .st_size = 0,
884 });
885
886 // There must always be a null section in index 0
887 try self.sections.append(allocator, .{
888 .sh_name = 0,
889 .sh_type = elf.SHT_NULL,
890 .sh_flags = 0,
891 .sh_addr = 0,
892 .sh_offset = 0,
893 .sh_size = 0,
894 .sh_link = 0,
895 .sh_info = 0,
896 .sh_addralign = 0,
897 .sh_entsize = 0,
898 });
899
900 try self.populateMissingMetadata();
901
902 return self;
795}903}
796904
797/// Returns error.IncrFailed if incremental update could not be performed.905/// Returns error.IncrFailed if incremental update could not be performed.
798fn updateFileInner(allocator: *Allocator, module: ir.Module, file: fs.File) !Result {906fn openBinFileInner(allocator: *Allocator, file: fs.File, options: Options) !ElfFile {
799 //var ehdr_buf: [@sizeOf(elf.Elf64_Ehdr)]u8 = undefined;907 switch (options.output_mode) {
908 .Exe => {},
909 .Obj => {},
910 .Lib => return error.IncrFailed,
911 }
912 switch (options.object_format) {
913 .unknown => unreachable, // TODO remove this tag from the enum
914 .coff => return error.IncrFailed,
915 .elf => {},
916 .macho => return error.IncrFailed,
917 .wasm => return error.IncrFailed,
918 }
919 var self: ElfFile = .{
920 .allocator = allocator,
921 .file = file,
922 .options = options,
923 .ptr_width = switch (self.options.target.cpu.arch.ptrBitWidth()) {
924 32 => .p32,
925 64 => .p64,
926 else => return error.UnsupportedELFArchitecture,
927 },
928 };
929 errdefer self.deinit();
800930
801 // TODO implement incremental linking931 // TODO implement reading the elf file
802 return error.IncrFailed;932 return error.IncrFailed;
933 //try self.populateMissingMetadata();
934 //return self;
803}935}
804936
805/// Saturating multiplication937/// Saturating multiplication
...@@ -840,14 +972,14 @@ fn sectHeaderTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr {...@@ -840,14 +972,14 @@ fn sectHeaderTo32(shdr: elf.Elf64_Shdr) elf.Elf32_Shdr {
840 };972 };
841}973}
842974
843fn determineMode(module: ir.Module) fs.File.Mode {975fn determineMode(options: Options) fs.File.Mode {
844 // On common systems with a 0o022 umask, 0o777 will still result in a file created976 // On common systems with a 0o022 umask, 0o777 will still result in a file created
845 // with 0o755 permissions, but it works appropriately if the system is configured977 // with 0o755 permissions, but it works appropriately if the system is configured
846 // more leniently. As another data point, C's fopen seems to open files with the978 // more leniently. As another data point, C's fopen seems to open files with the
847 // 666 mode.979 // 666 mode.
848 const executable_mode = if (std.Target.current.os.tag == .windows) 0 else 0o777;980 const executable_mode = if (std.Target.current.os.tag == .windows) 0 else 0o777;
849 switch (module.output_mode) {981 switch (options.output_mode) {
850 .Lib => return switch (module.link_mode) {982 .Lib => return switch (options.link_mode) {
851 .Dynamic => executable_mode,983 .Dynamic => executable_mode,
852 .Static => fs.File.default_mode,984 .Static => fs.File.default_mode,
853 },985 },
src-self-hosted/package.zig deleted-31
...@@ -1,31 +0,0 @@
1const std = @import("std");
2const mem = std.mem;
3const assert = std.debug.assert;
4const ArrayListSentineled = std.ArrayListSentineled;
5
6pub const Package = struct {
7 root_src_dir: ArrayListSentineled(u8, 0),
8 root_src_path: ArrayListSentineled(u8, 0),
9
10 /// relative to root_src_dir
11 table: Table,
12
13 pub const Table = std.StringHashMap(*Package);
14
15 /// makes internal copies of root_src_dir and root_src_path
16 /// allocator should be an arena allocator because Package never frees anything
17 pub fn create(allocator: *mem.Allocator, root_src_dir: []const u8, root_src_path: []const u8) !*Package {
18 const ptr = try allocator.create(Package);
19 ptr.* = Package{
20 .root_src_dir = try ArrayListSentineled(u8, 0).init(allocator, root_src_dir),
21 .root_src_path = try ArrayListSentineled(u8, 0).init(allocator, root_src_path),
22 .table = Table.init(allocator),
23 };
24 return ptr;
25 }
26
27 pub fn add(self: *Package, name: []const u8, package: *Package) !void {
28 const entry = try self.table.put(try mem.dupe(self.table.allocator, u8, name), package);
29 assert(entry == null);
30 }
31};
src-self-hosted/scope.zig deleted-418
...@@ -1,418 +0,0 @@
1const std = @import("std");
2const Allocator = mem.Allocator;
3const Decl = @import("decl.zig").Decl;
4const Compilation = @import("compilation.zig").Compilation;
5const mem = std.mem;
6const ast = std.zig.ast;
7const Value = @import("value.zig").Value;
8const Type = @import("type.zig").Type;
9const ir = @import("ir.zig");
10const Span = @import("errmsg.zig").Span;
11const assert = std.debug.assert;
12const event = std.event;
13const llvm = @import("llvm.zig");
14
15pub const Scope = struct {
16 id: Id,
17 parent: ?*Scope,
18 ref_count: std.atomic.Int(usize),
19
20 /// Thread-safe
21 pub fn ref(base: *Scope) void {
22 _ = base.ref_count.incr();
23 }
24
25 /// Thread-safe
26 pub fn deref(base: *Scope, comp: *Compilation) void {
27 if (base.ref_count.decr() == 1) {
28 if (base.parent) |parent| parent.deref(comp);
29 switch (base.id) {
30 .Root => @fieldParentPtr(Root, "base", base).destroy(comp),
31 .Decls => @fieldParentPtr(Decls, "base", base).destroy(comp),
32 .Block => @fieldParentPtr(Block, "base", base).destroy(comp),
33 .FnDef => @fieldParentPtr(FnDef, "base", base).destroy(comp),
34 .CompTime => @fieldParentPtr(CompTime, "base", base).destroy(comp),
35 .Defer => @fieldParentPtr(Defer, "base", base).destroy(comp),
36 .DeferExpr => @fieldParentPtr(DeferExpr, "base", base).destroy(comp),
37 .Var => @fieldParentPtr(Var, "base", base).destroy(comp),
38 .AstTree => @fieldParentPtr(AstTree, "base", base).destroy(comp),
39 }
40 }
41 }
42
43 pub fn findRoot(base: *Scope) *Root {
44 var scope = base;
45 while (scope.parent) |parent| {
46 scope = parent;
47 }
48 assert(scope.id == .Root);
49 return @fieldParentPtr(Root, "base", scope);
50 }
51
52 pub fn findFnDef(base: *Scope) ?*FnDef {
53 var scope = base;
54 while (true) {
55 switch (scope.id) {
56 .FnDef => return @fieldParentPtr(FnDef, "base", scope),
57 .Root, .Decls => return null,
58
59 .Block,
60 .Defer,
61 .DeferExpr,
62 .CompTime,
63 .Var,
64 => scope = scope.parent.?,
65
66 .AstTree => unreachable,
67 }
68 }
69 }
70
71 pub fn findDeferExpr(base: *Scope) ?*DeferExpr {
72 var scope = base;
73 while (true) {
74 switch (scope.id) {
75 .DeferExpr => return @fieldParentPtr(DeferExpr, "base", scope),
76
77 .FnDef,
78 .Decls,
79 => return null,
80
81 .Block,
82 .Defer,
83 .CompTime,
84 .Root,
85 .Var,
86 => scope = scope.parent orelse return null,
87
88 .AstTree => unreachable,
89 }
90 }
91 }
92
93 fn init(base: *Scope, id: Id, parent: *Scope) void {
94 base.* = Scope{
95 .id = id,
96 .parent = parent,
97 .ref_count = std.atomic.Int(usize).init(1),
98 };
99 parent.ref();
100 }
101
102 pub const Id = enum {
103 Root,
104 AstTree,
105 Decls,
106 Block,
107 FnDef,
108 CompTime,
109 Defer,
110 DeferExpr,
111 Var,
112 };
113
114 pub const Root = struct {
115 base: Scope,
116 realpath: []const u8,
117 decls: *Decls,
118
119 /// Creates a Root scope with 1 reference
120 /// Takes ownership of realpath
121 pub fn create(comp: *Compilation, realpath: []u8) !*Root {
122 const self = try comp.gpa().create(Root);
123 self.* = Root{
124 .base = Scope{
125 .id = .Root,
126 .parent = null,
127 .ref_count = std.atomic.Int(usize).init(1),
128 },
129 .realpath = realpath,
130 .decls = undefined,
131 };
132 errdefer comp.gpa().destroy(self);
133 self.decls = try Decls.create(comp, &self.base);
134 return self;
135 }
136
137 pub fn destroy(self: *Root, comp: *Compilation) void {
138 // TODO comp.fs_watch.removeFile(self.realpath);
139 self.decls.base.deref(comp);
140 comp.gpa().free(self.realpath);
141 comp.gpa().destroy(self);
142 }
143 };
144
145 pub const AstTree = struct {
146 base: Scope,
147 tree: *ast.Tree,
148
149 /// Creates a scope with 1 reference
150 /// Takes ownership of tree, will deinit and destroy when done.
151 pub fn create(comp: *Compilation, tree: *ast.Tree, root_scope: *Root) !*AstTree {
152 const self = try comp.gpa().create(AstTree);
153 self.* = AstTree{
154 .base = undefined,
155 .tree = tree,
156 };
157 self.base.init(.AstTree, &root_scope.base);
158
159 return self;
160 }
161
162 pub fn destroy(self: *AstTree, comp: *Compilation) void {
163 comp.gpa().free(self.tree.source);
164 self.tree.deinit();
165 comp.gpa().destroy(self);
166 }
167
168 pub fn root(self: *AstTree) *Root {
169 return self.base.findRoot();
170 }
171 };
172
173 pub const Decls = struct {
174 base: Scope,
175
176 /// This table remains Write Locked when the names are incomplete or possibly outdated.
177 /// So if a reader manages to grab a lock, it can be sure that the set of names is complete
178 /// and correct.
179 table: event.RwLocked(Decl.Table),
180
181 /// Creates a Decls scope with 1 reference
182 pub fn create(comp: *Compilation, parent: *Scope) !*Decls {
183 const self = try comp.gpa().create(Decls);
184 self.* = Decls{
185 .base = undefined,
186 .table = event.RwLocked(Decl.Table).init(Decl.Table.init(comp.gpa())),
187 };
188 self.base.init(.Decls, parent);
189 return self;
190 }
191
192 pub fn destroy(self: *Decls, comp: *Compilation) void {
193 self.table.deinit();
194 comp.gpa().destroy(self);
195 }
196 };
197
198 pub const Block = struct {
199 base: Scope,
200 incoming_values: std.ArrayList(*ir.Inst),
201 incoming_blocks: std.ArrayList(*ir.BasicBlock),
202 end_block: *ir.BasicBlock,
203 is_comptime: *ir.Inst,
204
205 safety: Safety,
206
207 const Safety = union(enum) {
208 Auto,
209 Manual: Manual,
210
211 const Manual = struct {
212 /// the source span that disabled the safety value
213 span: Span,
214
215 /// whether safety is enabled
216 enabled: bool,
217 };
218
219 fn get(self: Safety, comp: *Compilation) bool {
220 return switch (self) {
221 .Auto => switch (comp.build_mode) {
222 .Debug,
223 .ReleaseSafe,
224 => true,
225 .ReleaseFast,
226 .ReleaseSmall,
227 => false,
228 },
229 .Manual => |man| man.enabled,
230 };
231 }
232 };
233
234 /// Creates a Block scope with 1 reference
235 pub fn create(comp: *Compilation, parent: *Scope) !*Block {
236 const self = try comp.gpa().create(Block);
237 self.* = Block{
238 .base = undefined,
239 .incoming_values = undefined,
240 .incoming_blocks = undefined,
241 .end_block = undefined,
242 .is_comptime = undefined,
243 .safety = Safety.Auto,
244 };
245 self.base.init(.Block, parent);
246 return self;
247 }
248
249 pub fn destroy(self: *Block, comp: *Compilation) void {
250 comp.gpa().destroy(self);
251 }
252 };
253
254 pub const FnDef = struct {
255 base: Scope,
256
257 /// This reference is not counted so that the scope can get destroyed with the function
258 fn_val: ?*Value.Fn,
259
260 /// Creates a FnDef scope with 1 reference
261 /// Must set the fn_val later
262 pub fn create(comp: *Compilation, parent: *Scope) !*FnDef {
263 const self = try comp.gpa().create(FnDef);
264 self.* = FnDef{
265 .base = undefined,
266 .fn_val = null,
267 };
268 self.base.init(.FnDef, parent);
269 return self;
270 }
271
272 pub fn destroy(self: *FnDef, comp: *Compilation) void {
273 comp.gpa().destroy(self);
274 }
275 };
276
277 pub const CompTime = struct {
278 base: Scope,
279
280 /// Creates a CompTime scope with 1 reference
281 pub fn create(comp: *Compilation, parent: *Scope) !*CompTime {
282 const self = try comp.gpa().create(CompTime);
283 self.* = CompTime{ .base = undefined };
284 self.base.init(.CompTime, parent);
285 return self;
286 }
287
288 pub fn destroy(self: *CompTime, comp: *Compilation) void {
289 comp.gpa().destroy(self);
290 }
291 };
292
293 pub const Defer = struct {
294 base: Scope,
295 defer_expr_scope: *DeferExpr,
296 kind: Kind,
297
298 pub const Kind = enum {
299 ScopeExit,
300 ErrorExit,
301 };
302
303 /// Creates a Defer scope with 1 reference
304 pub fn create(
305 comp: *Compilation,
306 parent: *Scope,
307 kind: Kind,
308 defer_expr_scope: *DeferExpr,
309 ) !*Defer {
310 const self = try comp.gpa().create(Defer);
311 self.* = Defer{
312 .base = undefined,
313 .defer_expr_scope = defer_expr_scope,
314 .kind = kind,
315 };
316 self.base.init(.Defer, parent);
317 defer_expr_scope.base.ref();
318 return self;
319 }
320
321 pub fn destroy(self: *Defer, comp: *Compilation) void {
322 self.defer_expr_scope.base.deref(comp);
323 comp.gpa().destroy(self);
324 }
325 };
326
327 pub const DeferExpr = struct {
328 base: Scope,
329 expr_node: *ast.Node,
330 reported_err: bool,
331
332 /// Creates a DeferExpr scope with 1 reference
333 pub fn create(comp: *Compilation, parent: *Scope, expr_node: *ast.Node) !*DeferExpr {
334 const self = try comp.gpa().create(DeferExpr);
335 self.* = DeferExpr{
336 .base = undefined,
337 .expr_node = expr_node,
338 .reported_err = false,
339 };
340 self.base.init(.DeferExpr, parent);
341 return self;
342 }
343
344 pub fn destroy(self: *DeferExpr, comp: *Compilation) void {
345 comp.gpa().destroy(self);
346 }
347 };
348
349 pub const Var = struct {
350 base: Scope,
351 name: []const u8,
352 src_node: *ast.Node,
353 data: Data,
354
355 pub const Data = union(enum) {
356 Param: Param,
357 Const: *Value,
358 };
359
360 pub const Param = struct {
361 index: usize,
362 typ: *Type,
363 llvm_value: *llvm.Value,
364 };
365
366 pub fn createParam(
367 comp: *Compilation,
368 parent: *Scope,
369 name: []const u8,
370 src_node: *ast.Node,
371 param_index: usize,
372 param_type: *Type,
373 ) !*Var {
374 const self = try create(comp, parent, name, src_node);
375 self.data = Data{
376 .Param = Param{
377 .index = param_index,
378 .typ = param_type,
379 .llvm_value = undefined,
380 },
381 };
382 return self;
383 }
384
385 pub fn createConst(
386 comp: *Compilation,
387 parent: *Scope,
388 name: []const u8,
389 src_node: *ast.Node,
390 value: *Value,
391 ) !*Var {
392 const self = try create(comp, parent, name, src_node);
393 self.data = Data{ .Const = value };
394 value.ref();
395 return self;
396 }
397
398 fn create(comp: *Compilation, parent: *Scope, name: []const u8, src_node: *ast.Node) !*Var {
399 const self = try comp.gpa().create(Var);
400 self.* = Var{
401 .base = undefined,
402 .name = name,
403 .src_node = src_node,
404 .data = undefined,
405 };
406 self.base.init(.Var, parent);
407 return self;
408 }
409
410 pub fn destroy(self: *Var, comp: *Compilation) void {
411 switch (self.data) {
412 .Param => {},
413 .Const => |value| value.deref(comp),
414 }
415 comp.gpa().destroy(self);
416 }
417 };
418};
src-self-hosted/test.zig+5-6
...@@ -3,15 +3,14 @@ const link = @import("link.zig");...@@ -3,15 +3,14 @@ const link = @import("link.zig");
3const ir = @import("ir.zig");3const ir = @import("ir.zig");
4const Allocator = std.mem.Allocator;4const Allocator = std.mem.Allocator;
55
6var global_ctx: TestContext = undefined;
7
8test "self-hosted" {6test "self-hosted" {
9 try global_ctx.init();7 var ctx: TestContext = undefined;
10 defer global_ctx.deinit();8 try ctx.init();
9 defer ctx.deinit();
1110
12 try @import("stage2_tests").addCases(&global_ctx);11 try @import("stage2_tests").addCases(&ctx);
1312
14 try global_ctx.run();13 try ctx.run();
15}14}
1615
17pub const TestContext = struct {16pub const TestContext = struct {
src-self-hosted/type.zig+62-1
...@@ -52,6 +52,7 @@ pub const Type = extern union {...@@ -52,6 +52,7 @@ pub const Type = extern union {
52 .comptime_float => return .ComptimeFloat,52 .comptime_float => return .ComptimeFloat,
53 .noreturn => return .NoReturn,53 .noreturn => return .NoReturn,
5454
55 .fn_noreturn_no_args => return .Fn,
55 .fn_naked_noreturn_no_args => return .Fn,56 .fn_naked_noreturn_no_args => return .Fn,
56 .fn_ccc_void_no_args => return .Fn,57 .fn_ccc_void_no_args => return .Fn,
5758
...@@ -184,6 +185,7 @@ pub const Type = extern union {...@@ -184,6 +185,7 @@ pub const Type = extern union {
184 => return out_stream.writeAll(@tagName(t)),185 => return out_stream.writeAll(@tagName(t)),
185186
186 .const_slice_u8 => return out_stream.writeAll("[]const u8"),187 .const_slice_u8 => return out_stream.writeAll("[]const u8"),
188 .fn_noreturn_no_args => return out_stream.writeAll("fn() noreturn"),
187 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),189 .fn_naked_noreturn_no_args => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
188 .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),190 .fn_ccc_void_no_args => return out_stream.writeAll("fn() callconv(.C) void"),
189 .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),191 .single_const_pointer_to_comptime_int => return out_stream.writeAll("*const comptime_int"),
...@@ -244,6 +246,7 @@ pub const Type = extern union {...@@ -244,6 +246,7 @@ pub const Type = extern union {
244 .comptime_int => return Value.initTag(.comptime_int_type),246 .comptime_int => return Value.initTag(.comptime_int_type),
245 .comptime_float => return Value.initTag(.comptime_float_type),247 .comptime_float => return Value.initTag(.comptime_float_type),
246 .noreturn => return Value.initTag(.noreturn_type),248 .noreturn => return Value.initTag(.noreturn_type),
249 .fn_noreturn_no_args => return Value.initTag(.fn_noreturn_no_args_type),
247 .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type),250 .fn_naked_noreturn_no_args => return Value.initTag(.fn_naked_noreturn_no_args_type),
248 .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),251 .fn_ccc_void_no_args => return Value.initTag(.fn_ccc_void_no_args_type),
249 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),252 .single_const_pointer_to_comptime_int => return Value.initTag(.single_const_pointer_to_comptime_int_type),
...@@ -286,6 +289,7 @@ pub const Type = extern union {...@@ -286,6 +289,7 @@ pub const Type = extern union {
286 .array,289 .array,
287 .array_u8_sentinel_0,290 .array_u8_sentinel_0,
288 .const_slice_u8,291 .const_slice_u8,
292 .fn_noreturn_no_args,
289 .fn_naked_noreturn_no_args,293 .fn_naked_noreturn_no_args,
290 .fn_ccc_void_no_args,294 .fn_ccc_void_no_args,
291 .int_unsigned,295 .int_unsigned,
...@@ -329,6 +333,7 @@ pub const Type = extern union {...@@ -329,6 +333,7 @@ pub const Type = extern union {
329 .array_u8_sentinel_0,333 .array_u8_sentinel_0,
330 .single_const_pointer,334 .single_const_pointer,
331 .single_const_pointer_to_comptime_int,335 .single_const_pointer_to_comptime_int,
336 .fn_noreturn_no_args,
332 .fn_naked_noreturn_no_args,337 .fn_naked_noreturn_no_args,
333 .fn_ccc_void_no_args,338 .fn_ccc_void_no_args,
334 .int_unsigned,339 .int_unsigned,
...@@ -369,6 +374,7 @@ pub const Type = extern union {...@@ -369,6 +374,7 @@ pub const Type = extern union {
369 .noreturn,374 .noreturn,
370 .array,375 .array,
371 .array_u8_sentinel_0,376 .array_u8_sentinel_0,
377 .fn_noreturn_no_args,
372 .fn_naked_noreturn_no_args,378 .fn_naked_noreturn_no_args,
373 .fn_ccc_void_no_args,379 .fn_ccc_void_no_args,
374 .int_unsigned,380 .int_unsigned,
...@@ -410,6 +416,7 @@ pub const Type = extern union {...@@ -410,6 +416,7 @@ pub const Type = extern union {
410 .comptime_int,416 .comptime_int,
411 .comptime_float,417 .comptime_float,
412 .noreturn,418 .noreturn,
419 .fn_noreturn_no_args,
413 .fn_naked_noreturn_no_args,420 .fn_naked_noreturn_no_args,
414 .fn_ccc_void_no_args,421 .fn_ccc_void_no_args,
415 .int_unsigned,422 .int_unsigned,
...@@ -451,6 +458,7 @@ pub const Type = extern union {...@@ -451,6 +458,7 @@ pub const Type = extern union {
451 .comptime_int,458 .comptime_int,
452 .comptime_float,459 .comptime_float,
453 .noreturn,460 .noreturn,
461 .fn_noreturn_no_args,
454 .fn_naked_noreturn_no_args,462 .fn_naked_noreturn_no_args,
455 .fn_ccc_void_no_args,463 .fn_ccc_void_no_args,
456 .single_const_pointer,464 .single_const_pointer,
...@@ -481,6 +489,7 @@ pub const Type = extern union {...@@ -481,6 +489,7 @@ pub const Type = extern union {
481 .comptime_int,489 .comptime_int,
482 .comptime_float,490 .comptime_float,
483 .noreturn,491 .noreturn,
492 .fn_noreturn_no_args,
484 .fn_naked_noreturn_no_args,493 .fn_naked_noreturn_no_args,
485 .fn_ccc_void_no_args,494 .fn_ccc_void_no_args,
486 .array,495 .array,
...@@ -524,6 +533,7 @@ pub const Type = extern union {...@@ -524,6 +533,7 @@ pub const Type = extern union {
524 .comptime_int,533 .comptime_int,
525 .comptime_float,534 .comptime_float,
526 .noreturn,535 .noreturn,
536 .fn_noreturn_no_args,
527 .fn_naked_noreturn_no_args,537 .fn_naked_noreturn_no_args,
528 .fn_ccc_void_no_args,538 .fn_ccc_void_no_args,
529 .array,539 .array,
...@@ -579,6 +589,7 @@ pub const Type = extern union {...@@ -579,6 +589,7 @@ pub const Type = extern union {
579 /// Asserts the type is a function.589 /// Asserts the type is a function.
580 pub fn fnParamLen(self: Type) usize {590 pub fn fnParamLen(self: Type) usize {
581 return switch (self.tag()) {591 return switch (self.tag()) {
592 .fn_noreturn_no_args => 0,
582 .fn_naked_noreturn_no_args => 0,593 .fn_naked_noreturn_no_args => 0,
583 .fn_ccc_void_no_args => 0,594 .fn_ccc_void_no_args => 0,
584595
...@@ -622,6 +633,7 @@ pub const Type = extern union {...@@ -622,6 +633,7 @@ pub const Type = extern union {
622 /// given by `fnParamLen`.633 /// given by `fnParamLen`.
623 pub fn fnParamTypes(self: Type, types: []Type) void {634 pub fn fnParamTypes(self: Type, types: []Type) void {
624 switch (self.tag()) {635 switch (self.tag()) {
636 .fn_noreturn_no_args => return,
625 .fn_naked_noreturn_no_args => return,637 .fn_naked_noreturn_no_args => return,
626 .fn_ccc_void_no_args => return,638 .fn_ccc_void_no_args => return,
627639
...@@ -664,6 +676,7 @@ pub const Type = extern union {...@@ -664,6 +676,7 @@ pub const Type = extern union {
664 /// Asserts the type is a function.676 /// Asserts the type is a function.
665 pub fn fnReturnType(self: Type) Type {677 pub fn fnReturnType(self: Type) Type {
666 return switch (self.tag()) {678 return switch (self.tag()) {
679 .fn_noreturn_no_args => Type.initTag(.noreturn),
667 .fn_naked_noreturn_no_args => Type.initTag(.noreturn),680 .fn_naked_noreturn_no_args => Type.initTag(.noreturn),
668 .fn_ccc_void_no_args => Type.initTag(.void),681 .fn_ccc_void_no_args => Type.initTag(.void),
669682
...@@ -706,6 +719,7 @@ pub const Type = extern union {...@@ -706,6 +719,7 @@ pub const Type = extern union {
706 /// Asserts the type is a function.719 /// Asserts the type is a function.
707 pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {720 pub fn fnCallingConvention(self: Type) std.builtin.CallingConvention {
708 return switch (self.tag()) {721 return switch (self.tag()) {
722 .fn_noreturn_no_args => .Unspecified,
709 .fn_naked_noreturn_no_args => .Naked,723 .fn_naked_noreturn_no_args => .Naked,
710 .fn_ccc_void_no_args => .C,724 .fn_ccc_void_no_args => .C,
711725
...@@ -745,6 +759,49 @@ pub const Type = extern union {...@@ -745,6 +759,49 @@ pub const Type = extern union {
745 };759 };
746 }760 }
747761
762 /// Asserts the type is a function.
763 pub fn fnIsVarArgs(self: Type) bool {
764 return switch (self.tag()) {
765 .fn_noreturn_no_args => false,
766 .fn_naked_noreturn_no_args => false,
767 .fn_ccc_void_no_args => false,
768
769 .f16,
770 .f32,
771 .f64,
772 .f128,
773 .c_longdouble,
774 .c_void,
775 .bool,
776 .void,
777 .type,
778 .anyerror,
779 .comptime_int,
780 .comptime_float,
781 .noreturn,
782 .array,
783 .single_const_pointer,
784 .single_const_pointer_to_comptime_int,
785 .array_u8_sentinel_0,
786 .const_slice_u8,
787 .u8,
788 .i8,
789 .usize,
790 .isize,
791 .c_short,
792 .c_ushort,
793 .c_int,
794 .c_uint,
795 .c_long,
796 .c_ulong,
797 .c_longlong,
798 .c_ulonglong,
799 .int_unsigned,
800 .int_signed,
801 => unreachable,
802 };
803 }
804
748 pub fn isNumeric(self: Type) bool {805 pub fn isNumeric(self: Type) bool {
749 return switch (self.tag()) {806 return switch (self.tag()) {
750 .f16,807 .f16,
...@@ -776,6 +833,7 @@ pub const Type = extern union {...@@ -776,6 +833,7 @@ pub const Type = extern union {
776 .type,833 .type,
777 .anyerror,834 .anyerror,
778 .noreturn,835 .noreturn,
836 .fn_noreturn_no_args,
779 .fn_naked_noreturn_no_args,837 .fn_naked_noreturn_no_args,
780 .fn_ccc_void_no_args,838 .fn_ccc_void_no_args,
781 .array,839 .array,
...@@ -812,6 +870,7 @@ pub const Type = extern union {...@@ -812,6 +870,7 @@ pub const Type = extern union {
812 .bool,870 .bool,
813 .type,871 .type,
814 .anyerror,872 .anyerror,
873 .fn_noreturn_no_args,
815 .fn_naked_noreturn_no_args,874 .fn_naked_noreturn_no_args,
816 .fn_ccc_void_no_args,875 .fn_ccc_void_no_args,
817 .single_const_pointer_to_comptime_int,876 .single_const_pointer_to_comptime_int,
...@@ -865,6 +924,7 @@ pub const Type = extern union {...@@ -865,6 +924,7 @@ pub const Type = extern union {
865 .bool,924 .bool,
866 .type,925 .type,
867 .anyerror,926 .anyerror,
927 .fn_noreturn_no_args,
868 .fn_naked_noreturn_no_args,928 .fn_naked_noreturn_no_args,
869 .fn_ccc_void_no_args,929 .fn_ccc_void_no_args,
870 .single_const_pointer_to_comptime_int,930 .single_const_pointer_to_comptime_int,
...@@ -902,11 +962,11 @@ pub const Type = extern union {...@@ -902,11 +962,11 @@ pub const Type = extern union {
902 c_longlong,962 c_longlong,
903 c_ulonglong,963 c_ulonglong,
904 c_longdouble,964 c_longdouble,
905 c_void,
906 f16,965 f16,
907 f32,966 f32,
908 f64,967 f64,
909 f128,968 f128,
969 c_void,
910 bool,970 bool,
911 void,971 void,
912 type,972 type,
...@@ -914,6 +974,7 @@ pub const Type = extern union {...@@ -914,6 +974,7 @@ pub const Type = extern union {
914 comptime_int,974 comptime_int,
915 comptime_float,975 comptime_float,
916 noreturn,976 noreturn,
977 fn_noreturn_no_args,
917 fn_naked_noreturn_no_args,978 fn_naked_noreturn_no_args,
918 fn_ccc_void_no_args,979 fn_ccc_void_no_args,
919 single_const_pointer_to_comptime_int,980 single_const_pointer_to_comptime_int,
src-self-hosted/util.zig deleted-47
...@@ -1,47 +0,0 @@
1const std = @import("std");
2const Target = std.Target;
3const llvm = @import("llvm.zig");
4
5pub fn getDarwinArchString(self: Target) [:0]const u8 {
6 switch (self.cpu.arch) {
7 .aarch64 => return "arm64",
8 .thumb,
9 .arm,
10 => return "arm",
11 .powerpc => return "ppc",
12 .powerpc64 => return "ppc64",
13 .powerpc64le => return "ppc64le",
14 // @tagName should be able to return sentinel terminated slice
15 else => @panic("TODO https://github.com/ziglang/zig/issues/3779"), //return @tagName(arch),
16 }
17}
18
19pub fn llvmTargetFromTriple(triple: [:0]const u8) !*llvm.Target {
20 var result: *llvm.Target = undefined;
21 var err_msg: [*:0]u8 = undefined;
22 if (llvm.GetTargetFromTriple(triple, &result, &err_msg) != 0) {
23 std.debug.warn("triple: {s} error: {s}\n", .{ triple, err_msg });
24 return error.UnsupportedTarget;
25 }
26 return result;
27}
28
29pub fn initializeAllTargets() void {
30 llvm.InitializeAllTargets();
31 llvm.InitializeAllTargetInfos();
32 llvm.InitializeAllTargetMCs();
33 llvm.InitializeAllAsmPrinters();
34 llvm.InitializeAllAsmParsers();
35}
36
37pub fn getLLVMTriple(allocator: *std.mem.Allocator, target: std.Target) ![:0]u8 {
38 var result = try std.ArrayListSentineled(u8, 0).initSize(allocator, 0);
39 defer result.deinit();
40
41 try result.outStream().print(
42 "{}-unknown-{}-{}",
43 .{ @tagName(target.cpu.arch), @tagName(target.os.tag), @tagName(target.abi) },
44 );
45
46 return result.toOwnedSlice();
47}
src-self-hosted/value.zig+96-90
...@@ -6,6 +6,7 @@ const BigIntConst = std.math.big.int.Const;...@@ -6,6 +6,7 @@ const BigIntConst = std.math.big.int.Const;
6const BigIntMutable = std.math.big.int.Mutable;6const BigIntMutable = std.math.big.int.Mutable;
7const Target = std.Target;7const Target = std.Target;
8const Allocator = std.mem.Allocator;8const Allocator = std.mem.Allocator;
9const ir = @import("ir.zig");
910
10/// This is the raw data, with no bookkeeping, no memory awareness,11/// This is the raw data, with no bookkeeping, no memory awareness,
11/// no de-duplication, and no type system awareness.12/// no de-duplication, and no type system awareness.
...@@ -45,6 +46,7 @@ pub const Value = extern union {...@@ -45,6 +46,7 @@ pub const Value = extern union {
45 comptime_int_type,46 comptime_int_type,
46 comptime_float_type,47 comptime_float_type,
47 noreturn_type,48 noreturn_type,
49 fn_noreturn_no_args_type,
48 fn_naked_noreturn_no_args_type,50 fn_naked_noreturn_no_args_type,
49 fn_ccc_void_no_args_type,51 fn_ccc_void_no_args_type,
50 single_const_pointer_to_comptime_int_type,52 single_const_pointer_to_comptime_int_type,
...@@ -64,8 +66,8 @@ pub const Value = extern union {...@@ -64,8 +66,8 @@ pub const Value = extern union {
64 int_big_positive,66 int_big_positive,
65 int_big_negative,67 int_big_negative,
66 function,68 function,
67 ref,69 decl_ref,
68 ref_val,70 elem_ptr,
69 bytes,71 bytes,
70 repeated, // the value is a value repeated some number of times72 repeated, // the value is a value repeated some number of times
7173
...@@ -136,6 +138,7 @@ pub const Value = extern union {...@@ -136,6 +138,7 @@ pub const Value = extern union {
136 .comptime_int_type => return out_stream.writeAll("comptime_int"),138 .comptime_int_type => return out_stream.writeAll("comptime_int"),
137 .comptime_float_type => return out_stream.writeAll("comptime_float"),139 .comptime_float_type => return out_stream.writeAll("comptime_float"),
138 .noreturn_type => return out_stream.writeAll("noreturn"),140 .noreturn_type => return out_stream.writeAll("noreturn"),
141 .fn_noreturn_no_args_type => return out_stream.writeAll("fn() noreturn"),
139 .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),142 .fn_naked_noreturn_no_args_type => return out_stream.writeAll("fn() callconv(.Naked) noreturn"),
140 .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),143 .fn_ccc_void_no_args_type => return out_stream.writeAll("fn() callconv(.C) void"),
141 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),144 .single_const_pointer_to_comptime_int_type => return out_stream.writeAll("*const comptime_int"),
...@@ -153,11 +156,11 @@ pub const Value = extern union {...@@ -153,11 +156,11 @@ pub const Value = extern union {
153 .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}),156 .int_big_positive => return out_stream.print("{}", .{val.cast(Payload.IntBigPositive).?.asBigInt()}),
154 .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}),157 .int_big_negative => return out_stream.print("{}", .{val.cast(Payload.IntBigNegative).?.asBigInt()}),
155 .function => return out_stream.writeAll("(function)"),158 .function => return out_stream.writeAll("(function)"),
156 .ref => return out_stream.writeAll("(ref)"),159 .decl_ref => return out_stream.writeAll("(decl ref)"),
157 .ref_val => {160 .elem_ptr => {
158 try out_stream.writeAll("*const ");161 const elem_ptr = val.cast(Payload.Int_u64).?;
159 val = val.cast(Payload.RefVal).?.val;162 try out_stream.print("&[{}] ", .{elem_ptr.index});
160 continue;163 val = elem_ptr.array_ptr;
161 },164 },
162 .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream),165 .bytes => return std.zig.renderStringLiteral(self.cast(Payload.Bytes).?.data, out_stream),
163 .repeated => {166 .repeated => {
...@@ -181,31 +184,32 @@ pub const Value = extern union {...@@ -181,31 +184,32 @@ pub const Value = extern union {
181 return switch (self.tag()) {184 return switch (self.tag()) {
182 .ty => self.cast(Payload.Ty).?.ty,185 .ty => self.cast(Payload.Ty).?.ty,
183186
184 .u8_type => Type.initTag(.@"u8"),187 .u8_type => Type.initTag(.u8),
185 .i8_type => Type.initTag(.@"i8"),188 .i8_type => Type.initTag(.i8),
186 .isize_type => Type.initTag(.@"isize"),189 .isize_type => Type.initTag(.isize),
187 .usize_type => Type.initTag(.@"usize"),190 .usize_type => Type.initTag(.usize),
188 .c_short_type => Type.initTag(.@"c_short"),191 .c_short_type => Type.initTag(.c_short),
189 .c_ushort_type => Type.initTag(.@"c_ushort"),192 .c_ushort_type => Type.initTag(.c_ushort),
190 .c_int_type => Type.initTag(.@"c_int"),193 .c_int_type => Type.initTag(.c_int),
191 .c_uint_type => Type.initTag(.@"c_uint"),194 .c_uint_type => Type.initTag(.c_uint),
192 .c_long_type => Type.initTag(.@"c_long"),195 .c_long_type => Type.initTag(.c_long),
193 .c_ulong_type => Type.initTag(.@"c_ulong"),196 .c_ulong_type => Type.initTag(.c_ulong),
194 .c_longlong_type => Type.initTag(.@"c_longlong"),197 .c_longlong_type => Type.initTag(.c_longlong),
195 .c_ulonglong_type => Type.initTag(.@"c_ulonglong"),198 .c_ulonglong_type => Type.initTag(.c_ulonglong),
196 .c_longdouble_type => Type.initTag(.@"c_longdouble"),199 .c_longdouble_type => Type.initTag(.c_longdouble),
197 .f16_type => Type.initTag(.@"f16"),200 .f16_type => Type.initTag(.f16),
198 .f32_type => Type.initTag(.@"f32"),201 .f32_type => Type.initTag(.f32),
199 .f64_type => Type.initTag(.@"f64"),202 .f64_type => Type.initTag(.f64),
200 .f128_type => Type.initTag(.@"f128"),203 .f128_type => Type.initTag(.f128),
201 .c_void_type => Type.initTag(.@"c_void"),204 .c_void_type => Type.initTag(.c_void),
202 .bool_type => Type.initTag(.@"bool"),205 .bool_type => Type.initTag(.bool),
203 .void_type => Type.initTag(.@"void"),206 .void_type => Type.initTag(.void),
204 .type_type => Type.initTag(.@"type"),207 .type_type => Type.initTag(.type),
205 .anyerror_type => Type.initTag(.@"anyerror"),208 .anyerror_type => Type.initTag(.anyerror),
206 .comptime_int_type => Type.initTag(.@"comptime_int"),209 .comptime_int_type => Type.initTag(.comptime_int),
207 .comptime_float_type => Type.initTag(.@"comptime_float"),210 .comptime_float_type => Type.initTag(.comptime_float),
208 .noreturn_type => Type.initTag(.@"noreturn"),211 .noreturn_type => Type.initTag(.noreturn),
212 .fn_noreturn_no_args_type => Type.initTag(.fn_noreturn_no_args),
209 .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),213 .fn_naked_noreturn_no_args_type => Type.initTag(.fn_naked_noreturn_no_args),
210 .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),214 .fn_ccc_void_no_args_type => Type.initTag(.fn_ccc_void_no_args),
211 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),215 .single_const_pointer_to_comptime_int_type => Type.initTag(.single_const_pointer_to_comptime_int),
...@@ -222,8 +226,8 @@ pub const Value = extern union {...@@ -222,8 +226,8 @@ pub const Value = extern union {
222 .int_big_positive,226 .int_big_positive,
223 .int_big_negative,227 .int_big_negative,
224 .function,228 .function,
225 .ref,229 .decl_ref,
226 .ref_val,230 .elem_ptr,
227 .bytes,231 .bytes,
228 .repeated,232 .repeated,
229 => unreachable,233 => unreachable,
...@@ -259,6 +263,7 @@ pub const Value = extern union {...@@ -259,6 +263,7 @@ pub const Value = extern union {
259 .comptime_int_type,263 .comptime_int_type,
260 .comptime_float_type,264 .comptime_float_type,
261 .noreturn_type,265 .noreturn_type,
266 .fn_noreturn_no_args_type,
262 .fn_naked_noreturn_no_args_type,267 .fn_naked_noreturn_no_args_type,
263 .fn_ccc_void_no_args_type,268 .fn_ccc_void_no_args_type,
264 .single_const_pointer_to_comptime_int_type,269 .single_const_pointer_to_comptime_int_type,
...@@ -267,8 +272,8 @@ pub const Value = extern union {...@@ -267,8 +272,8 @@ pub const Value = extern union {
267 .bool_false,272 .bool_false,
268 .null_value,273 .null_value,
269 .function,274 .function,
270 .ref,275 .decl_ref,
271 .ref_val,276 .elem_ptr,
272 .bytes,277 .bytes,
273 .undef,278 .undef,
274 .repeated,279 .repeated,
...@@ -314,6 +319,7 @@ pub const Value = extern union {...@@ -314,6 +319,7 @@ pub const Value = extern union {
314 .comptime_int_type,319 .comptime_int_type,
315 .comptime_float_type,320 .comptime_float_type,
316 .noreturn_type,321 .noreturn_type,
322 .fn_noreturn_no_args_type,
317 .fn_naked_noreturn_no_args_type,323 .fn_naked_noreturn_no_args_type,
318 .fn_ccc_void_no_args_type,324 .fn_ccc_void_no_args_type,
319 .single_const_pointer_to_comptime_int_type,325 .single_const_pointer_to_comptime_int_type,
...@@ -322,8 +328,8 @@ pub const Value = extern union {...@@ -322,8 +328,8 @@ pub const Value = extern union {
322 .bool_false,328 .bool_false,
323 .null_value,329 .null_value,
324 .function,330 .function,
325 .ref,331 .decl_ref,
326 .ref_val,332 .elem_ptr,
327 .bytes,333 .bytes,
328 .undef,334 .undef,
329 .repeated,335 .repeated,
...@@ -370,6 +376,7 @@ pub const Value = extern union {...@@ -370,6 +376,7 @@ pub const Value = extern union {
370 .comptime_int_type,376 .comptime_int_type,
371 .comptime_float_type,377 .comptime_float_type,
372 .noreturn_type,378 .noreturn_type,
379 .fn_noreturn_no_args_type,
373 .fn_naked_noreturn_no_args_type,380 .fn_naked_noreturn_no_args_type,
374 .fn_ccc_void_no_args_type,381 .fn_ccc_void_no_args_type,
375 .single_const_pointer_to_comptime_int_type,382 .single_const_pointer_to_comptime_int_type,
...@@ -378,8 +385,8 @@ pub const Value = extern union {...@@ -378,8 +385,8 @@ pub const Value = extern union {
378 .bool_false,385 .bool_false,
379 .null_value,386 .null_value,
380 .function,387 .function,
381 .ref,388 .decl_ref,
382 .ref_val,389 .elem_ptr,
383 .bytes,390 .bytes,
384 .undef,391 .undef,
385 .repeated,392 .repeated,
...@@ -431,6 +438,7 @@ pub const Value = extern union {...@@ -431,6 +438,7 @@ pub const Value = extern union {
431 .comptime_int_type,438 .comptime_int_type,
432 .comptime_float_type,439 .comptime_float_type,
433 .noreturn_type,440 .noreturn_type,
441 .fn_noreturn_no_args_type,
434 .fn_naked_noreturn_no_args_type,442 .fn_naked_noreturn_no_args_type,
435 .fn_ccc_void_no_args_type,443 .fn_ccc_void_no_args_type,
436 .single_const_pointer_to_comptime_int_type,444 .single_const_pointer_to_comptime_int_type,
...@@ -439,8 +447,8 @@ pub const Value = extern union {...@@ -439,8 +447,8 @@ pub const Value = extern union {
439 .bool_false,447 .bool_false,
440 .null_value,448 .null_value,
441 .function,449 .function,
442 .ref,450 .decl_ref,
443 .ref_val,451 .elem_ptr,
444 .bytes,452 .bytes,
445 .repeated,453 .repeated,
446 => unreachable,454 => unreachable,
...@@ -521,6 +529,7 @@ pub const Value = extern union {...@@ -521,6 +529,7 @@ pub const Value = extern union {
521 .comptime_int_type,529 .comptime_int_type,
522 .comptime_float_type,530 .comptime_float_type,
523 .noreturn_type,531 .noreturn_type,
532 .fn_noreturn_no_args_type,
524 .fn_naked_noreturn_no_args_type,533 .fn_naked_noreturn_no_args_type,
525 .fn_ccc_void_no_args_type,534 .fn_ccc_void_no_args_type,
526 .single_const_pointer_to_comptime_int_type,535 .single_const_pointer_to_comptime_int_type,
...@@ -529,8 +538,8 @@ pub const Value = extern union {...@@ -529,8 +538,8 @@ pub const Value = extern union {
529 .bool_false,538 .bool_false,
530 .null_value,539 .null_value,
531 .function,540 .function,
532 .ref,541 .decl_ref,
533 .ref_val,542 .elem_ptr,
534 .bytes,543 .bytes,
535 .repeated,544 .repeated,
536 .undef,545 .undef,
...@@ -573,6 +582,7 @@ pub const Value = extern union {...@@ -573,6 +582,7 @@ pub const Value = extern union {
573 .comptime_int_type,582 .comptime_int_type,
574 .comptime_float_type,583 .comptime_float_type,
575 .noreturn_type,584 .noreturn_type,
585 .fn_noreturn_no_args_type,
576 .fn_naked_noreturn_no_args_type,586 .fn_naked_noreturn_no_args_type,
577 .fn_ccc_void_no_args_type,587 .fn_ccc_void_no_args_type,
578 .single_const_pointer_to_comptime_int_type,588 .single_const_pointer_to_comptime_int_type,
...@@ -581,8 +591,8 @@ pub const Value = extern union {...@@ -581,8 +591,8 @@ pub const Value = extern union {
581 .bool_false,591 .bool_false,
582 .null_value,592 .null_value,
583 .function,593 .function,
584 .ref,594 .decl_ref,
585 .ref_val,595 .elem_ptr,
586 .bytes,596 .bytes,
587 .repeated,597 .repeated,
588 .undef,598 .undef,
...@@ -636,7 +646,7 @@ pub const Value = extern union {...@@ -636,7 +646,7 @@ pub const Value = extern union {
636 }646 }
637647
638 /// Asserts the value is a pointer and dereferences it.648 /// Asserts the value is a pointer and dereferences it.
639 pub fn pointerDeref(self: Value) Value {649 pub fn pointerDeref(self: Value, module: *ir.Module) !Value {
640 return switch (self.tag()) {650 return switch (self.tag()) {
641 .ty,651 .ty,
642 .u8_type,652 .u8_type,
...@@ -664,6 +674,7 @@ pub const Value = extern union {...@@ -664,6 +674,7 @@ pub const Value = extern union {
664 .comptime_int_type,674 .comptime_int_type,
665 .comptime_float_type,675 .comptime_float_type,
666 .noreturn_type,676 .noreturn_type,
677 .fn_noreturn_no_args_type,
667 .fn_naked_noreturn_no_args_type,678 .fn_naked_noreturn_no_args_type,
668 .fn_ccc_void_no_args_type,679 .fn_ccc_void_no_args_type,
669 .single_const_pointer_to_comptime_int_type,680 .single_const_pointer_to_comptime_int_type,
...@@ -683,14 +694,21 @@ pub const Value = extern union {...@@ -683,14 +694,21 @@ pub const Value = extern union {
683 => unreachable,694 => unreachable,
684695
685 .the_one_possible_value => Value.initTag(.the_one_possible_value),696 .the_one_possible_value => Value.initTag(.the_one_possible_value),
686 .ref => self.cast(Payload.Ref).?.cell.contents,697 .decl_ref => {
687 .ref_val => self.cast(Payload.RefVal).?.val,698 const index = self.cast(Payload.DeclRef).?.index;
699 return module.getDeclValue(index);
700 },
701 .elem_ptr => {
702 const elem_ptr = self.cast(ElemPtr).?;
703 const array_val = try elem_ptr.array_ptr.pointerDeref(module);
704 return self.elemValue(array_val, elem_ptr.index);
705 },
688 };706 };
689 }707 }
690708
691 /// Asserts the value is a single-item pointer to an array, or an array,709 /// Asserts the value is a single-item pointer to an array, or an array,
692 /// or an unknown-length pointer, and returns the element value at the index.710 /// or an unknown-length pointer, and returns the element value at the index.
693 pub fn elemValueAt(self: Value, allocator: *Allocator, index: usize) Allocator.Error!Value {711 pub fn elemValue(self: Value, index: usize) Value {
694 switch (self.tag()) {712 switch (self.tag()) {
695 .ty,713 .ty,
696 .u8_type,714 .u8_type,
...@@ -718,6 +736,7 @@ pub const Value = extern union {...@@ -718,6 +736,7 @@ pub const Value = extern union {
718 .comptime_int_type,736 .comptime_int_type,
719 .comptime_float_type,737 .comptime_float_type,
720 .noreturn_type,738 .noreturn_type,
739 .fn_noreturn_no_args_type,
721 .fn_naked_noreturn_no_args_type,740 .fn_naked_noreturn_no_args_type,
722 .fn_ccc_void_no_args_type,741 .fn_ccc_void_no_args_type,
723 .single_const_pointer_to_comptime_int_type,742 .single_const_pointer_to_comptime_int_type,
...@@ -733,13 +752,12 @@ pub const Value = extern union {...@@ -733,13 +752,12 @@ pub const Value = extern union {
733 .int_big_positive,752 .int_big_positive,
734 .int_big_negative,753 .int_big_negative,
735 .undef,754 .undef,
755 .elem_ptr,
756 .decl_ref,
736 => unreachable,757 => unreachable,
737758
738 .ref => @panic("TODO figure out how MemoryCell works"),
739 .ref_val => @panic("TODO figure out how MemoryCell works"),
740
741 .bytes => {759 .bytes => {
742 const int_payload = try allocator.create(Value.Payload.Int_u64);760 const int_payload = try allocator.create(Payload.Int_u64);
743 int_payload.* = .{ .int = self.cast(Payload.Bytes).?.data[index] };761 int_payload.* = .{ .int = self.cast(Payload.Bytes).?.data[index] };
744 return Value.initPayload(&int_payload.base);762 return Value.initPayload(&int_payload.base);
745 },763 },
...@@ -749,6 +767,17 @@ pub const Value = extern union {...@@ -749,6 +767,17 @@ pub const Value = extern union {
749 }767 }
750 }768 }
751769
770 /// Returns a pointer to the element value at the index.
771 pub fn elemPtr(self: Value, allocator: *Allocator, index: usize) !Value {
772 const payload = try allocator.create(Payload.ElemPtr);
773 if (self.cast(Payload.ElemPtr)) |elem_ptr| {
774 payload.* = .{ .array_ptr = elem_ptr.array_ptr, .index = elem_ptr.index + index };
775 } else {
776 payload.* = .{ .array_ptr = self, .index = index };
777 }
778 return Value.initPayload(&payload.base);
779 }
780
752 pub fn isUndef(self: Value) bool {781 pub fn isUndef(self: Value) bool {
753 return self.tag() == .undef;782 return self.tag() == .undef;
754 }783 }
...@@ -783,6 +812,7 @@ pub const Value = extern union {...@@ -783,6 +812,7 @@ pub const Value = extern union {
783 .comptime_int_type,812 .comptime_int_type,
784 .comptime_float_type,813 .comptime_float_type,
785 .noreturn_type,814 .noreturn_type,
815 .fn_noreturn_no_args_type,
786 .fn_naked_noreturn_no_args_type,816 .fn_naked_noreturn_no_args_type,
787 .fn_ccc_void_no_args_type,817 .fn_ccc_void_no_args_type,
788 .single_const_pointer_to_comptime_int_type,818 .single_const_pointer_to_comptime_int_type,
...@@ -796,8 +826,8 @@ pub const Value = extern union {...@@ -796,8 +826,8 @@ pub const Value = extern union {
796 .int_i64,826 .int_i64,
797 .int_big_positive,827 .int_big_positive,
798 .int_big_negative,828 .int_big_negative,
799 .ref,829 .decl_ref,
800 .ref_val,830 .elem_ptr,
801 .bytes,831 .bytes,
802 .repeated,832 .repeated,
803 => false,833 => false,
...@@ -841,8 +871,7 @@ pub const Value = extern union {...@@ -841,8 +871,7 @@ pub const Value = extern union {
841871
842 pub const Function = struct {872 pub const Function = struct {
843 base: Payload = Payload{ .tag = .function },873 base: Payload = Payload{ .tag = .function },
844 /// Index into the `fns` array of the `ir.Module`874 func: *ir.Module.Fn,
845 index: usize,
846 };875 };
847876
848 pub const ArraySentinel0_u8_Type = struct {877 pub const ArraySentinel0_u8_Type = struct {
...@@ -855,14 +884,17 @@ pub const Value = extern union {...@@ -855,14 +884,17 @@ pub const Value = extern union {
855 elem_type: *Type,884 elem_type: *Type,
856 };885 };
857886
858 pub const Ref = struct {887 /// Represents a pointer to a decl, not the value of the decl.
859 base: Payload = Payload{ .tag = .ref },888 pub const DeclRef = struct {
860 cell: *MemoryCell,889 base: Payload = Payload{ .tag = .decl_ref },
890 /// Index into the Module's decls list
891 index: usize,
861 };892 };
862893
863 pub const RefVal = struct {894 pub const ElemPtr = struct {
864 base: Payload = Payload{ .tag = .ref_val },895 base: Payload = Payload{ .tag = .elem_ptr },
865 val: Value,896 array_ptr: Value,
897 index: usize,
866 };898 };
867899
868 pub const Bytes = struct {900 pub const Bytes = struct {
...@@ -890,29 +922,3 @@ pub const Value = extern union {...@@ -890,29 +922,3 @@ pub const Value = extern union {
890 limbs: [(@sizeOf(u64) / @sizeOf(std.math.big.Limb)) + 1]std.math.big.Limb,922 limbs: [(@sizeOf(u64) / @sizeOf(std.math.big.Limb)) + 1]std.math.big.Limb,
891 };923 };
892};924};
893
894/// This is the heart of resource management of the Zig compiler. The Zig compiler uses
895/// stop-the-world mark-and-sweep garbage collection during compilation to manage the resources
896/// associated with evaluating compile-time code and semantic analysis. Each `MemoryCell` represents
897/// a root.
898pub const MemoryCell = struct {
899 parent: Parent,
900 contents: Value,
901
902 pub const Parent = union(enum) {
903 none,
904 struct_field: struct {
905 struct_base: *MemoryCell,
906 field_index: usize,
907 },
908 array_elem: struct {
909 array_base: *MemoryCell,
910 elem_index: usize,
911 },
912 union_field: *MemoryCell,
913 err_union_code: *MemoryCell,
914 err_union_payload: *MemoryCell,
915 optional_payload: *MemoryCell,
916 optional_flag: *MemoryCell,
917 };
918};
src-self-hosted/visib.zig deleted-4
...@@ -1,4 +0,0 @@
1pub const Visib = enum {
2 Private,
3 Pub,
4};