stage2: rework the C backend

* std.ArrayList gains `moveToUnmanaged` and dead code
   `ArrayListUnmanaged.appendWrite` is deleted.
 * emit_h state is attached to Module rather than Compilation.
 * remove the implementation of emit-h because it did not properly
   integrate with incremental compilation. I will re-implement it
   in a follow-up commit.
 * Compilation: use the .codegen_failure tag rather than
   .dependency_failure tag for when `bin_file.updateDecl` fails.

C backend:
 * Use a CValue tagged union instead of strings for C values.
 * Cleanly separate state into Object and DeclGen:
   - Object is present only when generating a .c file
   - DeclGen is present for both generating a .c and .h
 * Move some functions into their respective Object/DeclGen namespace.
 * Forward decls are managed by the incremental compilation frontend; C
   backend no longer renders function signatures based on callsites.
   For simplicity, all functions always get forward decls.
 * Constants are managed by the incremental compilation frontend. C
   backend no longer has a "constants" section.
 * Participate in incremental compilation. Each Decl gets an ArrayList
   for its generated C code and it is updated when the Decl is updated.
   During flush(), all these are joined together in the output file.
 * The new CValue tagged union is used to clean up using of assigning to
   locals without an additional pointer local.
 * Fix bug with bitcast of non-pointers making the memcpy destination
   immutable.
This commit is contained in:
Andrew Kelley
2021-01-05 11:08:34 -07:00
parent 9360e5887c
commit 7b8cede61f
9 changed files with 661 additions and 613 deletions

View File

@@ -100,10 +100,20 @@ pub fn ArrayListAligned(comptime T: type, comptime alignment: ?u29) type {
/// Initializes an ArrayListUnmanaged with the `items` and `capacity` fields
/// of this ArrayList. This ArrayList retains ownership of underlying memory.
/// Deprecated: use `moveToUnmanaged` which has different semantics.
pub fn toUnmanaged(self: Self) ArrayListAlignedUnmanaged(T, alignment) {
return .{ .items = self.items, .capacity = self.capacity };
}
/// Initializes an ArrayListUnmanaged with the `items` and `capacity` fields
/// of this ArrayList. Empties this ArrayList.
pub fn moveToUnmanaged(self: *Self) ArrayListAlignedUnmanaged(T, alignment) {
const allocator = self.allocator;
const result = .{ .items = self.items, .capacity = self.capacity };
self.* = init(allocator);
return result;
}
/// The caller owns the returned memory. Empties this ArrayList.
pub fn toOwnedSlice(self: *Self) Slice {
const allocator = self.allocator;
@@ -551,14 +561,6 @@ pub fn ArrayListAlignedUnmanaged(comptime T: type, comptime alignment: ?u29) typ
mem.copy(T, self.items[oldlen..], items);
}
/// Same as `append` except it returns the number of bytes written, which is always the same
/// as `m.len`. The purpose of this function existing is to match `std.io.OutStream` API.
/// This function may be called only when `T` is `u8`.
fn appendWrite(self: *Self, allocator: *Allocator, m: []const u8) !usize {
try self.appendSlice(allocator, m);
return m.len;
}
/// Append a value to the list `n` times.
/// Allocates more memory as necessary.
pub fn appendNTimes(self: *Self, allocator: *Allocator, value: T, n: usize) !void {
@@ -1129,13 +1131,13 @@ test "std.ArrayList/ArrayListUnmanaged: ArrayList(T) of struct T" {
}
}
test "std.ArrayList(u8) implements outStream" {
test "std.ArrayList(u8) implements writer" {
var buffer = ArrayList(u8).init(std.testing.allocator);
defer buffer.deinit();
const x: i32 = 42;
const y: i32 = 1234;
try buffer.outStream().print("x: {}\ny: {}\n", .{ x, y });
try buffer.writer().print("x: {}\ny: {}\n", .{ x, y });
testing.expectEqualSlices(u8, "x: 42\ny: 1234\n", buffer.items);
}