aboutsummaryrefslogtreecommitdiff
path: root/src/codegen.zig
diff options
context:
space:
mode:
Diffstat (limited to 'src/codegen.zig')
-rw-r--r--src/codegen.zig111
1 files changed, 77 insertions, 34 deletions
diff --git a/src/codegen.zig b/src/codegen.zig
index 07f3a4d..d2b5d2a 100644
--- a/src/codegen.zig
+++ b/src/codegen.zig
@@ -610,40 +610,83 @@ const Context = struct {
}
}
- fn genPrint(self: *Context, print: compile.Instr.Print) !void {
- const num = self.register_allocator.get(print.arg);
-
- const quot = try self.register_allocator.allocateAux();
- 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.allocate(print.dest);
-
- try self.maybeFreeSources();
-
- try self.emit(.addi(digit, .zero, '\n'));
- try self.emit(.addi(.sp, .sp, -1));
- try self.emit(.sb(.sp, 0, digit));
- try self.emit(.addi(count, .zero, 1));
- try self.emit(.addi(quot, .zero, 10));
-
- try self.emit(.addi(digit, num, 0));
- try self.emit(.divu(num, digit, quot));
- try self.emit(.remu(digit, digit, quot));
- try self.emit(.addi(digit, digit, '0'));
- try self.emit(.addi(.sp, .sp, -1));
- try self.emit(.sb(.sp, 0, digit));
- try self.emit(.addi(count, count, 1));
- try self.emit(.bne(num, .zero, -4 * 7));
-
- try self.emit(.addi(.a7, .zero, 64)); // no = write
- try self.emit(.addi(.a0, .zero, 1)); // fd = stdout
- try self.emit(.addi(.a1, .sp, 0)); // buf = sp
- 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 genProcCall(self: *Context, call: compile.Instr.ProcCall) !void {
+ switch (call.proc) {
+ .print => {
+ const num = self.register_allocator.get(call.arg);
+
+ const quot = try self.register_allocator.allocateAux();
+ 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.allocate(call.dest);
+
+ try self.maybeFreeSources();
+
+ try self.emit(.addi(digit, .zero, '\n'));
+ try self.emit(.addi(.sp, .sp, -1));
+ try self.emit(.sb(.sp, 0, digit));
+ try self.emit(.addi(count, .zero, 1));
+ try self.emit(.addi(quot, .zero, 10));
+
+ try self.emit(.addi(digit, num, 0));
+ try self.emit(.divu(num, digit, quot));
+ try self.emit(.remu(digit, digit, quot));
+ try self.emit(.addi(digit, digit, '0'));
+ try self.emit(.addi(.sp, .sp, -1));
+ try self.emit(.sb(.sp, 0, digit));
+ try self.emit(.addi(count, count, 1));
+ try self.emit(.bne(num, .zero, -4 * 7));
+
+ try self.emit(.addi(.a7, .zero, @intFromEnum(std.os.linux.syscalls.RiscV64.write)));
+ try self.emit(.addi(.a0, .zero, 1)); // fd = stdout
+ try self.emit(.addi(.a1, .sp, 0)); // buf = sp
+ 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));
+ },
+ .read_int => {
+ try self.maybeFreeSources();
+
+ const result = try self.register_allocator.allocate(call.dest);
+ const ptr = try self.register_allocator.allocateAux();
+ defer self.register_allocator.freeAux(ptr);
+ const char = try self.register_allocator.allocateAux();
+ defer self.register_allocator.freeAux(char);
+ const newline = try self.register_allocator.allocateAux();
+ defer self.register_allocator.freeAux(newline);
+
+ try self.emit(.addi(.sp, .sp, -21));
+ try self.emit(.addi(newline, .zero, '\n'));
+ try self.emit(.addi(result, .zero, 0));
+
+ try self.emit(.addi(.a7, .zero, @intFromEnum(std.os.linux.syscalls.RiscV64.read)));
+ try self.emit(.addi(.a0, .zero, 0)); // fd = stdin
+ try self.emit(.addi(.a1, .sp, 0)); // buf = sp
+ try self.emit(.addi(.a2, .zero, 21)); // count = count
+ try self.emit(.ecall()); // syscall(no, fd, buf, count)
+
+ try self.emit(.addi(ptr, .sp, 0));
+ try self.emit(.add(.a0, .a0, .sp)); // a0 = end
+
+ // loop start
+ try self.emit(.bgeu(ptr, .a0, 4 * 8)); // done
+ try self.emit(.lb(char, ptr, 0));
+ try self.emit(.beq(char, newline, 4 * 6)); // done
+ try self.emit(.mul(result, result, newline)); // '\n' happens to also be 10
+ try self.emit(.addi(char, char, -'0'));
+ // assert 0 <= char <= 9
+ try self.emit(.add(result, result, char));
+
+ try self.emit(.addi(ptr, ptr, 1));
+ try self.emit(.jal(.zero, -4 * 7)); // -> loop start
+ // done
+
+ try self.emit(.addi(.sp, .sp, 21));
+ },
+ }
}
fn genDiscard(self: *Context, _: compile.Instr.Discard) !void {