Widen `ecall` intrinsic args
3ca028fc0bb8eda3776bcdddb4fd85f1de91d1fd96925b3facc73105def15f00
Change the ecall intrinsic signature and all call sites from `i32` to `i64` arguments and return value.
1 parent
a0bdac6c
lib/std/intrinsics.rad
+5 -1
| 1 | 1 | //! Compiler intrinsics. |
|
| 2 | 2 | ||
| 3 | 3 | /// Environment call. |
|
| 4 | - | @intrinsic pub extern fn ecall(number: u32, arg1: i32, arg2: i32, arg3: i32, arg4: i32) -> i32; |
|
| 4 | + | /// |
|
| 5 | + | /// Issues a system call with the given number and arguments. |
|
| 6 | + | /// Arguments and the return value are `i64` to support both 32-bit |
|
| 7 | + | /// emulator addresses and 64-bit native (AMD64) pointers. |
|
| 8 | + | @intrinsic pub extern fn ecall(number: u32, arg1: i64, arg2: i64, arg3: i64, arg4: i64) -> i64; |
|
| 5 | 9 | ||
| 6 | 10 | /// Break out of program. |
|
| 7 | 11 | @intrinsic pub extern fn ebreak(); |
lib/std/io.rad
+3 -3
| 1 | 1 | //! Input/output utilities. |
|
| 2 | 2 | use std::fmt; |
|
| 3 | 3 | use std::intrinsics; |
|
| 4 | 4 | ||
| 5 | 5 | pub fn print(str: *[u8]) { |
|
| 6 | - | intrinsics::ecall(64, 1, str.ptr as i32, str.len as i32, 0); |
|
| 6 | + | intrinsics::ecall(64, 1, str.ptr as i64, str.len as i64, 0); |
|
| 7 | 7 | } |
|
| 8 | 8 | ||
| 9 | 9 | pub fn printError(str: *[u8]) { |
|
| 10 | - | intrinsics::ecall(64, 2, str.ptr as i32, str.len as i32, 0); |
|
| 10 | + | intrinsics::ecall(64, 2, str.ptr as i64, str.len as i64, 0); |
|
| 11 | 11 | } |
|
| 12 | 12 | ||
| 13 | 13 | pub fn printLn(str: *[u8]) { |
|
| 14 | 14 | print(str); |
|
| 15 | 15 | print("\n"); |
| 32 | 32 | let result: *[u8] = fmt::formatBool(val, &mut buffer[..]); |
|
| 33 | 33 | print(result); |
|
| 34 | 34 | } |
|
| 35 | 35 | ||
| 36 | 36 | pub fn read(buf: *mut [u8]) -> u32 { |
|
| 37 | - | return intrinsics::ecall(63, 0, buf.ptr as i32, buf.len as i32, 0) as u32; |
|
| 37 | + | return intrinsics::ecall(63, 0, buf.ptr as i64, buf.len as i64, 0) as u32; |
|
| 38 | 38 | } |
|
| 39 | 39 | ||
| 40 | 40 | pub fn readToEnd(buf: *mut [u8]) -> *[u8] { |
|
| 41 | 41 | let mut total: u32 = 0; |
|
| 42 | 42 |
lib/std/sys/unix.rad
+17 -17
| 2 | 2 | use std::intrinsics; |
|
| 3 | 3 | ||
| 4 | 4 | /// File access modes. |
|
| 5 | 5 | // TODO: Use unlabeled struct. |
|
| 6 | 6 | pub record OpenFlags { |
|
| 7 | - | value: i32, |
|
| 7 | + | value: i64, |
|
| 8 | 8 | } |
|
| 9 | 9 | ||
| 10 | 10 | /// Open file for reading only. |
|
| 11 | 11 | pub const O_RDONLY: OpenFlags = OpenFlags { value: 0 }; |
|
| 12 | 12 |
| 21 | 21 | ||
| 22 | 22 | /// Truncate file to zero length. |
|
| 23 | 23 | pub const O_TRUNC: OpenFlags = OpenFlags { value: 512 }; |
|
| 24 | 24 | ||
| 25 | 25 | /// Standard file descriptor for stdin. |
|
| 26 | - | pub const STDIN: i32 = 0; |
|
| 26 | + | pub const STDIN: i64 = 0; |
|
| 27 | 27 | ||
| 28 | 28 | /// Standard file descriptor for stdout. |
|
| 29 | - | pub const STDOUT: i32 = 1; |
|
| 29 | + | pub const STDOUT: i64 = 1; |
|
| 30 | 30 | ||
| 31 | 31 | /// Standard file descriptor for stderr. |
|
| 32 | - | pub const STDERR: i32 = 2; |
|
| 32 | + | pub const STDERR: i64 = 2; |
|
| 33 | 33 | ||
| 34 | 34 | /// Special value representing current working directory for `openat()`. |
|
| 35 | - | const AT_FDCWD: i32 = -100; |
|
| 35 | + | const AT_FDCWD: i64 = -100; |
|
| 36 | 36 | ||
| 37 | 37 | /// Opens a file at the given path and returns a file descriptor. |
|
| 38 | 38 | /// Returns a negative value on error. |
|
| 39 | - | pub fn open(path: *[u8], flags: OpenFlags) -> i32 { |
|
| 40 | - | return intrinsics::ecall(56, AT_FDCWD, path.ptr as i32, flags.value, 0); |
|
| 39 | + | pub fn open(path: *[u8], flags: OpenFlags) -> i64 { |
|
| 40 | + | return intrinsics::ecall(56, AT_FDCWD, path.ptr as i64, flags.value, 0); |
|
| 41 | 41 | } |
|
| 42 | 42 | ||
| 43 | 43 | /// Opens a file at the given path with mode, returns a file descriptor. |
|
| 44 | - | pub fn openOpts(path: *[u8], flags: OpenFlags, mode: i32) -> i32 { |
|
| 45 | - | return intrinsics::ecall(56, AT_FDCWD, path.ptr as i32, flags.value, mode); |
|
| 44 | + | pub fn openOpts(path: *[u8], flags: OpenFlags, mode: i64) -> i64 { |
|
| 45 | + | return intrinsics::ecall(56, AT_FDCWD, path.ptr as i64, flags.value, mode); |
|
| 46 | 46 | } |
|
| 47 | 47 | ||
| 48 | 48 | /// Reads from a file descriptor into the provided buffer. |
|
| 49 | 49 | /// Returns the number of bytes read, or a negative value on error. |
|
| 50 | - | pub fn read(fd: i32, buf: *mut [u8]) -> i32 { |
|
| 51 | - | return intrinsics::ecall(63, fd, buf.ptr as i32, buf.len as i32, 0); |
|
| 50 | + | pub fn read(fd: i64, buf: *mut [u8]) -> i64 { |
|
| 51 | + | return intrinsics::ecall(63, fd, buf.ptr as i64, buf.len as i64, 0); |
|
| 52 | 52 | } |
|
| 53 | 53 | ||
| 54 | 54 | /// Reads from a file descriptor until EOF or buffer is full. |
|
| 55 | 55 | /// Returns the total number of bytes read, or a negative value on error. |
|
| 56 | - | pub fn readToEnd(fd: i32, buf: *mut [u8]) -> i32 { |
|
| 56 | + | pub fn readToEnd(fd: i64, buf: *mut [u8]) -> i64 { |
|
| 57 | 57 | let mut total: u32 = 0; |
|
| 58 | 58 | while total < buf.len { |
|
| 59 | 59 | let chunk = &mut buf[total..]; |
|
| 60 | 60 | let n = read(fd, chunk); |
|
| 61 | 61 |
| 65 | 65 | if n == 0 { |
|
| 66 | 66 | break; |
|
| 67 | 67 | } |
|
| 68 | 68 | total += n as u32; |
|
| 69 | 69 | } |
|
| 70 | - | return total as i32; |
|
| 70 | + | return total as i64; |
|
| 71 | 71 | } |
|
| 72 | 72 | ||
| 73 | 73 | /// Writes to a file descriptor from the provided buffer. |
|
| 74 | 74 | /// Returns the number of bytes written, or a negative value on error. |
|
| 75 | - | pub fn write(fd: i32, buf: *[u8]) -> i32 { |
|
| 76 | - | return intrinsics::ecall(64, fd, buf.ptr as i32, buf.len as i32, 0); |
|
| 75 | + | pub fn write(fd: i64, buf: *[u8]) -> i64 { |
|
| 76 | + | return intrinsics::ecall(64, fd, buf.ptr as i64, buf.len as i64, 0); |
|
| 77 | 77 | } |
|
| 78 | 78 | ||
| 79 | 79 | /// Closes a file descriptor. |
|
| 80 | 80 | /// Returns `0` on success, or a negative value on error. |
|
| 81 | - | pub fn close(fd: i32) -> i32 { |
|
| 81 | + | pub fn close(fd: i64) -> i64 { |
|
| 82 | 82 | return intrinsics::ecall(57, fd, 0, 0, 0); |
|
| 83 | 83 | } |
|
| 84 | 84 | ||
| 85 | 85 | ||
| 86 | 86 | /// Reads the entire contents of a file at the given path into the provided buffer. |
| 100 | 100 | } |
|
| 101 | 101 | return &buf[..(n as u32)]; |
|
| 102 | 102 | } |
|
| 103 | 103 | ||
| 104 | 104 | /// Exit the current process with the given status code. |
|
| 105 | - | pub fn exit(status: i32) { |
|
| 105 | + | pub fn exit(status: i64) { |
|
| 106 | 106 | intrinsics::ecall(93, status, 0, 0, 0); |
|
| 107 | 107 | } |
|
| 108 | 108 | ||
| 109 | 109 | /// Writes the entire contents of a buffer to a file at the given path. |
|
| 110 | 110 | /// Creates the file if it doesn't exist, truncates if it does. |
test/tests/ecall.i64.rad
added
+18 -0
| 1 | + | //! returns: 0 |
|
| 2 | + | ||
| 3 | + | @intrinsic extern fn ecall(number: u32, arg1: i64, arg2: i64, arg3: i64, arg4: i64) -> i64; |
|
| 4 | + | ||
| 5 | + | /// Test that ecall can pass and return i64 values. |
|
| 6 | + | @default fn main() -> i32 { |
|
| 7 | + | // ecall(64, fd, buf, len, 0) = write(fd, buf, len). |
|
| 8 | + | let msg: *[u8] = "ok\n"; |
|
| 9 | + | ||
| 10 | + | // Write to stdout. The pointer is passed as i64. |
|
| 11 | + | let n = ecall(64, 1, msg.ptr as i64, msg.len as i64, 0); |
|
| 12 | + | ||
| 13 | + | // Return value should be 3 (bytes written). |
|
| 14 | + | if n != 3 { |
|
| 15 | + | return 1; |
|
| 16 | + | } |
|
| 17 | + | return 0; |
|
| 18 | + | } |