diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/codegen.zig | 111 | ||||
-rw-r--r-- | src/compile.zig | 21 | ||||
-rw-r--r-- | src/main.zig | 2 |
3 files changed, 91 insertions, 43 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 { diff --git a/src/compile.zig b/src/compile.zig index acae7ff..c837495 100644 --- a/src/compile.zig +++ b/src/compile.zig @@ -14,7 +14,7 @@ pub const Instr = struct { pub const Type = union(enum) { constant: Constant, bin_op: BinOp, - print: Print, + proc_call: ProcCall, discard: Discard, }; @@ -43,11 +43,17 @@ pub const Instr = struct { } }; - pub const Print = struct { + pub const ProcCall = struct { dest: VReg, arg: VReg, + proc: Proc, - pub fn sources(self: Print) Sources { + const Proc = enum { + print, + read_int, + }; + + pub fn sources(self: ProcCall) Sources { return Sources.fromSlice(&.{self.arg}) catch unreachable; } }; @@ -68,7 +74,7 @@ pub const Instr = struct { pub fn dest(self: *const Instr) ?VReg { return switch (self.type) { - inline .constant, .bin_op, .print => |s| s.dest, + inline .constant, .bin_op, .proc_call => |s| s.dest, // inline .x => null, }; } @@ -167,14 +173,13 @@ const CompileContext = struct { }); }, .call => |call| { - if (call.proc.type != .identifier or - !std.mem.eql(u8, call.proc.loc.getIdent(self.source), "print")) - return error.CantCallAnythingButPrint; + if (call.proc.type != .identifier) return error.CanOnlyCallIdentifiers; + const proc = std.meta.stringToEnum(Instr.ProcCall.Proc, call.proc.loc.getIdent(self.source)) orelse return error.UnknownProcedure; const arg = try self.compileExpr(call.arg); try self.addInstr(.{ .loc = expr.loc, - .type = .{ .print = .{ .dest = dest, .arg = arg } }, + .type = .{ .proc_call = .{ .dest = dest, .arg = arg, .proc = proc } }, }); }, .identifier => { diff --git a/src/main.zig b/src/main.zig index 7e0794a..15118d8 100644 --- a/src/main.zig +++ b/src/main.zig @@ -37,7 +37,7 @@ pub fn main() !void { // } const source = - \\let x = 1; + \\let x = read_int(0); \\print(18446744073709551615); \\print(x + x); ; |