authorgravatar for kubkon@jakubkonka.comJakub Konka <kubkon@jakubkonka.com> 2021-11-11 10:45:00-08:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2021-11-11 10:45:00-08:00
log19e56638694dddf1b9137a352abf31df7952c5eb
treea896c6c4a1f6090d3f02ca09a473b2cf12dee227
parent53523ef5d0413459bd2eb9d84d2338f2bc49d417
parentbfb88b2d0dc9ca9663a2346d707ff4f0034739ba
signaturebadge-question-mark Signed by PGP key 4AEE18F83AFDEB23

Merge pull request #9935 from g-w1/plan9-std

add plan9 support to std

6 files changed, 187 insertions(+), 16 deletions(-)

lib/std/os.zig+1
......@@ -33,6 +33,7 @@ pub const netbsd = std.c;
3333pub const openbsd = std.c;
3434pub const solaris = std.c;
3535pub const linux = @import("os/linux.zig");
36pub const plan9 = @import("os/plan9.zig");
3637pub const uefi = @import("os/uefi.zig");
3738pub const wasi = @import("os/wasi.zig");
3839pub const windows = @import("os/windows.zig");
lib/std/os/plan9.zig created+91
......@@ -0,0 +1,91 @@
1const std = @import("../std.zig");
2const builtin = @import("builtin");
3
4pub const syscall_bits = switch (builtin.stage2_arch) {
5 .x86_64 => @import("plan9/x86_64.zig"),
6 else => @compileError("more plan9 syscall implementations (needs more inline asm in stage2"),
7};
8pub const SYS = enum(usize) {
9 SYSR1 = 0,
10 _ERRSTR = 1,
11 BIND = 2,
12 CHDIR = 3,
13 CLOSE = 4,
14 DUP = 5,
15 ALARM = 6,
16 EXEC = 7,
17 EXITS = 8,
18 _FSESSION = 9,
19 FAUTH = 10,
20 _FSTAT = 11,
21 SEGBRK = 12,
22 _MOUNT = 13,
23 OPEN = 14,
24 _READ = 15,
25 OSEEK = 16,
26 SLEEP = 17,
27 _STAT = 18,
28 RFORK = 19,
29 _WRITE = 20,
30 PIPE = 21,
31 CREATE = 22,
32 FD2PATH = 23,
33 BRK_ = 24,
34 REMOVE = 25,
35 _WSTAT = 26,
36 _FWSTAT = 27,
37 NOTIFY = 28,
38 NOTED = 29,
39 SEGATTACH = 30,
40 SEGDETACH = 31,
41 SEGFREE = 32,
42 SEGFLUSH = 33,
43 RENDEZVOUS = 34,
44 UNMOUNT = 35,
45 _WAIT = 36,
46 SEMACQUIRE = 37,
47 SEMRELEASE = 38,
48 SEEK = 39,
49 FVERSION = 40,
50 ERRSTR = 41,
51 STAT = 42,
52 FSTAT = 43,
53 WSTAT = 44,
54 FWSTAT = 45,
55 MOUNT = 46,
56 AWAIT = 47,
57 PREAD = 50,
58 PWRITE = 51,
59 TSEMACQUIRE = 52,
60 _NSEC = 53,
61};
62
63pub fn pwrite(fd: usize, buf: [*]const u8, count: usize, offset: usize) usize {
64 return syscall_bits.syscall4(.PWRITE, fd, @ptrToInt(buf), count, offset);
65}
66
67pub fn open(path: [*:0]const u8, omode: OpenMode) usize {
68 return syscall_bits.syscall2(.OPEN, @ptrToInt(path), @enumToInt(omode));
69}
70
71pub fn create(path: [*:0]const u8, omode: OpenMode, perms: usize) usize {
72 return syscall_bits.syscall3(.CREATE, @ptrToInt(path), @enumToInt(omode), perms);
73}
74
75pub fn exits(status: ?[*:0]const u8) void {
76 _ = syscall_bits.syscall1(.EXITS, if (status) |s| @ptrToInt(s) else 0);
77}
78
79pub fn close(fd: usize) usize {
80 return syscall_bits.syscall1(.CLOSE, fd);
81}
82pub const OpenMode = enum(usize) {
83 OREAD = 0, //* open for read
84 OWRITE = 1, //* write
85 ORDWR = 2, //* read and write
86 OEXEC = 3, //* execute, == read but check execute permission
87 OTRUNC = 16, //* or'ed in (except for exec), truncate file first
88 OCEXEC = 32, //* or'ed in (per file descriptor), close on exec
89 ORCLOSE = 64, //* or'ed in, remove on close
90 OEXCL = 0x1000, //* or'ed in, exclusive create
91};
lib/std/os/plan9/x86_64.zig created+73
......@@ -0,0 +1,73 @@
1const plan9 = @import("../plan9.zig");
2// TODO better inline asm
3
4pub fn syscall1(sys: plan9.SYS, arg0: usize) usize {
5 return asm volatile (
6 \\push %%r8
7 \\push $0
8 \\syscall
9 \\pop %%r11
10 \\pop %%r11
11 : [ret] "={rax}" (-> usize),
12 : [syscall_number] "{rbp}" (@enumToInt(sys)),
13 [arg0] "{r8}" (arg0),
14 : "rcx", "rax", "rbp", "r11", "memory"
15 );
16}
17pub fn syscall2(sys: plan9.SYS, arg0: usize, arg1: usize) usize {
18 return asm volatile (
19 \\push %%r9
20 \\push %%r8
21 \\push $0
22 \\syscall
23 \\pop %%r11
24 \\pop %%r11
25 \\pop %%r11
26 : [ret] "={rax}" (-> usize),
27 : [arg0] "{r8}" (arg0),
28 [arg1] "{r9}" (arg1),
29 [syscall_number] "{rbp}" (@enumToInt(sys)),
30 : "rcx", "rax", "rbp", "r11", "memory"
31 );
32}
33pub fn syscall3(sys: plan9.SYS, arg0: usize, arg1: usize, arg2: usize) usize {
34 return asm volatile (
35 \\push %%r10
36 \\push %%r9
37 \\push %%r8
38 \\push $0
39 \\syscall
40 \\pop %%r11
41 \\pop %%r11
42 \\pop %%r11
43 \\pop %%r11
44 : [ret] "={rax}" (-> usize),
45 : [arg0] "{r8}" (arg0),
46 [arg1] "{r9}" (arg1),
47 [arg2] "{r10}" (arg2),
48 [syscall_number] "{rbp}" (@enumToInt(sys)),
49 : "rcx", "rax", "rbp", "r11", "memory"
50 );
51}
52pub fn syscall4(sys: plan9.SYS, arg0: usize, arg1: usize, arg2: usize, arg3: usize) usize {
53 return asm volatile (
54 \\push %%r11
55 \\push %%r10
56 \\push %%r9
57 \\push %%r8
58 \\push $0
59 \\syscall
60 \\pop %%r11
61 \\pop %%r11
62 \\pop %%r11
63 \\pop %%r11
64 \\pop %%r11
65 : [ret] "={rax}" (-> usize),
66 : [arg0] "{r8}" (arg0),
67 [arg1] "{r9}" (arg1),
68 [arg2] "{r10}" (arg2),
69 [arg2] "{r11}" (arg3),
70 [syscall_number] "{rbp}" (@enumToInt(sys)),
71 : "rcx", "rax", "rbp", "r11", "memory"
72 );
73}
src/Sema.zig+3
......@@ -9002,6 +9002,9 @@ fn zirIsNonNullPtr(
90029002 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
90039003 const src = inst_data.src();
90049004 const ptr = sema.resolveInst(inst_data.operand);
9005 if ((try sema.resolveMaybeUndefVal(block, src, ptr)) == null) {
9006 return block.addUnOp(.is_non_null_ptr, ptr);
9007 }
90059008 const loaded = try sema.analyzeLoad(block, src, ptr, src);
90069009 return sema.analyzeIsNull(block, src, loaded, true);
90079010}
src/arch/x86_64/CodeGen.zig+11-15
......@@ -1836,10 +1836,10 @@ fn airCall(self: *Self, inst: Air.Inst.Index) !void {
18361836 try self.register_manager.getReg(reg, null);
18371837 try self.genSetReg(arg_ty, reg, arg_mcv);
18381838 },
1839 .stack_offset => {
1839 .stack_offset => |off| {
18401840 // Here we need to emit instructions like this:
18411841 // mov qword ptr [rsp + stack_offset], x
1842 return self.fail("TODO implement calling with parameters in memory", .{});
1842 try self.genSetStack(arg_ty, off, arg_mcv);
18431843 },
18441844 .ptr_stack_offset => {
18451845 return self.fail("TODO implement calling with MCValue.ptr_stack_offset arg", .{});
......@@ -1997,9 +1997,10 @@ fn airRet(self: *Self, inst: Air.Inst.Index) !void {
19971997fn airRetLoad(self: *Self, inst: Air.Inst.Index) !void {
19981998 const un_op = self.air.instructions.items(.data)[inst].un_op;
19991999 const ptr = try self.resolveInst(un_op);
2000 _ = ptr;
2001 return self.fail("TODO implement airRetLoad for {}", .{self.target.cpu.arch});
2002 //return self.finishAir(inst, .dead, .{ un_op, .none, .none });
2000 // we can reuse self.ret_mcv because it just gets returned
2001 try self.load(self.ret_mcv, ptr, self.air.typeOf(un_op));
2002 try self.ret(self.ret_mcv);
2003 return self.finishAir(inst, .dead, .{ un_op, .none, .none });
20032004}
20042005
20052006fn airCmp(self: *Self, inst: Air.Inst.Index, op: math.CompareOperator) !void {
......@@ -2497,8 +2498,7 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
24972498 const clobbers_len = @truncate(u5, extended.small >> 10);
24982499 _ = clobbers_len; // TODO honor these
24992500 const is_volatile = @truncate(u1, extended.small >> 15) != 0;
2500 const outputs = @bitCast([]const Air.Inst.Ref, self.air.extra[air_extra.end..][0..outputs_len]);
2501 const args = @bitCast([]const Air.Inst.Ref, self.air.extra[air_extra.end + outputs.len ..][0..args_len]);
2501 const args = @bitCast([]const Air.Inst.Ref, self.air.extra[air_extra.end..][0..args_len]);
25022502
25032503 if (outputs_len > 1) {
25042504 return self.fail("TODO implement codegen for asm with more than 1 output", .{});
......@@ -2601,16 +2601,12 @@ fn airAsm(self: *Self, inst: Air.Inst.Index) !void {
26012601 break :result MCValue{ .none = {} };
26022602 }
26032603 };
2604 if (outputs.len + args.len <= Liveness.bpi - 1) {
2604 if (args.len <= Liveness.bpi - 1) {
26052605 var buf = [1]Air.Inst.Ref{.none} ** (Liveness.bpi - 1);
2606 std.mem.copy(Air.Inst.Ref, &buf, outputs);
2607 std.mem.copy(Air.Inst.Ref, buf[outputs.len..], args);
2606 std.mem.copy(Air.Inst.Ref, &buf, args);
26082607 return self.finishAir(inst, result, buf);
26092608 }
2610 var bt = try self.iterateBigTomb(inst, outputs.len + args.len);
2611 for (outputs) |output| {
2612 bt.feed(output);
2613 }
2609 var bt = try self.iterateBigTomb(inst, args.len);
26142610 for (args) |arg| {
26152611 bt.feed(arg);
26162612 }
......@@ -3310,7 +3306,7 @@ fn resolveCallingConventionValues(self: *Self, fn_ty: Type) !CallMCValues {
33103306 const param_size = @intCast(u32, ty.abiSize(self.target.*));
33113307 const pass_in_reg = switch (ty.zigTypeTag()) {
33123308 .Bool => true,
3313 .Int => param_size <= 8,
3309 .Int, .Enum => param_size <= 8,
33143310 .Pointer => ty.ptrSize() != .Slice,
33153311 .Optional => ty.isPtrLikeOptional(),
33163312 else => false,
test/stage2/plan9.zig+8-1
......@@ -43,6 +43,13 @@ pub fn addCases(ctx: *TestContext) !void {
4343 \\ : "rcx", "rbp", "r11", "memory"
4444 \\ );
4545 \\}
46 , "");
46 , "Hello World\n");
47 case.addCompareOutput(
48 \\const std = @import("std");
49 \\pub fn main() void {
50 \\ const str = "Hello World!\n";
51 \\ _ = std.os.plan9.pwrite(1, str, str.len, 0);
52 \\}
53 , "Hello World\n");
4754 }
4855}