aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/codegen.zig24
-rw-r--r--src/compile.zig49
-rw-r--r--src/main.zig24
3 files changed, 58 insertions, 39 deletions
diff --git a/src/codegen.zig b/src/codegen.zig
index 1e8ed41..fe58f74 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -560,10 +560,11 @@ const Context = struct {
try self.instructions.append(inst);
}
- fn maybeFreeSources(self: *Context, vregs: compile.Instr.Sources) !void {
- for (vregs.slice()) |src| {
- if (self.block.?.vreg_last_use.get(src) == self.current_instruction_index.?) {
- self.register_allocator.free(src);
+ fn maybeFreeSources(self: *Context) !void {
+ const index = self.current_instruction_index.?;
+ if (self.block.?.vreg_last_use.get(index)) |last_used_here| {
+ for (last_used_here.items) |vreg| {
+ self.register_allocator.free(vreg);
}
}
}
@@ -601,7 +602,7 @@ const Context = struct {
fn genBinOp(self: *Context, bin_op: compile.Instr.BinOp) !void {
const lhs = self.register_allocator.get(bin_op.lhs);
const rhs = self.register_allocator.get(bin_op.rhs);
- try self.maybeFreeSources(bin_op.sources());
+ try self.maybeFreeSources();
const reg = try self.register_allocator.allocate(bin_op.dest);
switch (bin_op.op) {
.add => try self.emit(.add(reg, lhs, rhs)),
@@ -616,10 +617,9 @@ const Context = struct {
defer self.register_allocator.freeAux(quot);
const digit = try self.register_allocator.allocateAux();
defer self.register_allocator.freeAux(digit);
- const count = try self.register_allocator.allocateAux();
- defer self.register_allocator.freeAux(count);
+ const count = try self.register_allocator.allocate(print.dest);
- try self.maybeFreeSources(print.sources());
+ try self.maybeFreeSources();
try self.emit(.addi(digit, .zero, '\n'));
try self.emit(.addi(.sp, .sp, -1));
@@ -642,6 +642,12 @@ const Context = struct {
try self.emit(.addi(.a2, count, 0)); // count = count
try self.emit(.ecall()); // syscall(no, fd, buf, count)
try self.emit(.add(.sp, .sp, count));
+
+ try self.emit(.addi(count, count, -1));
+ }
+
+ fn genDiscard(self: *Context, _: compile.Instr.Discard) !void {
+ try self.maybeFreeSources();
}
fn codegenInstr(self: *Context, instr: compile.Instr) !void {
@@ -687,6 +693,8 @@ pub fn create_elf(allocator: Allocator, block: compile.Block) ![]u8 {
.ecall(),
});
+ std.debug.print("allocated regs: {}\n", .{root.fmtHashMap(ctx.register_allocator.allocated)});
+
var output_buffer: std.ArrayList(u8) = .init(allocator);
errdefer output_buffer.deinit();
try output_buffer.appendNTimes(undefined, @sizeOf(elf.Elf64_Ehdr) + @sizeOf(elf.Elf64_Phdr));
diff --git a/src/compile.zig b/src/compile.zig
index 6a79efd..9513a93 100644
--- a/src/compile.zig
+++ b/src/compile.zig
@@ -15,6 +15,7 @@ pub const Instr = struct {
constant: Constant,
bin_op: BinOp,
print: Print,
+ discard: Discard,
};
pub const Constant = struct {
@@ -43,6 +44,7 @@ pub const Instr = struct {
};
pub const Print = struct {
+ dest: VReg,
arg: VReg,
pub fn sources(self: Print) Sources {
@@ -50,6 +52,14 @@ pub const Instr = struct {
}
};
+ pub const Discard = struct {
+ vreg: VReg,
+
+ pub fn sources(self: Discard) Sources {
+ return Sources.fromSlice(&.{self.vreg}) catch unreachable;
+ }
+ };
+
pub fn sources(self: Instr) Sources {
return switch (self.type) {
inline else => |instr| instr.sources(),
@@ -58,8 +68,8 @@ pub const Instr = struct {
pub fn dest(self: *const Instr) ?VReg {
return switch (self.type) {
- inline .constant, .bin_op => |s| s.dest,
- inline .print => null,
+ inline .constant, .bin_op, .print => |s| s.dest,
+ // inline .x => null,
};
}
@@ -69,13 +79,16 @@ pub const Instr = struct {
pub const Block = struct {
// arguments: []Reg,
instrs: []Instr,
- vreg_last_use: std.AutoHashMap(VReg, usize),
+ vreg_last_use: std.AutoHashMap(usize, std.ArrayList(VReg)),
fn init(allocator: Allocator, instrs: []Instr) !Block {
- var vreg_last_use: std.AutoHashMap(VReg, usize) = .init(allocator);
+ var vreg_last_use: std.AutoHashMap(usize, std.ArrayList(VReg)) = .init(allocator);
for (0.., instrs) |i, instr| {
- for (instr.sources().slice()) |src|
- try vreg_last_use.put(src, i);
+ for (instr.sources().slice()) |src| {
+ const kv = try vreg_last_use.getOrPut(i);
+ if (!kv.found_existing) kv.value_ptr.* = .init(allocator);
+ try kv.value_ptr.append(src);
+ }
}
return .{
.instrs = instrs,
@@ -112,7 +125,10 @@ const CompileContext = struct {
fn compileStmt(self: *Self, stmt: parse.Stmt) !void {
switch (stmt.type) {
- .expr => |expr| _ = try self.compileExpr(expr),
+ .expr => |expr| try self.addInstr(.{
+ .loc = stmt.loc,
+ .type = .{ .discard = .{ .vreg = try self.compileExpr(expr) } },
+ }),
}
}
@@ -142,18 +158,15 @@ const CompileContext = struct {
});
},
.call => |call| {
- if (call.proc.type == .identifier and
- std.mem.eql(u8, call.proc.loc.getIdent(self.source), "print"))
- {
- const arg = try self.compileExpr(call.arg);
- try self.addInstr(.{
- .loc = expr.loc,
- .type = .{ .print = .{ .arg = arg } },
- });
- // BUG: we're returning a bogus virtual register that we didn't write to
- } else {
+ if (call.proc.type != .identifier or
+ !std.mem.eql(u8, call.proc.loc.getIdent(self.source), "print"))
return error.CantCallAnythingButPrint;
- }
+
+ const arg = try self.compileExpr(call.arg);
+ try self.addInstr(.{
+ .loc = expr.loc,
+ .type = .{ .print = .{ .dest = dest, .arg = arg } },
+ });
},
.identifier => return error.CantCompileIdentifierExpr,
}
diff --git a/src/main.zig b/src/main.zig
index dd34c53..6692799 100644
--- a/src/main.zig
+++ b/src/main.zig
@@ -13,16 +13,14 @@ pub fn main() !void {
var args = std.process.args();
_ = args.next();
- const arg = args.next() orelse "";
- const run_path, const out_file = if (std.mem.eql(u8, arg, "run")) blk: {
- const path = try std.fmt.allocPrint(allocator, "/tmp/{}.elf", .{std.crypto.random.int(u32)});
- break :blk .{ path, try std.fs.createFileAbsolute(path, .{ .mode = 0o777 }) };
- } else if (arg.len > 0)
- .{ null, try std.fs.cwd().createFile(arg, .{ .mode = 0o777 }) }
+ const out_path = args.next();
+ const out_file = if (out_path) |path|
+ try std.fs.cwd().createFile(path, .{ .mode = 0o777 })
else
- .{ null, std.io.getStdOut() };
- defer if (run_path) |path| allocator.free(path);
+ std.io.getStdOut();
+ const run = if (args.next()) |arg| std.mem.eql(u8, arg, "run") else false;
+
const output = out_file.writer();
// var br = std.io.bufferedReader(std.io.getStdIn().reader());
@@ -39,9 +37,9 @@ pub fn main() !void {
// }
const source =
+ \\1; 1; 1; 1; 1;
\\print 18446744073709551615;
- \\print (0 - 1);
- \\print 69;
+ \\print (print (0 - 1));
;
var lexer: Lexer = .{ .source = source };
std.debug.print("Tokens:\n", .{});
@@ -67,15 +65,15 @@ pub fn main() !void {
const elf = try codegen.create_elf(allocator, block);
try output.writeAll(elf);
std.debug.print("Run output:\n", .{});
- if (run_path) |path| {
+ if (run) {
out_file.close();
std.debug.print("{}\n", .{std.process.execv(
allocator,
if (target.cpu.arch == .riscv64 and target.os.tag == .linux)
- &.{path}
+ &.{out_path}
else
- &.{ "qemu-riscv64", path },
+ &.{ "qemu-riscv64", out_path.? },
)});
}
}