| author | |
| committer | |
| log | df24ce52b1059232db66e9af425a02df558aa1ca |
| tree | bf314eace4c7acd533c5c9532b330ecd8ae65686 |
| parent | eb9c29eb817a24e5326b9a63ebf7265d3b2bad2c |
| parent | 55c58f226d06d3708a82878a67f3800e0ce5810b |
In particular I wanted to take advantage of the new hex float parsing
code.52 files changed, 1674 insertions(+), 485 deletions(-)
build.zig+5-2| ... | @@ -44,6 +44,7 @@ pub fn build(b: *Builder) !void { | ... | @@ -44,6 +44,7 @@ pub fn build(b: *Builder) !void { |
| 44 | 44 | ||
| 45 | const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"}); | 45 | const fmt_build_zig = b.addFmt(&[_][]const u8{"build.zig"}); |
| 46 | 46 | ||
| 47 | const skip_debug = b.option(bool, "skip-debug", "Main test suite skips debug builds") orelse false; | ||
| 47 | const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false; | 48 | const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false; |
| 48 | const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release; | 49 | const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release; |
| 49 | const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release; | 50 | const skip_release_fast = b.option(bool, "skip-release-fast", "Main test suite skips release-fast builds") orelse skip_release; |
| ... | @@ -240,8 +241,10 @@ pub fn build(b: *Builder) !void { | ... | @@ -240,8 +241,10 @@ pub fn build(b: *Builder) !void { |
| 240 | 241 | ||
| 241 | var chosen_modes: [4]builtin.Mode = undefined; | 242 | var chosen_modes: [4]builtin.Mode = undefined; |
| 242 | var chosen_mode_index: usize = 0; | 243 | var chosen_mode_index: usize = 0; |
| 243 | chosen_modes[chosen_mode_index] = builtin.Mode.Debug; | 244 | if (!skip_debug) { |
| 244 | chosen_mode_index += 1; | 245 | chosen_modes[chosen_mode_index] = builtin.Mode.Debug; |
| 246 | chosen_mode_index += 1; | ||
| 247 | } | ||
| 245 | if (!skip_release_safe) { | 248 | if (!skip_release_safe) { |
| 246 | chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseSafe; | 249 | chosen_modes[chosen_mode_index] = builtin.Mode.ReleaseSafe; |
| 247 | chosen_mode_index += 1; | 250 | chosen_mode_index += 1; |
ci/drone/drone.yml+33-2| ... | @@ -6,7 +6,38 @@ platform: | ... | @@ -6,7 +6,38 @@ platform: |
| 6 | arch: arm64 | 6 | arch: arm64 |
| 7 | 7 | ||
| 8 | steps: | 8 | steps: |
| 9 | - name: build-and-test | 9 | - name: build |
| 10 | image: ziglang/static-base:llvm12-aarch64-1 | ||
| 11 | commands: | ||
| 12 | - ./ci/drone/linux_script_build | ||
| 13 | |||
| 14 | - name: test-1 | ||
| 15 | depends_on: | ||
| 16 | - build | ||
| 17 | image: ziglang/static-base:llvm12-aarch64-1 | ||
| 18 | commands: | ||
| 19 | - ./ci/drone/linux_script_test 1 | ||
| 20 | |||
| 21 | - name: test-2 | ||
| 22 | depends_on: | ||
| 23 | - build | ||
| 24 | image: ziglang/static-base:llvm12-aarch64-1 | ||
| 25 | commands: | ||
| 26 | - ./ci/drone/linux_script_test 2 | ||
| 27 | |||
| 28 | - name: test-3 | ||
| 29 | depends_on: | ||
| 30 | - build | ||
| 31 | image: ziglang/static-base:llvm12-aarch64-1 | ||
| 32 | commands: | ||
| 33 | - ./ci/drone/linux_script_test 3 | ||
| 34 | |||
| 35 | - name: finalize | ||
| 36 | depends_on: | ||
| 37 | - build | ||
| 38 | - test-1 | ||
| 39 | - test-2 | ||
| 40 | - test-3 | ||
| 10 | image: ziglang/static-base:llvm12-aarch64-1 | 41 | image: ziglang/static-base:llvm12-aarch64-1 |
| 11 | environment: | 42 | environment: |
| 12 | SRHT_OAUTH_TOKEN: | 43 | SRHT_OAUTH_TOKEN: |
| ... | @@ -16,4 +47,4 @@ steps: | ... | @@ -16,4 +47,4 @@ steps: |
| 16 | AWS_SECRET_ACCESS_KEY: | 47 | AWS_SECRET_ACCESS_KEY: |
| 17 | from_secret: AWS_SECRET_ACCESS_KEY | 48 | from_secret: AWS_SECRET_ACCESS_KEY |
| 18 | commands: | 49 | commands: |
| 19 | - ./ci/drone/linux_script | 50 | - ./ci/drone/linux_script_finalize |
ci/drone/linux_script deleted-65| ... | @@ -1,65 +0,0 @@ | ||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | set -x | ||
| 4 | set -e | ||
| 5 | |||
| 6 | TRIPLEARCH="$(uname -m)" | ||
| 7 | BUILDDIR="$(pwd)" | ||
| 8 | DISTDIR="$(pwd)/dist" | ||
| 9 | |||
| 10 | apk update | ||
| 11 | apk add py3-pip xz perl-utils jq curl samurai | ||
| 12 | pip3 install s3cmd | ||
| 13 | |||
| 14 | # Make the `zig version` number consistent. | ||
| 15 | # This will affect the cmake command below. | ||
| 16 | git config core.abbrev 9 | ||
| 17 | git fetch --unshallow || true | ||
| 18 | git fetch --tags | ||
| 19 | |||
| 20 | mkdir build | ||
| 21 | cd build | ||
| 22 | cmake .. -DCMAKE_BUILD_TYPE=Release "-DCMAKE_INSTALL_PREFIX=$DISTDIR" -DZIG_STATIC=ON -DCMAKE_PREFIX_PATH=/deps/local -GNinja | ||
| 23 | |||
| 24 | samu install | ||
| 25 | # run-translated-c tests are skipped due to: https://github.com/ziglang/zig/issues/8537 | ||
| 26 | ./zig build test \ | ||
| 27 | -Dskip-release \ | ||
| 28 | -Dskip-non-native \ | ||
| 29 | -Dskip-compile-errors \ | ||
| 30 | -Dskip-run-translated-c | ||
| 31 | |||
| 32 | if [ -z "$DRONE_PULL_REQUEST" ]; then | ||
| 33 | mv ../LICENSE "$DISTDIR/" | ||
| 34 | mv ../zig-cache/langref.html "$DISTDIR/" | ||
| 35 | mv "$DISTDIR/bin/zig" "$DISTDIR/" | ||
| 36 | rmdir "$DISTDIR/bin" | ||
| 37 | |||
| 38 | GITBRANCH="$DRONE_BRANCH" | ||
| 39 | VERSION="$("$DISTDIR/zig" version)" | ||
| 40 | DIRNAME="zig-linux-$TRIPLEARCH-$VERSION" | ||
| 41 | TARBALL="$DIRNAME.tar.xz" | ||
| 42 | mv "$DISTDIR" "$DIRNAME" | ||
| 43 | tar cfJ "$TARBALL" "$DIRNAME" | ||
| 44 | |||
| 45 | s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/ | ||
| 46 | |||
| 47 | SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1) | ||
| 48 | BYTESIZE=$(wc -c < $TARBALL) | ||
| 49 | |||
| 50 | JSONFILE="$TRIPLEARCH-linux-$GITBRANCH.json" | ||
| 51 | touch $JSONFILE | ||
| 52 | echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE | ||
| 53 | echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE | ||
| 54 | echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE | ||
| 55 | |||
| 56 | s3cmd put -P --add-header="Cache-Control: max-age=0, must-revalidate" "$JSONFILE" "s3://ziglang.org/builds/$JSONFILE" | ||
| 57 | s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$TRIPLEARCH-linux-$VERSION.json" | ||
| 58 | if [ "$GITBRANCH" = "master" ]; then | ||
| 59 | # avoid leaking oauth token | ||
| 60 | set +x | ||
| 61 | |||
| 62 | cd "$BUILDDIR" | ||
| 63 | ./ci/srht/on_master_success "$VERSION" "$SRHT_OAUTH_TOKEN" | ||
| 64 | fi | ||
| 65 | fi | ||
ci/drone/linux_script_base created+22| ... | @@ -0,0 +1,22 @@ | ||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | # https://docs.drone.io/pipeline/docker/syntax/workspace/ | ||
| 4 | # | ||
| 5 | # Drone automatically creates a temporary volume, known as your workspace, | ||
| 6 | # where it clones your repository. The workspace is the current working | ||
| 7 | # directory for each step in your pipeline. | ||
| 8 | # | ||
| 9 | # Because the workspace is a volume, filesystem changes are persisted between | ||
| 10 | # pipeline steps. In other words, individual steps can communicate and share | ||
| 11 | # state using the filesystem. | ||
| 12 | # | ||
| 13 | # Workspace volumes are ephemeral. They are created when the pipeline starts | ||
| 14 | # and destroyed after the pipeline completes. | ||
| 15 | |||
| 16 | set -x | ||
| 17 | set -e | ||
| 18 | |||
| 19 | TRIPLEARCH="$(uname -m)" | ||
| 20 | DISTDIR="$DRONE_WORKSPACE/dist" | ||
| 21 | |||
| 22 | export ZIG_GLOBAL_CACHE_DIR="$DRONE_WORKSPACE/zig-cache" | ||
ci/drone/linux_script_build created+18| ... | @@ -0,0 +1,18 @@ | ||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | . ./ci/drone/linux_script_base | ||
| 4 | |||
| 5 | apk update | ||
| 6 | apk add samurai | ||
| 7 | |||
| 8 | # Make the `zig version` number consistent. | ||
| 9 | # This will affect the cmake command below. | ||
| 10 | git config core.abbrev 9 | ||
| 11 | git fetch --unshallow || true | ||
| 12 | git fetch --tags | ||
| 13 | |||
| 14 | mkdir build | ||
| 15 | cd build | ||
| 16 | cmake .. -DCMAKE_BUILD_TYPE=Release "-DCMAKE_INSTALL_PREFIX=$DISTDIR" -DZIG_STATIC=ON -DCMAKE_PREFIX_PATH=/deps/local -GNinja | ||
| 17 | |||
| 18 | samu install | ||
ci/drone/linux_script_finalize created+46| ... | @@ -0,0 +1,46 @@ | ||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | . ./ci/drone/linux_script_base | ||
| 4 | |||
| 5 | if [ -n "$DRONE_PULL_REQUEST" ]; then | ||
| 6 | exit 0 | ||
| 7 | fi | ||
| 8 | |||
| 9 | apk update | ||
| 10 | apk add py3-pip xz perl-utils jq curl samurai | ||
| 11 | pip3 install s3cmd | ||
| 12 | |||
| 13 | cd build | ||
| 14 | |||
| 15 | mv ../LICENSE "$DISTDIR/" | ||
| 16 | # docs are disabled due to: https://github.com/ziglang/zig/issues/8597 | ||
| 17 | #mv ../zig-cache/langref.html "$DISTDIR/" | ||
| 18 | mv "$DISTDIR/bin/zig" "$DISTDIR/" | ||
| 19 | rmdir "$DISTDIR/bin" | ||
| 20 | |||
| 21 | GITBRANCH="$DRONE_BRANCH" | ||
| 22 | VERSION="$("$DISTDIR/zig" version)" | ||
| 23 | DIRNAME="zig-linux-$TRIPLEARCH-$VERSION" | ||
| 24 | TARBALL="$DIRNAME.tar.xz" | ||
| 25 | mv "$DISTDIR" "$DIRNAME" | ||
| 26 | tar cfJ "$TARBALL" "$DIRNAME" | ||
| 27 | |||
| 28 | s3cmd put -P --add-header="cache-control: public, max-age=31536000, immutable" "$TARBALL" s3://ziglang.org/builds/ | ||
| 29 | |||
| 30 | SHASUM=$(shasum -a 256 $TARBALL | cut '-d ' -f1) | ||
| 31 | BYTESIZE=$(wc -c < $TARBALL) | ||
| 32 | |||
| 33 | JSONFILE="tarball.json" | ||
| 34 | touch $JSONFILE | ||
| 35 | echo "{\"tarball\": \"$TARBALL\"," >>$JSONFILE | ||
| 36 | echo "\"shasum\": \"$SHASUM\"," >>$JSONFILE | ||
| 37 | echo "\"size\": \"$BYTESIZE\"}" >>$JSONFILE | ||
| 38 | |||
| 39 | s3cmd put -P "$JSONFILE" "s3://ziglang.org/builds/$TRIPLEARCH-linux-$VERSION.json" | ||
| 40 | if [ "$GITBRANCH" = "master" ]; then | ||
| 41 | # avoid leaking oauth token | ||
| 42 | set +x | ||
| 43 | |||
| 44 | cd "$DRONE_WORKSPACE" | ||
| 45 | ./ci/srht/on_master_success "$VERSION" "$SRHT_OAUTH_TOKEN" | ||
| 46 | fi | ||
ci/drone/linux_script_test created+46| ... | @@ -0,0 +1,46 @@ | ||
| 1 | #!/bin/sh | ||
| 2 | |||
| 3 | . ./ci/drone/linux_script_base | ||
| 4 | |||
| 5 | # only release-fast builds of test suite due to: https://github.com/ziglang/zig/issues/8597 | ||
| 6 | # | ||
| 7 | # Some test suite components will be missing because they do not support | ||
| 8 | # forcing -OReleaseFast | ||
| 9 | # | ||
| 10 | # see `zig build --help` for the full list of test-* components | ||
| 11 | case "$1" in | ||
| 12 | 1) | ||
| 13 | steps="\ | ||
| 14 | test-stage2 \ | ||
| 15 | test-fmt \ | ||
| 16 | test-behavior" | ||
| 17 | ;; | ||
| 18 | 2) | ||
| 19 | steps="test-std" | ||
| 20 | ;; | ||
| 21 | 3) | ||
| 22 | steps="\ | ||
| 23 | test-compiler-rt \ | ||
| 24 | test-minilibc \ | ||
| 25 | test-compare-output \ | ||
| 26 | test-translate-c \ | ||
| 27 | test-run-translated-c" | ||
| 28 | ;; | ||
| 29 | '') | ||
| 30 | echo "error: expecting test group argument" | ||
| 31 | exit 1 | ||
| 32 | ;; | ||
| 33 | *) | ||
| 34 | echo "error: unknown test group: $1" | ||
| 35 | exit 1 | ||
| 36 | ;; | ||
| 37 | esac | ||
| 38 | |||
| 39 | # only release-fast builds of test suite due to: https://github.com/ziglang/zig/issues/8597 | ||
| 40 | ./build/zig build \ | ||
| 41 | -Drelease \ | ||
| 42 | -Dskip-debug \ | ||
| 43 | -Dskip-release-small \ | ||
| 44 | -Dskip-release-safe \ | ||
| 45 | -Dskip-non-native \ | ||
| 46 | $steps | ||
lib/std/Thread.zig+6-3| ... | @@ -199,7 +199,8 @@ pub fn spawn(comptime startFn: anytype, context: SpawnContextType(@TypeOf(startF | ... | @@ -199,7 +199,8 @@ pub fn spawn(comptime startFn: anytype, context: SpawnContextType(@TypeOf(startF |
| 199 | inner: Context, | 199 | inner: Context, |
| 200 | }; | 200 | }; |
| 201 | fn threadMain(raw_arg: windows.LPVOID) callconv(.C) windows.DWORD { | 201 | fn threadMain(raw_arg: windows.LPVOID) callconv(.C) windows.DWORD { |
| 202 | const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*; | 202 | const arg = if (@sizeOf(Context) == 0) undefined // |
| 203 | else @ptrCast(*Context, @alignCast(@alignOf(Context), raw_arg)).*; | ||
| 203 | 204 | ||
| 204 | switch (@typeInfo(@typeInfo(@TypeOf(startFn)).Fn.return_type.?)) { | 205 | switch (@typeInfo(@typeInfo(@TypeOf(startFn)).Fn.return_type.?)) { |
| 205 | .NoReturn => { | 206 | .NoReturn => { |
| ... | @@ -260,7 +261,8 @@ pub fn spawn(comptime startFn: anytype, context: SpawnContextType(@TypeOf(startF | ... | @@ -260,7 +261,8 @@ pub fn spawn(comptime startFn: anytype, context: SpawnContextType(@TypeOf(startF |
| 260 | 261 | ||
| 261 | const MainFuncs = struct { | 262 | const MainFuncs = struct { |
| 262 | fn linuxThreadMain(ctx_addr: usize) callconv(.C) u8 { | 263 | fn linuxThreadMain(ctx_addr: usize) callconv(.C) u8 { |
| 263 | const arg = if (@sizeOf(Context) == 0) {} else @intToPtr(*const Context, ctx_addr).*; | 264 | const arg = if (@sizeOf(Context) == 0) undefined // |
| 265 | else @intToPtr(*Context, ctx_addr).*; | ||
| 264 | 266 | ||
| 265 | switch (@typeInfo(@typeInfo(@TypeOf(startFn)).Fn.return_type.?)) { | 267 | switch (@typeInfo(@typeInfo(@TypeOf(startFn)).Fn.return_type.?)) { |
| 266 | .NoReturn => { | 268 | .NoReturn => { |
| ... | @@ -292,7 +294,8 @@ pub fn spawn(comptime startFn: anytype, context: SpawnContextType(@TypeOf(startF | ... | @@ -292,7 +294,8 @@ pub fn spawn(comptime startFn: anytype, context: SpawnContextType(@TypeOf(startF |
| 292 | } | 294 | } |
| 293 | } | 295 | } |
| 294 | fn posixThreadMain(ctx: ?*c_void) callconv(.C) ?*c_void { | 296 | fn posixThreadMain(ctx: ?*c_void) callconv(.C) ?*c_void { |
| 295 | const arg = if (@sizeOf(Context) == 0) {} else @ptrCast(*Context, @alignCast(@alignOf(Context), ctx)).*; | 297 | const arg = if (@sizeOf(Context) == 0) undefined // |
| 298 | else @ptrCast(*Context, @alignCast(@alignOf(Context), ctx)).*; | ||
| 296 | 299 | ||
| 297 | switch (@typeInfo(@typeInfo(@TypeOf(startFn)).Fn.return_type.?)) { | 300 | switch (@typeInfo(@typeInfo(@TypeOf(startFn)).Fn.return_type.?)) { |
| 298 | .NoReturn => { | 301 | .NoReturn => { |
lib/std/builtin.zig+1| ... | @@ -166,6 +166,7 @@ pub const CallingConvention = enum { | ... | @@ -166,6 +166,7 @@ pub const CallingConvention = enum { |
| 166 | APCS, | 166 | APCS, |
| 167 | AAPCS, | 167 | AAPCS, |
| 168 | AAPCSVFP, | 168 | AAPCSVFP, |
| 169 | SysV | ||
| 169 | }; | 170 | }; |
| 170 | 171 | ||
| 171 | /// This data structure is used by the Zig language code generation and | 172 | /// This data structure is used by the Zig language code generation and |
lib/std/c/haiku.zig+48| ... | @@ -69,3 +69,51 @@ pub const pthread_rwlock_t = extern struct { | ... | @@ -69,3 +69,51 @@ pub const pthread_rwlock_t = extern struct { |
| 69 | writer_count: i32 = 0, | 69 | writer_count: i32 = 0, |
| 70 | waiters: [2]?*c_void = [_]?*c_void{ null, null }, | 70 | waiters: [2]?*c_void = [_]?*c_void{ null, null }, |
| 71 | }; | 71 | }; |
| 72 | |||
| 73 | pub const EAI = extern enum(c_int) { | ||
| 74 | /// address family for hostname not supported | ||
| 75 | ADDRFAMILY = 1, | ||
| 76 | |||
| 77 | /// name could not be resolved at this time | ||
| 78 | AGAIN = 2, | ||
| 79 | |||
| 80 | /// flags parameter had an invalid value | ||
| 81 | BADFLAGS = 3, | ||
| 82 | |||
| 83 | /// non-recoverable failure in name resolution | ||
| 84 | FAIL = 4, | ||
| 85 | |||
| 86 | /// address family not recognized | ||
| 87 | FAMILY = 5, | ||
| 88 | |||
| 89 | /// memory allocation failure | ||
| 90 | MEMORY = 6, | ||
| 91 | |||
| 92 | /// no address associated with hostname | ||
| 93 | NODATA = 7, | ||
| 94 | |||
| 95 | /// name does not resolve | ||
| 96 | NONAME = 8, | ||
| 97 | |||
| 98 | /// service not recognized for socket type | ||
| 99 | SERVICE = 9, | ||
| 100 | |||
| 101 | /// intended socket type was not recognized | ||
| 102 | SOCKTYPE = 10, | ||
| 103 | |||
| 104 | /// system error returned in errno | ||
| 105 | SYSTEM = 11, | ||
| 106 | |||
| 107 | /// invalid value for hints | ||
| 108 | BADHINTS = 12, | ||
| 109 | |||
| 110 | /// resolved protocol is unknown | ||
| 111 | PROTOCOL = 13, | ||
| 112 | |||
| 113 | /// argument buffer overflow | ||
| 114 | OVERFLOW = 14, | ||
| 115 | |||
| 116 | _, | ||
| 117 | }; | ||
| 118 | |||
| 119 | pub const EAI_MAX = 15; |
lib/std/child_process.zig+1-1| ... | @@ -264,7 +264,7 @@ pub const ChildProcess = struct { | ... | @@ -264,7 +264,7 @@ pub const ChildProcess = struct { |
| 264 | 264 | ||
| 265 | // TODO collect output in a deadlock-avoiding way on Windows. | 265 | // TODO collect output in a deadlock-avoiding way on Windows. |
| 266 | // https://github.com/ziglang/zig/issues/6343 | 266 | // https://github.com/ziglang/zig/issues/6343 |
| 267 | if (builtin.os.tag == .windows) { | 267 | if (builtin.os.tag == .windows or builtin.os.tag == .haiku) { |
| 268 | const stdout_in = child.stdout.?.reader(); | 268 | const stdout_in = child.stdout.?.reader(); |
| 269 | const stderr_in = child.stderr.?.reader(); | 269 | const stderr_in = child.stderr.?.reader(); |
| 270 | 270 |
lib/std/crypto/25519/edwards25519.zig+9-16| ... | @@ -75,16 +75,8 @@ pub const Edwards25519 = struct { | ... | @@ -75,16 +75,8 @@ pub const Edwards25519 = struct { |
| 75 | .is_base = true, | 75 | .is_base = true, |
| 76 | }; | 76 | }; |
| 77 | 77 | ||
| 78 | /// The edwards25519 neutral element. | 78 | pub const neutralElement = @compileError("deprecated: use identityElement instead"); |
| 79 | pub const neutralElement = Edwards25519{ | 79 | pub const identityElement = Edwards25519{ .x = Fe.zero, .y = Fe.one, .z = Fe.one, .t = Fe.zero }; |
| 80 | .x = Fe{ .limbs = .{ 2251799813685229, 2251799813685247, 2251799813685247, 2251799813685247, 2251799813685247 } }, | ||
| 81 | .y = Fe{ .limbs = .{ 1507481815385608, 2223447444246085, 1083941587175919, 2059929906842505, 1581435440146976 } }, | ||
| 82 | .z = Fe{ .limbs = .{ 1507481815385608, 2223447444246085, 1083941587175919, 2059929906842505, 1581435440146976 } }, | ||
| 83 | .t = Fe{ .limbs = .{ 2251799813685229, 2251799813685247, 2251799813685247, 2251799813685247, 2251799813685247 } }, | ||
| 84 | .is_base = false, | ||
| 85 | }; | ||
| 86 | |||
| 87 | const identityElement = Edwards25519{ .x = Fe.zero, .y = Fe.one, .z = Fe.one, .t = Fe.zero }; | ||
| 88 | 80 | ||
| 89 | /// Reject the neutral element. | 81 | /// Reject the neutral element. |
| 90 | pub fn rejectIdentity(p: Edwards25519) IdentityElementError!void { | 82 | pub fn rejectIdentity(p: Edwards25519) IdentityElementError!void { |
| ... | @@ -160,9 +152,10 @@ pub const Edwards25519 = struct { | ... | @@ -160,9 +152,10 @@ pub const Edwards25519 = struct { |
| 160 | return t; | 152 | return t; |
| 161 | } | 153 | } |
| 162 | 154 | ||
| 163 | fn nonAdjacentForm(s: [32]u8) [2 * 32]i8 { | 155 | fn slide(s: [32]u8) [2 * 32]i8 { |
| 156 | const reduced = if ((s[s.len - 1] & 0x80) != 0) s else scalar.reduce(s); | ||
| 164 | var e: [2 * 32]i8 = undefined; | 157 | var e: [2 * 32]i8 = undefined; |
| 165 | for (s) |x, i| { | 158 | for (reduced) |x, i| { |
| 166 | e[i * 2 + 0] = @as(i8, @truncate(u4, x)); | 159 | e[i * 2 + 0] = @as(i8, @truncate(u4, x)); |
| 167 | e[i * 2 + 1] = @as(i8, @truncate(u4, x >> 4)); | 160 | e[i * 2 + 1] = @as(i8, @truncate(u4, x >> 4)); |
| 168 | } | 161 | } |
| ... | @@ -185,7 +178,7 @@ pub const Edwards25519 = struct { | ... | @@ -185,7 +178,7 @@ pub const Edwards25519 = struct { |
| 185 | // avoid these to keep the standard library lightweight. | 178 | // avoid these to keep the standard library lightweight. |
| 186 | fn pcMul(pc: [9]Edwards25519, s: [32]u8, comptime vartime: bool) IdentityElementError!Edwards25519 { | 179 | fn pcMul(pc: [9]Edwards25519, s: [32]u8, comptime vartime: bool) IdentityElementError!Edwards25519 { |
| 187 | std.debug.assert(vartime); | 180 | std.debug.assert(vartime); |
| 188 | const e = nonAdjacentForm(s); | 181 | const e = slide(s); |
| 189 | var q = Edwards25519.identityElement; | 182 | var q = Edwards25519.identityElement; |
| 190 | var pos: usize = 2 * 32 - 1; | 183 | var pos: usize = 2 * 32 - 1; |
| 191 | while (true) : (pos -= 1) { | 184 | while (true) : (pos -= 1) { |
| ... | @@ -280,8 +273,8 @@ pub const Edwards25519 = struct { | ... | @@ -280,8 +273,8 @@ pub const Edwards25519 = struct { |
| 280 | xpc[4].rejectIdentity() catch return error.WeakPublicKey; | 273 | xpc[4].rejectIdentity() catch return error.WeakPublicKey; |
| 281 | break :pc xpc; | 274 | break :pc xpc; |
| 282 | }; | 275 | }; |
| 283 | const e1 = nonAdjacentForm(s1); | 276 | const e1 = slide(s1); |
| 284 | const e2 = nonAdjacentForm(s2); | 277 | const e2 = slide(s2); |
| 285 | var q = Edwards25519.identityElement; | 278 | var q = Edwards25519.identityElement; |
| 286 | var pos: usize = 2 * 32 - 1; | 279 | var pos: usize = 2 * 32 - 1; |
| 287 | while (true) : (pos -= 1) { | 280 | while (true) : (pos -= 1) { |
| ... | @@ -318,7 +311,7 @@ pub const Edwards25519 = struct { | ... | @@ -318,7 +311,7 @@ pub const Edwards25519 = struct { |
| 318 | } | 311 | } |
| 319 | var es: [count][2 * 32]i8 = undefined; | 312 | var es: [count][2 * 32]i8 = undefined; |
| 320 | for (ss) |s, i| { | 313 | for (ss) |s, i| { |
| 321 | es[i] = nonAdjacentForm(s); | 314 | es[i] = slide(s); |
| 322 | } | 315 | } |
| 323 | var q = Edwards25519.identityElement; | 316 | var q = Edwards25519.identityElement; |
| 324 | var pos: usize = 2 * 32 - 1; | 317 | var pos: usize = 2 * 32 - 1; |
lib/std/crypto/25519/field.zig+1-1| ... | @@ -355,7 +355,7 @@ pub const Fe = struct { | ... | @@ -355,7 +355,7 @@ pub const Fe = struct { |
| 355 | return fe; | 355 | return fe; |
| 356 | } | 356 | } |
| 357 | 357 | ||
| 358 | /// Compute the inverse of a field element | 358 | /// Return the inverse of a field element, or 0 if a=0. |
| 359 | pub fn invert(a: Fe) Fe { | 359 | pub fn invert(a: Fe) Fe { |
| 360 | var t0 = a.sq(); | 360 | var t0 = a.sq(); |
| 361 | var t1 = t0.sqn(2).mul(a); | 361 | var t1 = t0.sqn(2).mul(a); |
lib/std/crypto/25519/scalar.zig+1-1| ... | @@ -98,7 +98,7 @@ pub fn sub(a: [32]u8, b: [32]u8) [32]u8 { | ... | @@ -98,7 +98,7 @@ pub fn sub(a: [32]u8, b: [32]u8) [32]u8 { |
| 98 | return add(a, neg(b)); | 98 | return add(a, neg(b)); |
| 99 | } | 99 | } |
| 100 | 100 | ||
| 101 | /// A scalar in unpacked reprentation | 101 | /// A scalar in unpacked representation |
| 102 | pub const Scalar = struct { | 102 | pub const Scalar = struct { |
| 103 | const Limbs = [5]u64; | 103 | const Limbs = [5]u64; |
| 104 | limbs: Limbs = undefined, | 104 | limbs: Limbs = undefined, |
lib/std/crypto/utils.zig+52| ... | @@ -1,7 +1,11 @@ | ... | @@ -1,7 +1,11 @@ |
| 1 | const std = @import("../std.zig"); | 1 | const std = @import("../std.zig"); |
| 2 | const debug = std.debug; | ||
| 2 | const mem = std.mem; | 3 | const mem = std.mem; |
| 3 | const testing = std.testing; | 4 | const testing = std.testing; |
| 4 | 5 | ||
| 6 | const Endian = std.builtin.Endian; | ||
| 7 | const Order = std.math.Order; | ||
| 8 | |||
| 5 | /// Compares two arrays in constant time (for a given length) and returns whether they are equal. | 9 | /// Compares two arrays in constant time (for a given length) and returns whether they are equal. |
| 6 | /// This function was designed to compare short cryptographic secrets (MACs, signatures). | 10 | /// This function was designed to compare short cryptographic secrets (MACs, signatures). |
| 7 | /// For all other applications, use mem.eql() instead. | 11 | /// For all other applications, use mem.eql() instead. |
| ... | @@ -38,6 +42,41 @@ pub fn timingSafeEql(comptime T: type, a: T, b: T) bool { | ... | @@ -38,6 +42,41 @@ pub fn timingSafeEql(comptime T: type, a: T, b: T) bool { |
| 38 | } | 42 | } |
| 39 | } | 43 | } |
| 40 | 44 | ||
| 45 | /// Compare two integers serialized as arrays of the same size, in constant time. | ||
| 46 | /// Returns .lt if a<b, .gt if a>b and .eq if a=b | ||
| 47 | pub fn timingSafeCompare(comptime T: type, a: []const T, b: []const T, endian: Endian) Order { | ||
| 48 | debug.assert(a.len == b.len); | ||
| 49 | const bits = switch (@typeInfo(T)) { | ||
| 50 | .Int => |cinfo| if (cinfo.signedness != .unsigned) @compileError("Elements to be compared must be unsigned") else cinfo.bits, | ||
| 51 | else => @compileError("Elements to be compared must be integers"), | ||
| 52 | }; | ||
| 53 | comptime const Cext = std.meta.Int(.unsigned, bits + 1); | ||
| 54 | var gt: T = 0; | ||
| 55 | var eq: T = 1; | ||
| 56 | if (endian == .Little) { | ||
| 57 | var i = a.len; | ||
| 58 | while (i != 0) { | ||
| 59 | i -= 1; | ||
| 60 | const x1 = a[i]; | ||
| 61 | const x2 = b[i]; | ||
| 62 | gt |= @truncate(T, (@as(Cext, x2) -% @as(Cext, x1)) >> bits) & eq; | ||
| 63 | eq &= @truncate(T, (@as(Cext, (x2 ^ x1)) -% 1) >> bits); | ||
| 64 | } | ||
| 65 | } else { | ||
| 66 | for (a) |x1, i| { | ||
| 67 | const x2 = b[i]; | ||
| 68 | gt |= @truncate(T, (@as(Cext, x2) -% @as(Cext, x1)) >> bits) & eq; | ||
| 69 | eq &= @truncate(T, (@as(Cext, (x2 ^ x1)) -% 1) >> bits); | ||
| 70 | } | ||
| 71 | } | ||
| 72 | if (gt != 0) { | ||
| 73 | return Order.gt; | ||
| 74 | } else if (eq != 0) { | ||
| 75 | return Order.eq; | ||
| 76 | } | ||
| 77 | return Order.lt; | ||
| 78 | } | ||
| 79 | |||
| 41 | /// Sets a slice to zeroes. | 80 | /// Sets a slice to zeroes. |
| 42 | /// Prevents the store from being optimized out. | 81 | /// Prevents the store from being optimized out. |
| 43 | pub fn secureZero(comptime T: type, s: []T) void { | 82 | pub fn secureZero(comptime T: type, s: []T) void { |
| ... | @@ -70,6 +109,19 @@ test "crypto.utils.timingSafeEql (vectors)" { | ... | @@ -70,6 +109,19 @@ test "crypto.utils.timingSafeEql (vectors)" { |
| 70 | testing.expect(timingSafeEql(std.meta.Vector(100, u8), v1, v3)); | 109 | testing.expect(timingSafeEql(std.meta.Vector(100, u8), v1, v3)); |
| 71 | } | 110 | } |
| 72 | 111 | ||
| 112 | test "crypto.utils.timingSafeCompare" { | ||
| 113 | var a = [_]u8{10} ** 32; | ||
| 114 | var b = [_]u8{10} ** 32; | ||
| 115 | testing.expectEqual(timingSafeCompare(u8, &a, &b, .Big), .eq); | ||
| 116 | testing.expectEqual(timingSafeCompare(u8, &a, &b, .Little), .eq); | ||
| 117 | a[31] = 1; | ||
| 118 | testing.expectEqual(timingSafeCompare(u8, &a, &b, .Big), .lt); | ||
| 119 | testing.expectEqual(timingSafeCompare(u8, &a, &b, .Little), .lt); | ||
| 120 | a[0] = 20; | ||
| 121 | testing.expectEqual(timingSafeCompare(u8, &a, &b, .Big), .gt); | ||
| 122 | testing.expectEqual(timingSafeCompare(u8, &a, &b, .Little), .lt); | ||
| 123 | } | ||
| 124 | |||
| 73 | test "crypto.utils.secureZero" { | 125 | test "crypto.utils.secureZero" { |
| 74 | var a = [_]u8{0xfe} ** 8; | 126 | var a = [_]u8{0xfe} ** 8; |
| 75 | var b = [_]u8{0xfe} ** 8; | 127 | var b = [_]u8{0xfe} ** 8; |
lib/std/debug.zig+11-4| ... | @@ -339,6 +339,13 @@ pub const StackIterator = struct { | ... | @@ -339,6 +339,13 @@ pub const StackIterator = struct { |
| 339 | fp: usize, | 339 | fp: usize, |
| 340 | 340 | ||
| 341 | pub fn init(first_address: ?usize, fp: ?usize) StackIterator { | 341 | pub fn init(first_address: ?usize, fp: ?usize) StackIterator { |
| 342 | if (native_arch == .sparcv9) { | ||
| 343 | // Flush all the register windows on stack. | ||
| 344 | asm volatile ( | ||
| 345 | \\ flushw | ||
| 346 | ::: "memory"); | ||
| 347 | } | ||
| 348 | |||
| 342 | return StackIterator{ | 349 | return StackIterator{ |
| 343 | .first_address = first_address, | 350 | .first_address = first_address, |
| 344 | .fp = fp orelse @frameAddress(), | 351 | .fp = fp orelse @frameAddress(), |
| ... | @@ -346,18 +353,18 @@ pub const StackIterator = struct { | ... | @@ -346,18 +353,18 @@ pub const StackIterator = struct { |
| 346 | } | 353 | } |
| 347 | 354 | ||
| 348 | // Offset of the saved BP wrt the frame pointer. | 355 | // Offset of the saved BP wrt the frame pointer. |
| 349 | const fp_offset = if (native_arch.isRISCV()) | 356 | const fp_offset = if (comptime native_arch.isRISCV()) |
| 350 | // On RISC-V the frame pointer points to the top of the saved register | 357 | // On RISC-V the frame pointer points to the top of the saved register |
| 351 | // area, on pretty much every other architecture it points to the stack | 358 | // area, on pretty much every other architecture it points to the stack |
| 352 | // slot where the previous frame pointer is saved. | 359 | // slot where the previous frame pointer is saved. |
| 353 | 2 * @sizeOf(usize) | 360 | 2 * @sizeOf(usize) |
| 354 | else if (native_arch.isSPARC()) | 361 | else if (comptime native_arch.isSPARC()) |
| 355 | // On SPARC the previous frame pointer is stored at 14 slots past %fp+BIAS. | 362 | // On SPARC the previous frame pointer is stored at 14 slots past %fp+BIAS. |
| 356 | 14 * @sizeOf(usize) | 363 | 14 * @sizeOf(usize) |
| 357 | else | 364 | else |
| 358 | 0; | 365 | 0; |
| 359 | 366 | ||
| 360 | const fp_bias = if (native_arch.isSPARC()) | 367 | const fp_bias = if (comptime native_arch.isSPARC()) |
| 361 | // On SPARC frame pointers are biased by a constant. | 368 | // On SPARC frame pointers are biased by a constant. |
| 362 | 2047 | 369 | 2047 |
| 363 | else | 370 | else |
| ... | @@ -383,7 +390,7 @@ pub const StackIterator = struct { | ... | @@ -383,7 +390,7 @@ pub const StackIterator = struct { |
| 383 | } | 390 | } |
| 384 | 391 | ||
| 385 | fn next_internal(self: *StackIterator) ?usize { | 392 | fn next_internal(self: *StackIterator) ?usize { |
| 386 | const fp = if (native_arch.isSPARC()) | 393 | const fp = if (comptime native_arch.isSPARC()) |
| 387 | // On SPARC the offset is positive. (!) | 394 | // On SPARC the offset is positive. (!) |
| 388 | math.add(usize, self.fp, fp_offset) catch return null | 395 | math.add(usize, self.fp, fp_offset) catch return null |
| 389 | else | 396 | else |
lib/std/fmt.zig+3-1| ... | @@ -1523,9 +1523,11 @@ test "parseUnsigned" { | ... | @@ -1523,9 +1523,11 @@ test "parseUnsigned" { |
| 1523 | } | 1523 | } |
| 1524 | 1524 | ||
| 1525 | pub const parseFloat = @import("fmt/parse_float.zig").parseFloat; | 1525 | pub const parseFloat = @import("fmt/parse_float.zig").parseFloat; |
| 1526 | pub const parseHexFloat = @import("fmt/parse_hex_float.zig").parseHexFloat; | ||
| 1526 | 1527 | ||
| 1527 | test "parseFloat" { | 1528 | test { |
| 1528 | _ = @import("fmt/parse_float.zig"); | 1529 | _ = @import("fmt/parse_float.zig"); |
| 1530 | _ = @import("fmt/parse_hex_float.zig"); | ||
| 1529 | } | 1531 | } |
| 1530 | 1532 | ||
| 1531 | pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { | 1533 | pub fn charToDigit(c: u8, radix: u8) (error{InvalidCharacter}!u8) { |
lib/std/fmt/parse_hex_float.zig created+352| ... | @@ -0,0 +1,352 @@ | ||
| 1 | // SPDX-License-Identifier: MIT | ||
| 2 | // Copyright (c) 2015-2021 Zig Contributors | ||
| 3 | // This file is part of [zig](https://ziglang.org/), which is MIT licensed. | ||
| 4 | // The MIT license requires this copyright notice to be included in all copies | ||
| 5 | // and substantial portions of the software.const std = @import("std"); | ||
| 6 | // | ||
| 7 | // The rounding logic is inspired by LLVM's APFloat and Go's atofHex | ||
| 8 | // implementation. | ||
| 9 | |||
| 10 | const std = @import("std"); | ||
| 11 | const ascii = std.ascii; | ||
| 12 | const fmt = std.fmt; | ||
| 13 | const math = std.math; | ||
| 14 | const testing = std.testing; | ||
| 15 | |||
| 16 | const assert = std.debug.assert; | ||
| 17 | |||
| 18 | pub fn parseHexFloat(comptime T: type, s: []const u8) !T { | ||
| 19 | assert(@typeInfo(T) == .Float); | ||
| 20 | |||
| 21 | const IntT = std.meta.Int(.unsigned, @typeInfo(T).Float.bits); | ||
| 22 | |||
| 23 | const mantissa_bits = math.floatMantissaBits(T); | ||
| 24 | const exponent_bits = math.floatExponentBits(T); | ||
| 25 | |||
| 26 | const sign_shift = mantissa_bits + exponent_bits; | ||
| 27 | |||
| 28 | const exponent_bias = (1 << (exponent_bits - 1)) - 1; | ||
| 29 | const exponent_min = 1 - exponent_bias; | ||
| 30 | const exponent_max = exponent_bias; | ||
| 31 | |||
| 32 | if (s.len == 0) | ||
| 33 | return error.InvalidCharacter; | ||
| 34 | |||
| 35 | if (ascii.eqlIgnoreCase(s, "nan")) { | ||
| 36 | return math.nan(T); | ||
| 37 | } else if (ascii.eqlIgnoreCase(s, "inf") or ascii.eqlIgnoreCase(s, "+inf")) { | ||
| 38 | return math.inf(T); | ||
| 39 | } else if (ascii.eqlIgnoreCase(s, "-inf")) { | ||
| 40 | return -math.inf(T); | ||
| 41 | } | ||
| 42 | |||
| 43 | var negative: bool = false; | ||
| 44 | var exp_negative: bool = false; | ||
| 45 | |||
| 46 | var mantissa: u128 = 0; | ||
| 47 | var exponent: i16 = 0; | ||
| 48 | var frac_scale: i16 = 0; | ||
| 49 | |||
| 50 | const State = enum { | ||
| 51 | MaybeSign, | ||
| 52 | Prefix, | ||
| 53 | LeadingIntegerDigit, | ||
| 54 | IntegerDigit, | ||
| 55 | MaybeDot, | ||
| 56 | LeadingFractionDigit, | ||
| 57 | FractionDigit, | ||
| 58 | ExpPrefix, | ||
| 59 | MaybeExpSign, | ||
| 60 | ExpDigit, | ||
| 61 | }; | ||
| 62 | |||
| 63 | var state = State.MaybeSign; | ||
| 64 | |||
| 65 | var i: usize = 0; | ||
| 66 | while (i < s.len) { | ||
| 67 | const c = s[i]; | ||
| 68 | |||
| 69 | switch (state) { | ||
| 70 | .MaybeSign => { | ||
| 71 | state = .Prefix; | ||
| 72 | |||
| 73 | if (c == '+') { | ||
| 74 | i += 1; | ||
| 75 | } else if (c == '-') { | ||
| 76 | negative = true; | ||
| 77 | i += 1; | ||
| 78 | } | ||
| 79 | }, | ||
| 80 | .Prefix => { | ||
| 81 | state = .LeadingIntegerDigit; | ||
| 82 | |||
| 83 | // Match both 0x and 0X. | ||
| 84 | if (i + 2 > s.len or s[i] != '0' or s[i + 1] | 32 != 'x') | ||
| 85 | return error.InvalidCharacter; | ||
| 86 | i += 2; | ||
| 87 | }, | ||
| 88 | .LeadingIntegerDigit => { | ||
| 89 | if (c == '0') { | ||
| 90 | // Skip leading zeros. | ||
| 91 | i += 1; | ||
| 92 | } else if (c == '_') { | ||
| 93 | return error.InvalidCharacter; | ||
| 94 | } else { | ||
| 95 | state = .IntegerDigit; | ||
| 96 | } | ||
| 97 | }, | ||
| 98 | .IntegerDigit => { | ||
| 99 | if (ascii.isXDigit(c)) { | ||
| 100 | if (mantissa >= math.maxInt(u128) / 16) | ||
| 101 | return error.Overflow; | ||
| 102 | mantissa *%= 16; | ||
| 103 | mantissa += try fmt.charToDigit(c, 16); | ||
| 104 | i += 1; | ||
| 105 | } else if (c == '_') { | ||
| 106 | i += 1; | ||
| 107 | } else { | ||
| 108 | state = .MaybeDot; | ||
| 109 | } | ||
| 110 | }, | ||
| 111 | .MaybeDot => { | ||
| 112 | if (c == '.') { | ||
| 113 | state = .LeadingFractionDigit; | ||
| 114 | i += 1; | ||
| 115 | } else state = .ExpPrefix; | ||
| 116 | }, | ||
| 117 | .LeadingFractionDigit => { | ||
| 118 | if (c == '_') { | ||
| 119 | return error.InvalidCharacter; | ||
| 120 | } else state = .FractionDigit; | ||
| 121 | }, | ||
| 122 | .FractionDigit => { | ||
| 123 | if (ascii.isXDigit(c)) { | ||
| 124 | if (mantissa < math.maxInt(u128) / 16) { | ||
| 125 | mantissa *%= 16; | ||
| 126 | mantissa +%= try fmt.charToDigit(c, 16); | ||
| 127 | frac_scale += 1; | ||
| 128 | } else if (c != '0') { | ||
| 129 | return error.Overflow; | ||
| 130 | } | ||
| 131 | i += 1; | ||
| 132 | } else if (c == '_') { | ||
| 133 | i += 1; | ||
| 134 | } else { | ||
| 135 | state = .ExpPrefix; | ||
| 136 | } | ||
| 137 | }, | ||
| 138 | .ExpPrefix => { | ||
| 139 | state = .MaybeExpSign; | ||
| 140 | // Match both p and P. | ||
| 141 | if (c | 32 != 'p') | ||
| 142 | return error.InvalidCharacter; | ||
| 143 | i += 1; | ||
| 144 | }, | ||
| 145 | .MaybeExpSign => { | ||
| 146 | state = .ExpDigit; | ||
| 147 | |||
| 148 | if (c == '+') { | ||
| 149 | i += 1; | ||
| 150 | } else if (c == '-') { | ||
| 151 | exp_negative = true; | ||
| 152 | i += 1; | ||
| 153 | } | ||
| 154 | }, | ||
| 155 | .ExpDigit => { | ||
| 156 | if (ascii.isXDigit(c)) { | ||
| 157 | if (exponent >= math.maxInt(i16) / 10) | ||
| 158 | return error.Overflow; | ||
| 159 | exponent *%= 10; | ||
| 160 | exponent +%= try fmt.charToDigit(c, 10); | ||
| 161 | i += 1; | ||
| 162 | } else if (c == '_') { | ||
| 163 | i += 1; | ||
| 164 | } else { | ||
| 165 | return error.InvalidCharacter; | ||
| 166 | } | ||
| 167 | }, | ||
| 168 | } | ||
| 169 | } | ||
| 170 | |||
| 171 | if (exp_negative) | ||
| 172 | exponent *= -1; | ||
| 173 | |||
| 174 | // Bring the decimal part to the left side of the decimal dot. | ||
| 175 | exponent -= frac_scale * 4; | ||
| 176 | |||
| 177 | if (mantissa == 0) { | ||
| 178 | // Signed zero. | ||
| 179 | return if (negative) -0.0 else 0.0; | ||
| 180 | } | ||
| 181 | |||
| 182 | // Divide by 2^mantissa_bits to right-align the mantissa in the fractional | ||
| 183 | // part. | ||
| 184 | exponent += mantissa_bits; | ||
| 185 | |||
| 186 | // Keep around two extra bits to correctly round any value that doesn't fit | ||
| 187 | // the available mantissa bits. The result LSB serves as Guard bit, the | ||
| 188 | // following one is the Round bit and the last one is the Sticky bit, | ||
| 189 | // computed by OR-ing all the dropped bits. | ||
| 190 | |||
| 191 | // Normalize by aligning the implicit one bit. | ||
| 192 | while (mantissa >> (mantissa_bits + 2) == 0) { | ||
| 193 | mantissa <<= 1; | ||
| 194 | exponent -= 1; | ||
| 195 | } | ||
| 196 | |||
| 197 | // Normalize again by dropping the excess precision. | ||
| 198 | // Note that the discarded bits are folded into the Sticky bit. | ||
| 199 | while (mantissa >> (mantissa_bits + 2 + 1) != 0) { | ||
| 200 | mantissa = mantissa >> 1 | (mantissa & 1); | ||
| 201 | exponent += 1; | ||
| 202 | } | ||
| 203 | |||
| 204 | // Very small numbers can be possibly represented as denormals, reduce the | ||
| 205 | // exponent as much as possible. | ||
| 206 | while (mantissa != 0 and exponent < exponent_min - 2) { | ||
| 207 | mantissa = mantissa >> 1 | (mantissa & 1); | ||
| 208 | exponent += 1; | ||
| 209 | } | ||
| 210 | |||
| 211 | // There are two cases to handle: | ||
| 212 | // - We've truncated more than 0.5ULP (R=S=1), increase the mantissa. | ||
| 213 | // - We've truncated exactly 0.5ULP (R=1 S=0), increase the mantissa if the | ||
| 214 | // result is odd (G=1). | ||
| 215 | // The two checks can be neatly folded as follows. | ||
| 216 | mantissa |= @boolToInt(mantissa & 0b100 != 0); | ||
| 217 | mantissa += 1; | ||
| 218 | |||
| 219 | mantissa >>= 2; | ||
| 220 | exponent += 2; | ||
| 221 | |||
| 222 | if (mantissa & (1 << (mantissa_bits + 1)) != 0) { | ||
| 223 | // Renormalize, if the exponent overflows we'll catch that below. | ||
| 224 | mantissa >>= 1; | ||
| 225 | exponent += 1; | ||
| 226 | } | ||
| 227 | |||
| 228 | if (mantissa >> mantissa_bits == 0) { | ||
| 229 | // This is a denormal number, the biased exponent is zero. | ||
| 230 | exponent = -exponent_bias; | ||
| 231 | } | ||
| 232 | |||
| 233 | if (exponent > exponent_max) { | ||
| 234 | // Overflow, return +inf. | ||
| 235 | return math.inf(T); | ||
| 236 | } | ||
| 237 | |||
| 238 | // Remove the implicit bit. | ||
| 239 | mantissa &= @as(u128, (1 << mantissa_bits) - 1); | ||
| 240 | |||
| 241 | const raw: IntT = | ||
| 242 | (if (negative) @as(IntT, 1) << sign_shift else 0) | | ||
| 243 | @as(IntT, @bitCast(u16, exponent + exponent_bias)) << mantissa_bits | | ||
| 244 | @truncate(IntT, mantissa); | ||
| 245 | |||
| 246 | return @bitCast(T, raw); | ||
| 247 | } | ||
| 248 | |||
| 249 | test "special" { | ||
| 250 | testing.expect(math.isNan(try parseHexFloat(f32, "nAn"))); | ||
| 251 | testing.expect(math.isPositiveInf(try parseHexFloat(f32, "iNf"))); | ||
| 252 | testing.expect(math.isPositiveInf(try parseHexFloat(f32, "+Inf"))); | ||
| 253 | testing.expect(math.isNegativeInf(try parseHexFloat(f32, "-iNf"))); | ||
| 254 | } | ||
| 255 | test "zero" { | ||
| 256 | testing.expectEqual(@as(f32, 0.0), try parseHexFloat(f32, "0x0")); | ||
| 257 | testing.expectEqual(@as(f32, 0.0), try parseHexFloat(f32, "-0x0")); | ||
| 258 | testing.expectEqual(@as(f32, 0.0), try parseHexFloat(f32, "0x0p42")); | ||
| 259 | testing.expectEqual(@as(f32, 0.0), try parseHexFloat(f32, "-0x0.00000p42")); | ||
| 260 | testing.expectEqual(@as(f32, 0.0), try parseHexFloat(f32, "0x0.00000p666")); | ||
| 261 | } | ||
| 262 | |||
| 263 | test "f16" { | ||
| 264 | const Case = struct { s: []const u8, v: f16 }; | ||
| 265 | const cases: []const Case = &[_]Case{ | ||
| 266 | .{ .s = "0x1p0", .v = 1.0 }, | ||
| 267 | .{ .s = "-0x1p-1", .v = -0.5 }, | ||
| 268 | .{ .s = "0x10p+10", .v = 16384.0 }, | ||
| 269 | .{ .s = "0x10p-10", .v = 0.015625 }, | ||
| 270 | // Max normalized value. | ||
| 271 | .{ .s = "0x1.ffcp+15", .v = math.f16_max }, | ||
| 272 | .{ .s = "-0x1.ffcp+15", .v = -math.f16_max }, | ||
| 273 | // Min normalized value. | ||
| 274 | .{ .s = "0x1p-14", .v = math.f16_min }, | ||
| 275 | .{ .s = "-0x1p-14", .v = -math.f16_min }, | ||
| 276 | // Min denormal value. | ||
| 277 | .{ .s = "0x1p-24", .v = math.f16_true_min }, | ||
| 278 | .{ .s = "-0x1p-24", .v = -math.f16_true_min }, | ||
| 279 | }; | ||
| 280 | |||
| 281 | for (cases) |case| { | ||
| 282 | testing.expectEqual(case.v, try parseHexFloat(f16, case.s)); | ||
| 283 | } | ||
| 284 | } | ||
| 285 | test "f32" { | ||
| 286 | const Case = struct { s: []const u8, v: f32 }; | ||
| 287 | const cases: []const Case = &[_]Case{ | ||
| 288 | .{ .s = "0x1p0", .v = 1.0 }, | ||
| 289 | .{ .s = "-0x1p-1", .v = -0.5 }, | ||
| 290 | .{ .s = "0x10p+10", .v = 16384.0 }, | ||
| 291 | .{ .s = "0x10p-10", .v = 0.015625 }, | ||
| 292 | .{ .s = "0x0.ffffffp128", .v = 0x0.ffffffp128 }, | ||
| 293 | .{ .s = "0x0.1234570p-125", .v = 0x0.1234570p-125 }, | ||
| 294 | // Max normalized value. | ||
| 295 | .{ .s = "0x1.fffffeP+127", .v = math.f32_max }, | ||
| 296 | .{ .s = "-0x1.fffffeP+127", .v = -math.f32_max }, | ||
| 297 | // Min normalized value. | ||
| 298 | .{ .s = "0x1p-126", .v = math.f32_min }, | ||
| 299 | .{ .s = "-0x1p-126", .v = -math.f32_min }, | ||
| 300 | // Min denormal value. | ||
| 301 | .{ .s = "0x1P-149", .v = math.f32_true_min }, | ||
| 302 | .{ .s = "-0x1P-149", .v = -math.f32_true_min }, | ||
| 303 | }; | ||
| 304 | |||
| 305 | for (cases) |case| { | ||
| 306 | testing.expectEqual(case.v, try parseHexFloat(f32, case.s)); | ||
| 307 | } | ||
| 308 | } | ||
| 309 | test "f64" { | ||
| 310 | const Case = struct { s: []const u8, v: f64 }; | ||
| 311 | const cases: []const Case = &[_]Case{ | ||
| 312 | .{ .s = "0x1p0", .v = 1.0 }, | ||
| 313 | .{ .s = "-0x1p-1", .v = -0.5 }, | ||
| 314 | .{ .s = "0x10p+10", .v = 16384.0 }, | ||
| 315 | .{ .s = "0x10p-10", .v = 0.015625 }, | ||
| 316 | // Max normalized value. | ||
| 317 | .{ .s = "0x1.fffffffffffffp+1023", .v = math.f64_max }, | ||
| 318 | .{ .s = "-0x1.fffffffffffffp1023", .v = -math.f64_max }, | ||
| 319 | // Min normalized value. | ||
| 320 | .{ .s = "0x1p-1022", .v = math.f64_min }, | ||
| 321 | .{ .s = "-0x1p-1022", .v = -math.f64_min }, | ||
| 322 | // Min denormalized value. | ||
| 323 | .{ .s = "0x1p-1074", .v = math.f64_true_min }, | ||
| 324 | .{ .s = "-0x1p-1074", .v = -math.f64_true_min }, | ||
| 325 | }; | ||
| 326 | |||
| 327 | for (cases) |case| { | ||
| 328 | testing.expectEqual(case.v, try parseHexFloat(f64, case.s)); | ||
| 329 | } | ||
| 330 | } | ||
| 331 | test "f128" { | ||
| 332 | const Case = struct { s: []const u8, v: f128 }; | ||
| 333 | const cases: []const Case = &[_]Case{ | ||
| 334 | .{ .s = "0x1p0", .v = 1.0 }, | ||
| 335 | .{ .s = "-0x1p-1", .v = -0.5 }, | ||
| 336 | .{ .s = "0x10p+10", .v = 16384.0 }, | ||
| 337 | .{ .s = "0x10p-10", .v = 0.015625 }, | ||
| 338 | // Max normalized value. | ||
| 339 | .{ .s = "0xf.fffffffffffffffffffffffffff8p+16380", .v = math.f128_max }, | ||
| 340 | .{ .s = "-0xf.fffffffffffffffffffffffffff8p+16380", .v = -math.f128_max }, | ||
| 341 | // Min normalized value. | ||
| 342 | .{ .s = "0x1p-16382", .v = math.f128_min }, | ||
| 343 | .{ .s = "-0x1p-16382", .v = -math.f128_min }, | ||
| 344 | // // Min denormalized value. | ||
| 345 | .{ .s = "0x1p-16494", .v = math.f128_true_min }, | ||
| 346 | .{ .s = "-0x1p-16494", .v = -math.f128_true_min }, | ||
| 347 | }; | ||
| 348 | |||
| 349 | for (cases) |case| { | ||
| 350 | testing.expectEqual(@bitCast(u128, case.v), @bitCast(u128, try parseHexFloat(f128, case.s))); | ||
| 351 | } | ||
| 352 | } | ||
lib/std/json/test.zig+2-4| ... | @@ -29,8 +29,7 @@ fn ok(s: []const u8) !void { | ... | @@ -29,8 +29,7 @@ fn ok(s: []const u8) !void { |
| 29 | fn err(s: []const u8) void { | 29 | fn err(s: []const u8) void { |
| 30 | testing.expect(!json.validate(s)); | 30 | testing.expect(!json.validate(s)); |
| 31 | 31 | ||
| 32 | testNonStreaming(s) catch return; | 32 | testing.expect(std.meta.isError(testNonStreaming(s))); |
| 33 | testing.expect(false); | ||
| 34 | } | 33 | } |
| 35 | 34 | ||
| 36 | fn utf8Error(s: []const u8) void { | 35 | fn utf8Error(s: []const u8) void { |
| ... | @@ -48,8 +47,7 @@ fn any(s: []const u8) void { | ... | @@ -48,8 +47,7 @@ fn any(s: []const u8) void { |
| 48 | fn anyStreamingErrNonStreaming(s: []const u8) void { | 47 | fn anyStreamingErrNonStreaming(s: []const u8) void { |
| 49 | _ = json.validate(s); | 48 | _ = json.validate(s); |
| 50 | 49 | ||
| 51 | testNonStreaming(s) catch return; | 50 | testing.expect(std.meta.isError(testNonStreaming(s))); |
| 52 | testing.expect(false); | ||
| 53 | } | 51 | } |
| 54 | 52 | ||
| 55 | fn roundTrip(s: []const u8) !void { | 53 | fn roundTrip(s: []const u8) !void { |
lib/std/mem.zig+40-4| ... | @@ -1877,7 +1877,11 @@ test "rotate" { | ... | @@ -1877,7 +1877,11 @@ test "rotate" { |
| 1877 | 1877 | ||
| 1878 | /// Replace needle with replacement as many times as possible, writing to an output buffer which is assumed to be of | 1878 | /// Replace needle with replacement as many times as possible, writing to an output buffer which is assumed to be of |
| 1879 | /// appropriate size. Use replacementSize to calculate an appropriate buffer size. | 1879 | /// appropriate size. Use replacementSize to calculate an appropriate buffer size. |
| 1880 | /// The needle must not be empty. | ||
| 1880 | pub fn replace(comptime T: type, input: []const T, needle: []const T, replacement: []const T, output: []T) usize { | 1881 | pub fn replace(comptime T: type, input: []const T, needle: []const T, replacement: []const T, output: []T) usize { |
| 1882 | // Empty needle will loop until output buffer overflows. | ||
| 1883 | assert(needle.len > 0); | ||
| 1884 | |||
| 1881 | var i: usize = 0; | 1885 | var i: usize = 0; |
| 1882 | var slide: usize = 0; | 1886 | var slide: usize = 0; |
| 1883 | var replacements: usize = 0; | 1887 | var replacements: usize = 0; |
| ... | @@ -1900,22 +1904,48 @@ pub fn replace(comptime T: type, input: []const T, needle: []const T, replacemen | ... | @@ -1900,22 +1904,48 @@ pub fn replace(comptime T: type, input: []const T, needle: []const T, replacemen |
| 1900 | test "replace" { | 1904 | test "replace" { |
| 1901 | var output: [29]u8 = undefined; | 1905 | var output: [29]u8 = undefined; |
| 1902 | var replacements = replace(u8, "All your base are belong to us", "base", "Zig", output[0..]); | 1906 | var replacements = replace(u8, "All your base are belong to us", "base", "Zig", output[0..]); |
| 1907 | var expected: []const u8 = "All your Zig are belong to us"; | ||
| 1903 | testing.expect(replacements == 1); | 1908 | testing.expect(replacements == 1); |
| 1904 | testing.expect(eql(u8, output[0..], "All your Zig are belong to us")); | 1909 | testing.expectEqualStrings(expected, output[0..expected.len]); |
| 1905 | 1910 | ||
| 1906 | replacements = replace(u8, "Favor reading code over writing code.", "code", "", output[0..]); | 1911 | replacements = replace(u8, "Favor reading code over writing code.", "code", "", output[0..]); |
| 1912 | expected = "Favor reading over writing ."; | ||
| 1907 | testing.expect(replacements == 2); | 1913 | testing.expect(replacements == 2); |
| 1908 | testing.expect(eql(u8, output[0..], "Favor reading over writing .")); | 1914 | testing.expectEqualStrings(expected, output[0..expected.len]); |
| 1915 | |||
| 1916 | // Empty needle is not allowed but input may be empty. | ||
| 1917 | replacements = replace(u8, "", "x", "y", output[0..0]); | ||
| 1918 | expected = ""; | ||
| 1919 | testing.expect(replacements == 0); | ||
| 1920 | testing.expectEqualStrings(expected, output[0..expected.len]); | ||
| 1921 | |||
| 1922 | // Adjacent replacements. | ||
| 1923 | |||
| 1924 | replacements = replace(u8, "\\n\\n", "\\n", "\n", output[0..]); | ||
| 1925 | expected = "\n\n"; | ||
| 1926 | testing.expect(replacements == 2); | ||
| 1927 | testing.expectEqualStrings(expected, output[0..expected.len]); | ||
| 1928 | |||
| 1929 | replacements = replace(u8, "abbba", "b", "cd", output[0..]); | ||
| 1930 | expected = "acdcdcda"; | ||
| 1931 | testing.expect(replacements == 3); | ||
| 1932 | testing.expectEqualStrings(expected, output[0..expected.len]); | ||
| 1909 | } | 1933 | } |
| 1910 | 1934 | ||
| 1911 | /// Calculate the size needed in an output buffer to perform a replacement. | 1935 | /// Calculate the size needed in an output buffer to perform a replacement. |
| 1936 | /// The needle must not be empty. | ||
| 1912 | pub fn replacementSize(comptime T: type, input: []const T, needle: []const T, replacement: []const T) usize { | 1937 | pub fn replacementSize(comptime T: type, input: []const T, needle: []const T, replacement: []const T) usize { |
| 1938 | // Empty needle will loop forever. | ||
| 1939 | assert(needle.len > 0); | ||
| 1940 | |||
| 1913 | var i: usize = 0; | 1941 | var i: usize = 0; |
| 1914 | var size: usize = input.len; | 1942 | var size: usize = input.len; |
| 1915 | while (i < input.len) : (i += 1) { | 1943 | while (i < input.len) { |
| 1916 | if (mem.indexOf(T, input[i..], needle) == @as(usize, 0)) { | 1944 | if (mem.indexOf(T, input[i..], needle) == @as(usize, 0)) { |
| 1917 | size = size - needle.len + replacement.len; | 1945 | size = size - needle.len + replacement.len; |
| 1918 | i += needle.len; | 1946 | i += needle.len; |
| 1947 | } else { | ||
| 1948 | i += 1; | ||
| 1919 | } | 1949 | } |
| 1920 | } | 1950 | } |
| 1921 | 1951 | ||
| ... | @@ -1924,9 +1954,15 @@ pub fn replacementSize(comptime T: type, input: []const T, needle: []const T, re | ... | @@ -1924,9 +1954,15 @@ pub fn replacementSize(comptime T: type, input: []const T, needle: []const T, re |
| 1924 | 1954 | ||
| 1925 | test "replacementSize" { | 1955 | test "replacementSize" { |
| 1926 | testing.expect(replacementSize(u8, "All your base are belong to us", "base", "Zig") == 29); | 1956 | testing.expect(replacementSize(u8, "All your base are belong to us", "base", "Zig") == 29); |
| 1927 | testing.expect(replacementSize(u8, "", "", "") == 0); | ||
| 1928 | testing.expect(replacementSize(u8, "Favor reading code over writing code.", "code", "") == 29); | 1957 | testing.expect(replacementSize(u8, "Favor reading code over writing code.", "code", "") == 29); |
| 1929 | testing.expect(replacementSize(u8, "Only one obvious way to do things.", "things.", "things in Zig.") == 41); | 1958 | testing.expect(replacementSize(u8, "Only one obvious way to do things.", "things.", "things in Zig.") == 41); |
| 1959 | |||
| 1960 | // Empty needle is not allowed but input may be empty. | ||
| 1961 | testing.expect(replacementSize(u8, "", "x", "y") == 0); | ||
| 1962 | |||
| 1963 | // Adjacent replacements. | ||
| 1964 | testing.expect(replacementSize(u8, "\\n\\n", "\\n", "\n") == 2); | ||
| 1965 | testing.expect(replacementSize(u8, "abbba", "b", "cd") == 8); | ||
| 1930 | } | 1966 | } |
| 1931 | 1967 | ||
| 1932 | /// Perform a replacement on an allocated buffer of pre-determined size. Caller must free returned memory. | 1968 | /// Perform a replacement on an allocated buffer of pre-determined size. Caller must free returned memory. |
lib/std/meta.zig+26-3| ... | @@ -117,10 +117,21 @@ test "std.meta.bitCount" { | ... | @@ -117,10 +117,21 @@ test "std.meta.bitCount" { |
| 117 | testing.expect(bitCount(f32) == 32); | 117 | testing.expect(bitCount(f32) == 32); |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | /// Returns the alignment of type T. | ||
| 121 | /// Note that if T is a pointer or function type the result is different than | ||
| 122 | /// the one returned by @alignOf(T). | ||
| 123 | /// If T is a pointer type the alignment of the type it points to is returned. | ||
| 124 | /// If T is a function type the alignment a target-dependent value is returned. | ||
| 120 | pub fn alignment(comptime T: type) comptime_int { | 125 | pub fn alignment(comptime T: type) comptime_int { |
| 121 | //@alignOf works on non-pointer types | 126 | return switch (@typeInfo(T)) { |
| 122 | const P = if (comptime trait.is(.Pointer)(T)) T else *T; | 127 | .Optional => |info| switch (@typeInfo(info.child)) { |
| 123 | return @typeInfo(P).Pointer.alignment; | 128 | .Pointer, .Fn => alignment(info.child), |
| 129 | else => @alignOf(T), | ||
| 130 | }, | ||
| 131 | .Pointer => |info| info.alignment, | ||
| 132 | .Fn => |info| info.alignment, | ||
| 133 | else => @alignOf(T), | ||
| 134 | }; | ||
| 124 | } | 135 | } |
| 125 | 136 | ||
| 126 | test "std.meta.alignment" { | 137 | test "std.meta.alignment" { |
| ... | @@ -129,6 +140,8 @@ test "std.meta.alignment" { | ... | @@ -129,6 +140,8 @@ test "std.meta.alignment" { |
| 129 | testing.expect(alignment(*align(2) u8) == 2); | 140 | testing.expect(alignment(*align(2) u8) == 2); |
| 130 | testing.expect(alignment([]align(1) u8) == 1); | 141 | testing.expect(alignment([]align(1) u8) == 1); |
| 131 | testing.expect(alignment([]align(2) u8) == 2); | 142 | testing.expect(alignment([]align(2) u8) == 2); |
| 143 | testing.expect(alignment(fn () void) > 0); | ||
| 144 | testing.expect(alignment(fn () align(128) void) == 128); | ||
| 132 | } | 145 | } |
| 133 | 146 | ||
| 134 | pub fn Child(comptime T: type) type { | 147 | pub fn Child(comptime T: type) type { |
| ... | @@ -1342,3 +1355,13 @@ test "shuffleVectorIndex" { | ... | @@ -1342,3 +1355,13 @@ test "shuffleVectorIndex" { |
| 1342 | testing.expect(shuffleVectorIndex(6, vector_len) == -3); | 1355 | testing.expect(shuffleVectorIndex(6, vector_len) == -3); |
| 1343 | testing.expect(shuffleVectorIndex(7, vector_len) == -4); | 1356 | testing.expect(shuffleVectorIndex(7, vector_len) == -4); |
| 1344 | } | 1357 | } |
| 1358 | |||
| 1359 | /// Returns whether `error_union` contains an error. | ||
| 1360 | pub fn isError(error_union: anytype) bool { | ||
| 1361 | return if (error_union) |_| false else |_| true; | ||
| 1362 | } | ||
| 1363 | |||
| 1364 | test "isError" { | ||
| 1365 | std.testing.expect(isError(math.absInt(@as(i8, -128)))); | ||
| 1366 | std.testing.expect(!isError(math.absInt(@as(i8, -127)))); | ||
| 1367 | } |
lib/std/os/bits/haiku.zig+128-206| ... | @@ -279,20 +279,10 @@ pub const PROT_READ = 1; | ... | @@ -279,20 +279,10 @@ pub const PROT_READ = 1; |
| 279 | pub const PROT_WRITE = 2; | 279 | pub const PROT_WRITE = 2; |
| 280 | pub const PROT_EXEC = 4; | 280 | pub const PROT_EXEC = 4; |
| 281 | 281 | ||
| 282 | pub const CLOCK_REALTIME = 0; | 282 | pub const CLOCK_MONOTONIC = 0; |
| 283 | pub const CLOCK_VIRTUAL = 1; | 283 | pub const CLOCK_REALTIME = -1; |
| 284 | pub const CLOCK_PROF = 2; | 284 | pub const CLOCK_PROCESS_CPUTIME_ID = -2; |
| 285 | pub const CLOCK_MONOTONIC = 4; | 285 | pub const CLOCK_THREAD_CPUTIME_ID = -3; |
| 286 | pub const CLOCK_UPTIME = 5; | ||
| 287 | pub const CLOCK_UPTIME_PRECISE = 7; | ||
| 288 | pub const CLOCK_UPTIME_FAST = 8; | ||
| 289 | pub const CLOCK_REALTIME_PRECISE = 9; | ||
| 290 | pub const CLOCK_REALTIME_FAST = 10; | ||
| 291 | pub const CLOCK_MONOTONIC_PRECISE = 11; | ||
| 292 | pub const CLOCK_MONOTONIC_FAST = 12; | ||
| 293 | pub const CLOCK_SECOND = 13; | ||
| 294 | pub const CLOCK_THREAD_CPUTIME_ID = 14; | ||
| 295 | pub const CLOCK_PROCESS_CPUTIME_ID = 15; | ||
| 296 | 286 | ||
| 297 | pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize)); | 287 | pub const MAP_FAILED = @intToPtr(*c_void, maxInt(usize)); |
| 298 | pub const MAP_SHARED = 0x0001; | 288 | pub const MAP_SHARED = 0x0001; |
| ... | @@ -310,58 +300,59 @@ pub const MAP_NOCORE = 0x00020000; | ... | @@ -310,58 +300,59 @@ pub const MAP_NOCORE = 0x00020000; |
| 310 | pub const MAP_PREFAULT_READ = 0x00040000; | 300 | pub const MAP_PREFAULT_READ = 0x00040000; |
| 311 | pub const MAP_32BIT = 0x00080000; | 301 | pub const MAP_32BIT = 0x00080000; |
| 312 | 302 | ||
| 313 | pub const WNOHANG = 1; | 303 | pub const WNOHANG = 0x1; |
| 314 | pub const WUNTRACED = 2; | 304 | pub const WUNTRACED = 0x2; |
| 315 | pub const WSTOPPED = WUNTRACED; | 305 | pub const WSTOPPED = 0x10; |
| 316 | pub const WCONTINUED = 4; | 306 | pub const WCONTINUED = 0x4; |
| 317 | pub const WNOWAIT = 8; | 307 | pub const WNOWAIT = 0x20; |
| 318 | pub const WEXITED = 16; | 308 | pub const WEXITED = 0x08; |
| 319 | pub const WTRAPPED = 32; | 309 | |
| 320 | 310 | pub const SA_ONSTACK = 0x20; | |
| 321 | pub const SA_ONSTACK = 0x0001; | 311 | pub const SA_RESTART = 0x10; |
| 322 | pub const SA_RESTART = 0x0002; | 312 | pub const SA_RESETHAND = 0x04; |
| 323 | pub const SA_RESETHAND = 0x0004; | 313 | pub const SA_NOCLDSTOP = 0x01; |
| 324 | pub const SA_NOCLDSTOP = 0x0008; | 314 | pub const SA_NODEFER = 0x08; |
| 325 | pub const SA_NODEFER = 0x0010; | 315 | pub const SA_NOCLDWAIT = 0x02; |
| 326 | pub const SA_NOCLDWAIT = 0x0020; | 316 | pub const SA_SIGINFO = 0x40; |
| 327 | pub const SA_SIGINFO = 0x0040; | 317 | pub const SA_NOMASK = SA_NODEFER; |
| 318 | pub const SA_STACK = SA_ONSTACK; | ||
| 319 | pub const SA_ONESHOT = SA_RESETHAND; | ||
| 328 | 320 | ||
| 329 | pub const SIGHUP = 1; | 321 | pub const SIGHUP = 1; |
| 330 | pub const SIGINT = 2; | 322 | pub const SIGINT = 2; |
| 331 | pub const SIGQUIT = 3; | 323 | pub const SIGQUIT = 3; |
| 332 | pub const SIGILL = 4; | 324 | pub const SIGILL = 4; |
| 333 | pub const SIGTRAP = 5; | 325 | pub const SIGCHLD = 5; |
| 334 | pub const SIGABRT = 6; | 326 | pub const SIGABRT = 6; |
| 335 | pub const SIGIOT = SIGABRT; | 327 | pub const SIGIOT = SIGABRT; |
| 336 | pub const SIGEMT = 7; | 328 | pub const SIGPIPE = 7; |
| 337 | pub const SIGFPE = 8; | 329 | pub const SIGFPE = 8; |
| 338 | pub const SIGKILL = 9; | 330 | pub const SIGKILL = 9; |
| 339 | pub const SIGBUS = 10; | 331 | pub const SIGSTOP = 10; |
| 340 | pub const SIGSEGV = 11; | 332 | pub const SIGSEGV = 11; |
| 341 | pub const SIGSYS = 12; | 333 | pub const SIGCONT = 12; |
| 342 | pub const SIGPIPE = 13; | 334 | pub const SIGTSTP = 13; |
| 343 | pub const SIGALRM = 14; | 335 | pub const SIGALRM = 14; |
| 344 | pub const SIGTERM = 15; | 336 | pub const SIGTERM = 15; |
| 345 | pub const SIGURG = 16; | 337 | pub const SIGTTIN = 16; |
| 346 | pub const SIGSTOP = 17; | 338 | pub const SIGTTOU = 17; |
| 347 | pub const SIGTSTP = 18; | 339 | pub const SIGUSR1 = 18; |
| 348 | pub const SIGCONT = 19; | 340 | pub const SIGUSR2 = 19; |
| 349 | pub const SIGCHLD = 20; | 341 | pub const SIGWINCH = 20; |
| 350 | pub const SIGTTIN = 21; | 342 | pub const SIGKILLTHR = 21; |
| 351 | pub const SIGTTOU = 22; | 343 | pub const SIGTRAP = 22; |
| 352 | pub const SIGIO = 23; | 344 | pub const SIGPOLL = 23; |
| 353 | pub const SIGXCPU = 24; | 345 | pub const SIGPROF = 24; |
| 354 | pub const SIGXFSZ = 25; | 346 | pub const SIGSYS = 25; |
| 355 | pub const SIGVTALRM = 26; | 347 | pub const SIGURG = 26; |
| 356 | pub const SIGPROF = 27; | 348 | pub const SIGVTALRM = 27; |
| 357 | pub const SIGWINCH = 28; | 349 | pub const SIGXCPU = 28; |
| 358 | pub const SIGINFO = 29; | 350 | pub const SIGXFSZ = 29; |
| 359 | pub const SIGUSR1 = 30; | 351 | pub const SIGBUS = 30; |
| 360 | pub const SIGUSR2 = 31; | 352 | pub const SIGRESERVED1 = 31; |
| 361 | pub const SIGTHR = 32; | 353 | pub const SIGRESERVED2 = 32; |
| 362 | pub const SIGLWP = SIGTHR; | 354 | |
| 363 | pub const SIGLIBRT = 33; | 355 | // TODO: check |
| 364 | |||
| 365 | pub const SIGRTMIN = 65; | 356 | pub const SIGRTMIN = 65; |
| 366 | pub const SIGRTMAX = 126; | 357 | pub const SIGRTMAX = 126; |
| 367 | 358 | ||
| ... | @@ -645,135 +636,51 @@ pub const EVFILT_SENDFILE = -12; | ... | @@ -645,135 +636,51 @@ pub const EVFILT_SENDFILE = -12; |
| 645 | 636 | ||
| 646 | pub const EVFILT_EMPTY = -13; | 637 | pub const EVFILT_EMPTY = -13; |
| 647 | 638 | ||
| 648 | /// On input, NOTE_TRIGGER causes the event to be triggered for output. | 639 | pub const TCGETA = 0x8000; |
| 649 | pub const NOTE_TRIGGER = 0x01000000; | 640 | pub const TCSETA = 0x8001; |
| 650 | 641 | pub const TCSETAW = 0x8004; | |
| 651 | /// ignore input fflags | 642 | pub const TCSETAF = 0x8003; |
| 652 | pub const NOTE_FFNOP = 0x00000000; | 643 | pub const TCSBRK = 08005; |
| 653 | 644 | pub const TCXONC = 0x8007; | |
| 654 | /// and fflags | 645 | pub const TCFLSH = 0x8006; |
| 655 | pub const NOTE_FFAND = 0x40000000; | 646 | |
| 656 | 647 | pub const TIOCSCTTY = 0x8017; | |
| 657 | /// or fflags | 648 | pub const TIOCGPGRP = 0x8015; |
| 658 | pub const NOTE_FFOR = 0x80000000; | 649 | pub const TIOCSPGRP = 0x8016; |
| 659 | 650 | pub const TIOCGWINSZ = 0x8012; | |
| 660 | /// copy fflags | 651 | pub const TIOCSWINSZ = 0x8013; |
| 661 | pub const NOTE_FFCOPY = 0xc0000000; | 652 | pub const TIOCMGET = 0x8018; |
| 662 | 653 | pub const TIOCMBIS = 0x8022; | |
| 663 | /// mask for operations | 654 | pub const TIOCMBIC = 0x8023; |
| 664 | pub const NOTE_FFCTRLMASK = 0xc0000000; | 655 | pub const TIOCMSET = 0x8019; |
| 665 | pub const NOTE_FFLAGSMASK = 0x00ffffff; | 656 | pub const FIONREAD = 0xbe000001; |
| 666 | 657 | pub const FIONBIO = 0xbe000000; | |
| 667 | /// low water mark | 658 | pub const TIOCSBRK = 0x8020; |
| 668 | pub const NOTE_LOWAT = 0x00000001; | 659 | pub const TIOCCBRK = 0x8021; |
| 669 | 660 | pub const TIOCGSID = 0x8024; | |
| 670 | /// behave like poll() | ||
| 671 | pub const NOTE_FILE_POLL = 0x00000002; | ||
| 672 | |||
| 673 | /// vnode was removed | ||
| 674 | pub const NOTE_DELETE = 0x00000001; | ||
| 675 | |||
| 676 | /// data contents changed | ||
| 677 | pub const NOTE_WRITE = 0x00000002; | ||
| 678 | |||
| 679 | /// size increased | ||
| 680 | pub const NOTE_EXTEND = 0x00000004; | ||
| 681 | |||
| 682 | /// attributes changed | ||
| 683 | pub const NOTE_ATTRIB = 0x00000008; | ||
| 684 | |||
| 685 | /// link count changed | ||
| 686 | pub const NOTE_LINK = 0x00000010; | ||
| 687 | |||
| 688 | /// vnode was renamed | ||
| 689 | pub const NOTE_RENAME = 0x00000020; | ||
| 690 | |||
| 691 | /// vnode access was revoked | ||
| 692 | pub const NOTE_REVOKE = 0x00000040; | ||
| 693 | |||
| 694 | /// vnode was opened | ||
| 695 | pub const NOTE_OPEN = 0x00000080; | ||
| 696 | |||
| 697 | /// file closed, fd did not allow write | ||
| 698 | pub const NOTE_CLOSE = 0x00000100; | ||
| 699 | |||
| 700 | /// file closed, fd did allow write | ||
| 701 | pub const NOTE_CLOSE_WRITE = 0x00000200; | ||
| 702 | |||
| 703 | /// file was read | ||
| 704 | pub const NOTE_READ = 0x00000400; | ||
| 705 | |||
| 706 | /// process exited | ||
| 707 | pub const NOTE_EXIT = 0x80000000; | ||
| 708 | |||
| 709 | /// process forked | ||
| 710 | pub const NOTE_FORK = 0x40000000; | ||
| 711 | |||
| 712 | /// process exec'd | ||
| 713 | pub const NOTE_EXEC = 0x20000000; | ||
| 714 | |||
| 715 | /// mask for signal & exit status | ||
| 716 | pub const NOTE_PDATAMASK = 0x000fffff; | ||
| 717 | pub const NOTE_PCTRLMASK = (~NOTE_PDATAMASK); | ||
| 718 | |||
| 719 | /// data is seconds | ||
| 720 | pub const NOTE_SECONDS = 0x00000001; | ||
| 721 | |||
| 722 | /// data is milliseconds | ||
| 723 | pub const NOTE_MSECONDS = 0x00000002; | ||
| 724 | |||
| 725 | /// data is microseconds | ||
| 726 | pub const NOTE_USECONDS = 0x00000004; | ||
| 727 | |||
| 728 | /// data is nanoseconds | ||
| 729 | pub const NOTE_NSECONDS = 0x00000008; | ||
| 730 | |||
| 731 | /// timeout is absolute | ||
| 732 | pub const NOTE_ABSTIME = 0x00000010; | ||
| 733 | |||
| 734 | pub const TIOCEXCL = 0x2000740d; | ||
| 735 | pub const TIOCNXCL = 0x2000740e; | ||
| 736 | pub const TIOCSCTTY = 0x20007461; | ||
| 737 | pub const TIOCGPGRP = 0x40047477; | ||
| 738 | pub const TIOCSPGRP = 0x80047476; | ||
| 739 | pub const TIOCOUTQ = 0x40047473; | ||
| 740 | pub const TIOCSTI = 0x80017472; | ||
| 741 | pub const TIOCGWINSZ = 0x40087468; | ||
| 742 | pub const TIOCSWINSZ = 0x80087467; | ||
| 743 | pub const TIOCMGET = 0x4004746a; | ||
| 744 | pub const TIOCMBIS = 0x8004746c; | ||
| 745 | pub const TIOCMBIC = 0x8004746b; | ||
| 746 | pub const TIOCMSET = 0x8004746d; | ||
| 747 | pub const FIONREAD = 0x4004667f; | ||
| 748 | pub const TIOCCONS = 0x80047462; | ||
| 749 | pub const TIOCPKT = 0x80047470; | ||
| 750 | pub const FIONBIO = 0x8004667e; | ||
| 751 | pub const TIOCNOTTY = 0x20007471; | ||
| 752 | pub const TIOCSETD = 0x8004741b; | ||
| 753 | pub const TIOCGETD = 0x4004741a; | ||
| 754 | pub const TIOCSBRK = 0x2000747b; | ||
| 755 | pub const TIOCCBRK = 0x2000747a; | ||
| 756 | pub const TIOCGSID = 0x40047463; | ||
| 757 | pub const TIOCGPTN = 0x4004740f; | ||
| 758 | pub const TIOCSIG = 0x2004745f; | ||
| 759 | 661 | ||
| 760 | pub fn WEXITSTATUS(s: u32) u32 { | 662 | pub fn WEXITSTATUS(s: u32) u32 { |
| 761 | return (s & 0xff00) >> 8; | 663 | return (s & 0xff); |
| 762 | } | 664 | } |
| 665 | |||
| 763 | pub fn WTERMSIG(s: u32) u32 { | 666 | pub fn WTERMSIG(s: u32) u32 { |
| 764 | return s & 0x7f; | 667 | return (s >> 8) & 0xff; |
| 765 | } | 668 | } |
| 669 | |||
| 766 | pub fn WSTOPSIG(s: u32) u32 { | 670 | pub fn WSTOPSIG(s: u32) u32 { |
| 767 | return WEXITSTATUS(s); | 671 | return WEXITSTATUS(s); |
| 768 | } | 672 | } |
| 673 | |||
| 769 | pub fn WIFEXITED(s: u32) bool { | 674 | pub fn WIFEXITED(s: u32) bool { |
| 770 | return WTERMSIG(s) == 0; | 675 | return WTERMSIG(s) == 0; |
| 771 | } | 676 | } |
| 677 | |||
| 772 | pub fn WIFSTOPPED(s: u32) bool { | 678 | pub fn WIFSTOPPED(s: u32) bool { |
| 773 | return @intCast(u16, (((s & 0xffff) *% 0x10001) >> 8)) > 0x7f00; | 679 | return ((s >> 16) & 0xff) != 0; |
| 774 | } | 680 | } |
| 681 | |||
| 775 | pub fn WIFSIGNALED(s: u32) bool { | 682 | pub fn WIFSIGNALED(s: u32) bool { |
| 776 | return (s & 0xffff) -% 1 < 0xff; | 683 | return ((s >> 8) & 0xff) != 0; |
| 777 | } | 684 | } |
| 778 | 685 | ||
| 779 | pub const winsize = extern struct { | 686 | pub const winsize = extern struct { |
| ... | @@ -823,49 +730,47 @@ pub const sigset_t = extern struct { | ... | @@ -823,49 +730,47 @@ pub const sigset_t = extern struct { |
| 823 | __bits: [_SIG_WORDS]u32, | 730 | __bits: [_SIG_WORDS]u32, |
| 824 | }; | 731 | }; |
| 825 | 732 | ||
| 826 | pub const EPERM = 1; // Operation not permitted | 733 | pub const EPERM = -0x7ffffff1; // Operation not permitted |
| 827 | pub const ENOENT = 2; // No such file or directory | 734 | pub const ENOENT = -0x7fff9ffd; // No such file or directory |
| 828 | pub const ESRCH = 3; // No such process | 735 | pub const ESRCH = -0x7fff8ff3; // No such process |
| 829 | pub const EINTR = 4; // Interrupted system call | 736 | pub const EINTR = -0x7ffffff6; // Interrupted system call |
| 830 | pub const EIO = 5; // Input/output error | 737 | pub const EIO = -0x7fffffff; // Input/output error |
| 831 | pub const ENXIO = 6; // Device not configured | 738 | pub const ENXIO = -0x7fff8ff5; // Device not configured |
| 832 | pub const E2BIG = 7; // Argument list too long | 739 | pub const E2BIG = -0x7fff8fff; // Argument list too long |
| 833 | pub const ENOEXEC = 8; // Exec format error | 740 | pub const ENOEXEC = -0x7fffecfe; // Exec format error |
| 834 | pub const EBADF = 9; // Bad file descriptor | 741 | pub const ECHILD = -0x7fff8ffe; // No child processes |
| 835 | pub const ECHILD = 10; // No child processes | 742 | pub const EDEADLK = -0x7fff8ffd; // Resource deadlock avoided |
| 836 | pub const EDEADLK = 11; // Resource deadlock avoided | 743 | pub const ENOMEM = -0x80000000; // Cannot allocate memory |
| 837 | // 11 was EAGAIN | 744 | pub const EACCES = -0x7ffffffe; // Permission denied |
| 838 | pub const ENOMEM = 12; // Cannot allocate memory | 745 | pub const EFAULT = -0x7fffecff; // Bad address |
| 839 | pub const EACCES = 13; // Permission denied | 746 | pub const EBUSY = -0x7ffffff2; // Device busy |
| 840 | pub const EFAULT = 14; // Bad address | 747 | pub const EEXIST = -0x7fff9ffe; // File exists |
| 841 | pub const ENOTBLK = 15; // Block device required | 748 | pub const EXDEV = -0x7fff9ff5; // Cross-device link |
| 842 | pub const EBUSY = 16; // Device busy | 749 | pub const ENODEV = -0x7fff8ff9; // Operation not supported by device |
| 843 | pub const EEXIST = 17; // File exists | 750 | pub const ENOTDIR = -0x7fff9ffb; // Not a directory |
| 844 | pub const EXDEV = 18; // Cross-device link | 751 | pub const EISDIR = -0x7fff9ff7; // Is a directory |
| 845 | pub const ENODEV = 19; // Operation not supported by device | 752 | pub const EINVAL = -0x7ffffffb; // Invalid argument |
| 846 | pub const ENOTDIR = 20; // Not a directory | 753 | pub const ENFILE = -0x7fff8ffa; // Too many open files in system |
| 847 | pub const EISDIR = 21; // Is a directory | 754 | pub const EMFILE = -0x7fff9ff6; // Too many open files |
| 848 | pub const EINVAL = 22; // Invalid argument | 755 | pub const ENOTTY = -0x7fff8ff6; // Inappropriate ioctl for device |
| 849 | pub const ENFILE = 23; // Too many open files in system | 756 | pub const ETXTBSY = -0x7fff8fc5; // Text file busy |
| 850 | pub const EMFILE = 24; // Too many open files | 757 | pub const EFBIG = -0x7fff8ffc; // File too large |
| 851 | pub const ENOTTY = 25; // Inappropriate ioctl for device | 758 | pub const ENOSPC = -0x7fff9ff9; // No space left on device |
| 852 | pub const ETXTBSY = 26; // Text file busy | 759 | pub const ESPIPE = -0x7fff8ff4; // Illegal seek |
| 853 | pub const EFBIG = 27; // File too large | 760 | pub const EROFS = -0x7fff9ff8; // Read-only filesystem |
| 854 | pub const ENOSPC = 28; // No space left on device | 761 | pub const EMLINK = -0x7fff8ffb; // Too many links |
| 855 | pub const ESPIPE = 29; // Illegal seek | 762 | pub const EPIPE = -0x7fff9ff3; // Broken pipe |
| 856 | pub const EROFS = 30; // Read-only filesystem | 763 | pub const EBADF = -0x7fffa000; // Bad file descriptor |
| 857 | pub const EMLINK = 31; // Too many links | ||
| 858 | pub const EPIPE = 32; // Broken pipe | ||
| 859 | 764 | ||
| 860 | // math software | 765 | // math software |
| 861 | pub const EDOM = 33; // Numerical argument out of domain | 766 | pub const EDOM = 33; // Numerical argument out of domain |
| 862 | pub const ERANGE = 34; // Result too large | 767 | pub const ERANGE = 34; // Result too large |
| 863 | 768 | ||
| 864 | // non-blocking and interrupt i/o | 769 | // non-blocking and interrupt i/o |
| 865 | pub const EAGAIN = 35; // Resource temporarily unavailable | 770 | pub const EAGAIN = -0x7ffffff5; |
| 866 | pub const EWOULDBLOCK = EAGAIN; // Operation would block | 771 | pub const EWOULDBLOCK = -0x7ffffff5; |
| 867 | pub const EINPROGRESS = 36; // Operation now in progress | 772 | pub const EINPROGRESS = -0x7fff8fdc; |
| 868 | pub const EALREADY = 37; // Operation already in progress | 773 | pub const EALREADY = -0x7fff8fdb; |
| 869 | 774 | ||
| 870 | // ipc/network software -- argument errors | 775 | // ipc/network software -- argument errors |
| 871 | pub const ENOTSOCK = 38; // Socket operation on non-socket | 776 | pub const ENOTSOCK = 38; // Socket operation on non-socket |
| ... | @@ -1447,3 +1352,20 @@ pub const directory_which = enum(c_int) { | ... | @@ -1447,3 +1352,20 @@ pub const directory_which = enum(c_int) { |
| 1447 | 1352 | ||
| 1448 | _, | 1353 | _, |
| 1449 | }; | 1354 | }; |
| 1355 | |||
| 1356 | pub const cc_t = u8; | ||
| 1357 | pub const speed_t = u8; | ||
| 1358 | pub const tcflag_t = u32; | ||
| 1359 | |||
| 1360 | pub const NCCS = 32; | ||
| 1361 | |||
| 1362 | pub const termios = extern struct { | ||
| 1363 | c_iflag: tcflag_t, | ||
| 1364 | c_oflag: tcflag_t, | ||
| 1365 | c_cflag: tcflag_t, | ||
| 1366 | c_lflag: tcflag_t, | ||
| 1367 | c_line: cc_t, | ||
| 1368 | c_ispeed: speed_t, | ||
| 1369 | c_ospeed: speed_t, | ||
| 1370 | cc_t: [NCCS]cc_t, | ||
| 1371 | }; |
lib/std/os/linux/tls.zig+2-2| ... | @@ -248,7 +248,7 @@ fn initTLS() void { | ... | @@ -248,7 +248,7 @@ fn initTLS() void { |
| 248 | tls_data = @intToPtr([*]u8, img_base + phdr.p_vaddr)[0..phdr.p_filesz]; | 248 | tls_data = @intToPtr([*]u8, img_base + phdr.p_vaddr)[0..phdr.p_filesz]; |
| 249 | tls_data_alloc_size = phdr.p_memsz; | 249 | tls_data_alloc_size = phdr.p_memsz; |
| 250 | } else { | 250 | } else { |
| 251 | tls_align_factor = @alignOf(*usize); | 251 | tls_align_factor = @alignOf(usize); |
| 252 | tls_data = &[_]u8{}; | 252 | tls_data = &[_]u8{}; |
| 253 | tls_data_alloc_size = 0; | 253 | tls_data_alloc_size = 0; |
| 254 | } | 254 | } |
| ... | @@ -308,7 +308,7 @@ fn initTLS() void { | ... | @@ -308,7 +308,7 @@ fn initTLS() void { |
| 308 | } | 308 | } |
| 309 | 309 | ||
| 310 | fn alignPtrCast(comptime T: type, ptr: [*]u8) callconv(.Inline) *T { | 310 | fn alignPtrCast(comptime T: type, ptr: [*]u8) callconv(.Inline) *T { |
| 311 | return @ptrCast(*T, @alignCast(@alignOf(*T), ptr)); | 311 | return @ptrCast(*T, @alignCast(@alignOf(T), ptr)); |
| 312 | } | 312 | } |
| 313 | 313 | ||
| 314 | /// Initializes all the fields of the static TLS area and returns the computed | 314 | /// Initializes all the fields of the static TLS area and returns the computed |
lib/std/std.zig+1| ... | @@ -88,6 +88,7 @@ pub const time = @import("time.zig"); | ... | @@ -88,6 +88,7 @@ pub const time = @import("time.zig"); |
| 88 | pub const unicode = @import("unicode.zig"); | 88 | pub const unicode = @import("unicode.zig"); |
| 89 | pub const valgrind = @import("valgrind.zig"); | 89 | pub const valgrind = @import("valgrind.zig"); |
| 90 | pub const wasm = @import("wasm.zig"); | 90 | pub const wasm = @import("wasm.zig"); |
| 91 | pub const x = @import("x.zig"); | ||
| 91 | pub const zig = @import("zig.zig"); | 92 | pub const zig = @import("zig.zig"); |
| 92 | pub const start = @import("start.zig"); | 93 | pub const start = @import("start.zig"); |
| 93 | 94 |
lib/std/target.zig+4-3| ... | @@ -211,8 +211,9 @@ pub const Target = struct { | ... | @@ -211,8 +211,9 @@ pub const Target = struct { |
| 211 | /// If neither of these cases apply, a runtime check should be used to determine if the | 211 | /// If neither of these cases apply, a runtime check should be used to determine if the |
| 212 | /// target supports a given OS feature. | 212 | /// target supports a given OS feature. |
| 213 | /// | 213 | /// |
| 214 | /// Binaries built with a given maximum version will continue to function on newer operating system | 214 | /// Binaries built with a given maximum version will continue to function on newer |
| 215 | /// versions. However, such a binary may not take full advantage of the newer operating system APIs. | 215 | /// operating system versions. However, such a binary may not take full advantage of the |
| 216 | /// newer operating system APIs. | ||
| 216 | /// | 217 | /// |
| 217 | /// See `Os.isAtLeast`. | 218 | /// See `Os.isAtLeast`. |
| 218 | pub const VersionRange = union { | 219 | pub const VersionRange = union { |
| ... | @@ -260,7 +261,7 @@ pub const Target = struct { | ... | @@ -260,7 +261,7 @@ pub const Target = struct { |
| 260 | .freebsd => return .{ | 261 | .freebsd => return .{ |
| 261 | .semver = Version.Range{ | 262 | .semver = Version.Range{ |
| 262 | .min = .{ .major = 12, .minor = 0 }, | 263 | .min = .{ .major = 12, .minor = 0 }, |
| 263 | .max = .{ .major = 12, .minor = 1 }, | 264 | .max = .{ .major = 13, .minor = 0 }, |
| 264 | }, | 265 | }, |
| 265 | }, | 266 | }, |
| 266 | .macos => return .{ | 267 | .macos => return .{ |
lib/std/unicode.zig+1-1| ... | @@ -206,7 +206,7 @@ pub fn utf8ValidateSlice(s: []const u8) bool { | ... | @@ -206,7 +206,7 @@ pub fn utf8ValidateSlice(s: []const u8) bool { |
| 206 | return false; | 206 | return false; |
| 207 | } | 207 | } |
| 208 | 208 | ||
| 209 | if (utf8Decode(s[i .. i + cp_len])) |_| {} else |_| { | 209 | if (std.meta.isError(utf8Decode(s[i .. i + cp_len]))) { |
| 210 | return false; | 210 | return false; |
| 211 | } | 211 | } |
| 212 | i += cp_len; | 212 | i += cp_len; |
lib/std/x.zig created+1| ... | @@ -0,0 +1 @@ | ||
| 1 | pub const os = @import("x/os/os.zig"); | ||
lib/std/x/os/Socket.zig created+276| ... | @@ -0,0 +1,276 @@ | ||
| 1 | const std = @import("../../std.zig"); | ||
| 2 | |||
| 3 | const os = std.os; | ||
| 4 | const mem = std.mem; | ||
| 5 | const net = std.net; | ||
| 6 | const time = std.time; | ||
| 7 | const builtin = std.builtin; | ||
| 8 | const testing = std.testing; | ||
| 9 | |||
| 10 | const Socket = @This(); | ||
| 11 | |||
| 12 | /// A socket-address pair. | ||
| 13 | pub const Connection = struct { | ||
| 14 | socket: Socket, | ||
| 15 | address: net.Address, | ||
| 16 | }; | ||
| 17 | |||
| 18 | /// The underlying handle of a socket. | ||
| 19 | fd: os.socket_t, | ||
| 20 | |||
| 21 | /// Open a new socket. | ||
| 22 | pub fn init(domain: u32, socket_type: u32, protocol: u32) !Socket { | ||
| 23 | return Socket{ .fd = try os.socket(domain, socket_type, protocol) }; | ||
| 24 | } | ||
| 25 | |||
| 26 | /// Closes the socket. | ||
| 27 | pub fn deinit(self: Socket) void { | ||
| 28 | os.closeSocket(self.fd); | ||
| 29 | } | ||
| 30 | |||
| 31 | /// Shutdown either the read side, or write side, or the entirety of a socket. | ||
| 32 | pub fn shutdown(self: Socket, how: os.ShutdownHow) !void { | ||
| 33 | return os.shutdown(self.fd, how); | ||
| 34 | } | ||
| 35 | |||
| 36 | /// Binds the socket to an address. | ||
| 37 | pub fn bind(self: Socket, address: net.Address) !void { | ||
| 38 | return os.bind(self.fd, &address.any, address.getOsSockLen()); | ||
| 39 | } | ||
| 40 | |||
| 41 | /// Start listening for incoming connections on the socket. | ||
| 42 | pub fn listen(self: Socket, max_backlog_size: u31) !void { | ||
| 43 | return os.listen(self.fd, max_backlog_size); | ||
| 44 | } | ||
| 45 | |||
| 46 | /// Have the socket attempt to the connect to an address. | ||
| 47 | pub fn connect(self: Socket, address: net.Address) !void { | ||
| 48 | return os.connect(self.fd, &address.any, address.getOsSockLen()); | ||
| 49 | } | ||
| 50 | |||
| 51 | /// Accept a pending incoming connection queued to the kernel backlog | ||
| 52 | /// of the socket. | ||
| 53 | pub fn accept(self: Socket, flags: u32) !Socket.Connection { | ||
| 54 | var address: os.sockaddr = undefined; | ||
| 55 | var address_len: u32 = @sizeOf(os.sockaddr); | ||
| 56 | |||
| 57 | const fd = try os.accept(self.fd, &address, &address_len, flags); | ||
| 58 | |||
| 59 | return Connection{ | ||
| 60 | .socket = Socket{ .fd = fd }, | ||
| 61 | .address = net.Address.initPosix(@alignCast(4, &address)), | ||
| 62 | }; | ||
| 63 | } | ||
| 64 | |||
| 65 | /// Read data from the socket into the buffer provided. It returns the | ||
| 66 | /// number of bytes read into the buffer provided. | ||
| 67 | pub fn read(self: Socket, buf: []u8) !usize { | ||
| 68 | return os.read(self.fd, buf); | ||
| 69 | } | ||
| 70 | |||
| 71 | /// Read data from the socket into the buffer provided with a set of flags | ||
| 72 | /// specified. It returns the number of bytes read into the buffer provided. | ||
| 73 | pub fn recv(self: Socket, buf: []u8, flags: u32) !usize { | ||
| 74 | return os.recv(self.fd, buf, flags); | ||
| 75 | } | ||
| 76 | |||
| 77 | /// Write a buffer of data provided to the socket. It returns the number | ||
| 78 | /// of bytes that are written to the socket. | ||
| 79 | pub fn write(self: Socket, buf: []const u8) !usize { | ||
| 80 | return os.write(self.fd, buf); | ||
| 81 | } | ||
| 82 | |||
| 83 | /// Writes multiple I/O vectors to the socket. It returns the number | ||
| 84 | /// of bytes that are written to the socket. | ||
| 85 | pub fn writev(self: Socket, buffers: []const os.iovec_const) !usize { | ||
| 86 | return os.writev(self.fd, buffers); | ||
| 87 | } | ||
| 88 | |||
| 89 | /// Write a buffer of data provided to the socket with a set of flags specified. | ||
| 90 | /// It returns the number of bytes that are written to the socket. | ||
| 91 | pub fn send(self: Socket, buf: []const u8, flags: u32) !usize { | ||
| 92 | return os.send(self.fd, buf, flags); | ||
| 93 | } | ||
| 94 | |||
| 95 | /// Writes multiple I/O vectors with a prepended message header to the socket | ||
| 96 | /// with a set of flags specified. It returns the number of bytes that are | ||
| 97 | /// written to the socket. | ||
| 98 | pub fn sendmsg(self: Socket, msg: os.msghdr_const, flags: u32) !usize { | ||
| 99 | return os.sendmsg(self.fd, msg, flags); | ||
| 100 | } | ||
| 101 | |||
| 102 | /// Query the address that the socket is locally bounded to. | ||
| 103 | pub fn getLocalAddress(self: Socket) !net.Address { | ||
| 104 | var address: os.sockaddr = undefined; | ||
| 105 | var address_len: u32 = @sizeOf(os.sockaddr); | ||
| 106 | try os.getsockname(self.fd, &address, &address_len); | ||
| 107 | return net.Address.initPosix(@alignCast(4, &address)); | ||
| 108 | } | ||
| 109 | |||
| 110 | /// Query and return the latest cached error on the socket. | ||
| 111 | pub fn getError(self: Socket) !void { | ||
| 112 | return os.getsockoptError(self.fd); | ||
| 113 | } | ||
| 114 | |||
| 115 | /// Query the read buffer size of the socket. | ||
| 116 | pub fn getReadBufferSize(self: Socket) !u32 { | ||
| 117 | var value: u32 = undefined; | ||
| 118 | var value_len: u32 = @sizeOf(u32); | ||
| 119 | |||
| 120 | const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&value), &value_len); | ||
| 121 | return switch (os.errno(rc)) { | ||
| 122 | 0 => value, | ||
| 123 | os.EBADF => error.BadFileDescriptor, | ||
| 124 | os.EFAULT => error.InvalidAddressSpace, | ||
| 125 | os.EINVAL => error.InvalidSocketOption, | ||
| 126 | os.ENOPROTOOPT => error.UnknownSocketOption, | ||
| 127 | os.ENOTSOCK => error.NotASocket, | ||
| 128 | else => |err| os.unexpectedErrno(err), | ||
| 129 | }; | ||
| 130 | } | ||
| 131 | |||
| 132 | /// Query the write buffer size of the socket. | ||
| 133 | pub fn getWriteBufferSize(self: Socket) !u32 { | ||
| 134 | var value: u32 = undefined; | ||
| 135 | var value_len: u32 = @sizeOf(u32); | ||
| 136 | |||
| 137 | const rc = os.system.getsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&value), &value_len); | ||
| 138 | return switch (os.errno(rc)) { | ||
| 139 | 0 => value, | ||
| 140 | os.EBADF => error.BadFileDescriptor, | ||
| 141 | os.EFAULT => error.InvalidAddressSpace, | ||
| 142 | os.EINVAL => error.InvalidSocketOption, | ||
| 143 | os.ENOPROTOOPT => error.UnknownSocketOption, | ||
| 144 | os.ENOTSOCK => error.NotASocket, | ||
| 145 | else => |err| os.unexpectedErrno(err), | ||
| 146 | }; | ||
| 147 | } | ||
| 148 | |||
| 149 | /// Allow multiple sockets on the same host to listen on the same address. It returns `error.UnsupportedSocketOption` if | ||
| 150 | /// the host does not support sockets listening the same address. | ||
| 151 | pub fn setReuseAddress(self: Socket, enabled: bool) !void { | ||
| 152 | if (comptime @hasDecl(os, "SO_REUSEADDR")) { | ||
| 153 | return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_REUSEADDR, mem.asBytes(&@as(usize, @boolToInt(enabled)))); | ||
| 154 | } | ||
| 155 | return error.UnsupportedSocketOption; | ||
| 156 | } | ||
| 157 | |||
| 158 | /// Allow multiple sockets on the same host to listen on the same port. It returns `error.UnsupportedSocketOption` if | ||
| 159 | /// the host does not supports sockets listening on the same port. | ||
| 160 | pub fn setReusePort(self: Socket, enabled: bool) !void { | ||
| 161 | if (comptime @hasDecl(os, "SO_REUSEPORT")) { | ||
| 162 | return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_REUSEPORT, mem.asBytes(&@as(usize, @boolToInt(enabled)))); | ||
| 163 | } | ||
| 164 | return error.UnsupportedSocketOption; | ||
| 165 | } | ||
| 166 | |||
| 167 | /// Disable Nagle's algorithm on a TCP socket. It returns `error.UnsupportedSocketOption` if the host does not support | ||
| 168 | /// sockets disabling Nagle's algorithm. | ||
| 169 | pub fn setNoDelay(self: Socket, enabled: bool) !void { | ||
| 170 | if (comptime @hasDecl(os, "TCP_NODELAY")) { | ||
| 171 | return os.setsockopt(self.fd, os.IPPROTO_TCP, os.TCP_NODELAY, mem.asBytes(&@as(usize, @boolToInt(enabled)))); | ||
| 172 | } | ||
| 173 | return error.UnsupportedSocketOption; | ||
| 174 | } | ||
| 175 | |||
| 176 | /// Enables TCP Fast Open (RFC 7413) on a TCP socket. It returns `error.UnsupportedSocketOption` if the host does not | ||
| 177 | /// support TCP Fast Open. | ||
| 178 | pub fn setFastOpen(self: Socket, enabled: bool) !void { | ||
| 179 | if (comptime @hasDecl(os, "TCP_FASTOPEN")) { | ||
| 180 | return os.setsockopt(self.fd, os.IPPROTO_TCP, os.TCP_FASTOPEN, mem.asBytes(&@as(usize, @boolToInt(enabled)))); | ||
| 181 | } | ||
| 182 | return error.UnsupportedSocketOption; | ||
| 183 | } | ||
| 184 | |||
| 185 | /// Enables TCP Quick ACK on a TCP socket to immediately send rather than delay ACKs when necessary. It returns | ||
| 186 | /// `error.UnsupportedSocketOption` if the host does not support TCP Quick ACK. | ||
| 187 | pub fn setQuickACK(self: Socket, enabled: bool) !void { | ||
| 188 | if (comptime @hasDecl(os, "TCP_QUICKACK")) { | ||
| 189 | return os.setsockopt(self.fd, os.IPPROTO_TCP, os.TCP_QUICKACK, mem.asBytes(&@as(usize, @boolToInt(enabled)))); | ||
| 190 | } | ||
| 191 | return error.UnsupportedSocketOption; | ||
| 192 | } | ||
| 193 | |||
| 194 | /// Set the write buffer size of the socket. | ||
| 195 | pub fn setWriteBufferSize(self: Socket, size: u32) !void { | ||
| 196 | return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDBUF, mem.asBytes(&size)); | ||
| 197 | } | ||
| 198 | |||
| 199 | /// Set the read buffer size of the socket. | ||
| 200 | pub fn setReadBufferSize(self: Socket, size: u32) !void { | ||
| 201 | return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVBUF, mem.asBytes(&size)); | ||
| 202 | } | ||
| 203 | |||
| 204 | /// Set a timeout on the socket that is to occur if no messages are successfully written | ||
| 205 | /// to its bound destination after a specified number of milliseconds. A subsequent write | ||
| 206 | /// to the socket will thereafter return `error.WouldBlock` should the timeout be exceeded. | ||
| 207 | pub fn setWriteTimeout(self: Socket, milliseconds: usize) !void { | ||
| 208 | const timeout = os.timeval{ | ||
| 209 | .tv_sec = @intCast(isize, milliseconds / time.ms_per_s), | ||
| 210 | .tv_usec = @intCast(isize, (milliseconds % time.ms_per_s) * time.us_per_ms), | ||
| 211 | }; | ||
| 212 | |||
| 213 | return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_SNDTIMEO, mem.asBytes(&timeout)); | ||
| 214 | } | ||
| 215 | |||
| 216 | /// Set a timeout on the socket that is to occur if no messages are successfully read | ||
| 217 | /// from its bound destination after a specified number of milliseconds. A subsequent | ||
| 218 | /// read from the socket will thereafter return `error.WouldBlock` should the timeout be | ||
| 219 | /// exceeded. | ||
| 220 | pub fn setReadTimeout(self: Socket, milliseconds: usize) !void { | ||
| 221 | const timeout = os.timeval{ | ||
| 222 | .tv_sec = @intCast(isize, milliseconds / time.ms_per_s), | ||
| 223 | .tv_usec = @intCast(isize, (milliseconds % time.ms_per_s) * time.us_per_ms), | ||
| 224 | }; | ||
| 225 | |||
| 226 | return os.setsockopt(self.fd, os.SOL_SOCKET, os.SO_RCVTIMEO, mem.asBytes(&timeout)); | ||
| 227 | } | ||
| 228 | |||
| 229 | test { | ||
| 230 | testing.refAllDecls(@This()); | ||
| 231 | } | ||
| 232 | |||
| 233 | test "socket/linux: set read timeout of 1 millisecond on blocking socket" { | ||
| 234 | if (builtin.os.tag != .linux) return error.SkipZigTest; | ||
| 235 | |||
| 236 | const a = try Socket.init(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC, os.IPPROTO_TCP); | ||
| 237 | defer a.deinit(); | ||
| 238 | |||
| 239 | try a.bind(net.Address.initIp4([_]u8{ 0, 0, 0, 0 }, 0)); | ||
| 240 | try a.listen(128); | ||
| 241 | |||
| 242 | const binded_address = try a.getLocalAddress(); | ||
| 243 | |||
| 244 | const b = try Socket.init(os.AF_INET, os.SOCK_STREAM | os.SOCK_CLOEXEC, os.IPPROTO_TCP); | ||
| 245 | defer b.deinit(); | ||
| 246 | |||
| 247 | try b.connect(binded_address); | ||
| 248 | try b.setReadTimeout(1); | ||
| 249 | |||
| 250 | const ab = try a.accept(os.SOCK_CLOEXEC); | ||
| 251 | defer ab.socket.deinit(); | ||
| 252 | |||
| 253 | var buf: [1]u8 = undefined; | ||
| 254 | testing.expectError(error.WouldBlock, b.read(&buf)); | ||
| 255 | } | ||
| 256 | |||
| 257 | test "socket/linux: create non-blocking socket pair" { | ||
| 258 | if (builtin.os.tag != .linux) return error.SkipZigTest; | ||
| 259 | |||
| 260 | const a = try Socket.init(os.AF_INET, os.SOCK_STREAM | os.SOCK_NONBLOCK | os.SOCK_CLOEXEC, os.IPPROTO_TCP); | ||
| 261 | defer a.deinit(); | ||
| 262 | |||
| 263 | try a.bind(net.Address.initIp4([_]u8{ 0, 0, 0, 0 }, 0)); | ||
| 264 | try a.listen(128); | ||
| 265 | |||
| 266 | const binded_address = try a.getLocalAddress(); | ||
| 267 | |||
| 268 | const b = try Socket.init(os.AF_INET, os.SOCK_STREAM | os.SOCK_NONBLOCK | os.SOCK_CLOEXEC, os.IPPROTO_TCP); | ||
| 269 | defer b.deinit(); | ||
| 270 | |||
| 271 | testing.expectError(error.WouldBlock, b.connect(binded_address)); | ||
| 272 | try b.getError(); | ||
| 273 | |||
| 274 | const ab = try a.accept(os.SOCK_NONBLOCK | os.SOCK_CLOEXEC); | ||
| 275 | defer ab.socket.deinit(); | ||
| 276 | } | ||
lib/std/x/os/os.zig created+9| ... | @@ -0,0 +1,9 @@ | ||
| 1 | const std = @import("../../std.zig"); | ||
| 2 | |||
| 3 | const testing = std.testing; | ||
| 4 | |||
| 5 | pub const Socket = @import("Socket.zig"); | ||
| 6 | |||
| 7 | test { | ||
| 8 | testing.refAllDecls(@This()); | ||
| 9 | } | ||
lib/std/zig/system.zig+10-5| ... | @@ -15,6 +15,7 @@ const Target = std.Target; | ... | @@ -15,6 +15,7 @@ const Target = std.Target; |
| 15 | const CrossTarget = std.zig.CrossTarget; | 15 | const CrossTarget = std.zig.CrossTarget; |
| 16 | const macos = @import("system/macos.zig"); | 16 | const macos = @import("system/macos.zig"); |
| 17 | const native_endian = std.Target.current.cpu.arch.endian(); | 17 | const native_endian = std.Target.current.cpu.arch.endian(); |
| 18 | const linux = @import("system/linux.zig"); | ||
| 18 | pub const windows = @import("system/windows.zig"); | 19 | pub const windows = @import("system/windows.zig"); |
| 19 | 20 | ||
| 20 | pub const getSDKPath = macos.getSDKPath; | 21 | pub const getSDKPath = macos.getSDKPath; |
| ... | @@ -912,15 +913,19 @@ pub const NativeTargetInfo = struct { | ... | @@ -912,15 +913,19 @@ pub const NativeTargetInfo = struct { |
| 912 | .x86_64, .i386 => { | 913 | .x86_64, .i386 => { |
| 913 | return @import("system/x86.zig").detectNativeCpuAndFeatures(cpu_arch, os, cross_target); | 914 | return @import("system/x86.zig").detectNativeCpuAndFeatures(cpu_arch, os, cross_target); |
| 914 | }, | 915 | }, |
| 915 | else => { | 916 | else => {}, |
| 916 | // This architecture does not have CPU model & feature detection yet. | ||
| 917 | // See https://github.com/ziglang/zig/issues/4591 | ||
| 918 | return null; | ||
| 919 | }, | ||
| 920 | } | 917 | } |
| 918 | |||
| 919 | // This architecture does not have CPU model & feature detection yet. | ||
| 920 | // See https://github.com/ziglang/zig/issues/4591 | ||
| 921 | if (std.Target.current.os.tag != .linux) | ||
| 922 | return null; | ||
| 923 | |||
| 924 | return linux.detectNativeCpuAndFeatures(); | ||
| 921 | } | 925 | } |
| 922 | }; | 926 | }; |
| 923 | 927 | ||
| 924 | test { | 928 | test { |
| 925 | _ = @import("system/macos.zig"); | 929 | _ = @import("system/macos.zig"); |
| 930 | _ = @import("system/linux.zig"); | ||
| 926 | } | 931 | } |
lib/std/zig/system/linux.zig created+199| ... | @@ -0,0 +1,199 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const mem = std.mem; | ||
| 3 | const io = std.io; | ||
| 4 | const fs = std.fs; | ||
| 5 | const fmt = std.fmt; | ||
| 6 | const testing = std.testing; | ||
| 7 | |||
| 8 | const Target = std.Target; | ||
| 9 | const CrossTarget = std.zig.CrossTarget; | ||
| 10 | |||
| 11 | const assert = std.debug.assert; | ||
| 12 | |||
| 13 | const SparcCpuinfoImpl = struct { | ||
| 14 | model: ?*const Target.Cpu.Model = null, | ||
| 15 | is_64bit: bool = false, | ||
| 16 | |||
| 17 | const cpu_names = .{ | ||
| 18 | .{ "SuperSparc", &Target.sparc.cpu.supersparc }, | ||
| 19 | .{ "HyperSparc", &Target.sparc.cpu.hypersparc }, | ||
| 20 | .{ "SpitFire", &Target.sparc.cpu.ultrasparc }, | ||
| 21 | .{ "BlackBird", &Target.sparc.cpu.ultrasparc }, | ||
| 22 | .{ "Sabre", &Target.sparc.cpu.ultrasparc }, | ||
| 23 | .{ "Hummingbird", &Target.sparc.cpu.ultrasparc }, | ||
| 24 | .{ "Cheetah", &Target.sparc.cpu.ultrasparc3 }, | ||
| 25 | .{ "Jalapeno", &Target.sparc.cpu.ultrasparc3 }, | ||
| 26 | .{ "Jaguar", &Target.sparc.cpu.ultrasparc3 }, | ||
| 27 | .{ "Panther", &Target.sparc.cpu.ultrasparc3 }, | ||
| 28 | .{ "Serrano", &Target.sparc.cpu.ultrasparc3 }, | ||
| 29 | .{ "UltraSparc T1", &Target.sparc.cpu.niagara }, | ||
| 30 | .{ "UltraSparc T2", &Target.sparc.cpu.niagara2 }, | ||
| 31 | .{ "UltraSparc T3", &Target.sparc.cpu.niagara3 }, | ||
| 32 | .{ "UltraSparc T4", &Target.sparc.cpu.niagara4 }, | ||
| 33 | .{ "UltraSparc T5", &Target.sparc.cpu.niagara4 }, | ||
| 34 | .{ "LEON", &Target.sparc.cpu.leon3 }, | ||
| 35 | }; | ||
| 36 | |||
| 37 | fn line_hook(self: *SparcCpuinfoImpl, key: []const u8, value: []const u8) !bool { | ||
| 38 | if (mem.eql(u8, key, "cpu")) { | ||
| 39 | inline for (cpu_names) |pair| { | ||
| 40 | if (mem.indexOfPos(u8, value, 0, pair[0]) != null) { | ||
| 41 | self.model = pair[1]; | ||
| 42 | break; | ||
| 43 | } | ||
| 44 | } | ||
| 45 | } else if (mem.eql(u8, key, "type")) { | ||
| 46 | self.is_64bit = mem.eql(u8, value, "sun4u") or mem.eql(u8, value, "sun4v"); | ||
| 47 | } | ||
| 48 | |||
| 49 | return true; | ||
| 50 | } | ||
| 51 | |||
| 52 | fn finalize(self: *const SparcCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu { | ||
| 53 | // At the moment we only support 64bit SPARC systems. | ||
| 54 | assert(self.is_64bit); | ||
| 55 | |||
| 56 | const model = self.model orelse Target.Cpu.Model.generic(arch); | ||
| 57 | return Target.Cpu{ | ||
| 58 | .arch = arch, | ||
| 59 | .model = model, | ||
| 60 | .features = model.features, | ||
| 61 | }; | ||
| 62 | } | ||
| 63 | }; | ||
| 64 | |||
| 65 | const SparcCpuinfoParser = CpuinfoParser(SparcCpuinfoImpl); | ||
| 66 | |||
| 67 | test "cpuinfo: SPARC" { | ||
| 68 | try testParser(SparcCpuinfoParser, &Target.sparc.cpu.niagara2, | ||
| 69 | \\cpu : UltraSparc T2 (Niagara2) | ||
| 70 | \\fpu : UltraSparc T2 integrated FPU | ||
| 71 | \\pmu : niagara2 | ||
| 72 | \\type : sun4v | ||
| 73 | ); | ||
| 74 | } | ||
| 75 | |||
| 76 | const PowerpcCpuinfoImpl = struct { | ||
| 77 | model: ?*const Target.Cpu.Model = null, | ||
| 78 | |||
| 79 | const cpu_names = .{ | ||
| 80 | .{ "604e", &Target.powerpc.cpu.@"604e" }, | ||
| 81 | .{ "604", &Target.powerpc.cpu.@"604" }, | ||
| 82 | .{ "7400", &Target.powerpc.cpu.@"7400" }, | ||
| 83 | .{ "7410", &Target.powerpc.cpu.@"7400" }, | ||
| 84 | .{ "7447", &Target.powerpc.cpu.@"7400" }, | ||
| 85 | .{ "7455", &Target.powerpc.cpu.@"7450" }, | ||
| 86 | .{ "G4", &Target.powerpc.cpu.@"g4" }, | ||
| 87 | .{ "POWER4", &Target.powerpc.cpu.@"970" }, | ||
| 88 | .{ "PPC970FX", &Target.powerpc.cpu.@"970" }, | ||
| 89 | .{ "PPC970MP", &Target.powerpc.cpu.@"970" }, | ||
| 90 | .{ "G5", &Target.powerpc.cpu.@"g5" }, | ||
| 91 | .{ "POWER5", &Target.powerpc.cpu.@"g5" }, | ||
| 92 | .{ "A2", &Target.powerpc.cpu.@"a2" }, | ||
| 93 | .{ "POWER6", &Target.powerpc.cpu.@"pwr6" }, | ||
| 94 | .{ "POWER7", &Target.powerpc.cpu.@"pwr7" }, | ||
| 95 | .{ "POWER8", &Target.powerpc.cpu.@"pwr8" }, | ||
| 96 | .{ "POWER8E", &Target.powerpc.cpu.@"pwr8" }, | ||
| 97 | .{ "POWER8NVL", &Target.powerpc.cpu.@"pwr8" }, | ||
| 98 | .{ "POWER9", &Target.powerpc.cpu.@"pwr9" }, | ||
| 99 | .{ "POWER10", &Target.powerpc.cpu.@"pwr10" }, | ||
| 100 | }; | ||
| 101 | |||
| 102 | fn line_hook(self: *PowerpcCpuinfoImpl, key: []const u8, value: []const u8) !bool { | ||
| 103 | if (mem.eql(u8, key, "cpu")) { | ||
| 104 | // The model name is often followed by a comma or space and extra | ||
| 105 | // info. | ||
| 106 | inline for (cpu_names) |pair| { | ||
| 107 | const end_index = mem.indexOfAny(u8, value, ", ") orelse value.len; | ||
| 108 | if (mem.eql(u8, value[0..end_index], pair[0])) { | ||
| 109 | self.model = pair[1]; | ||
| 110 | break; | ||
| 111 | } | ||
| 112 | } | ||
| 113 | |||
| 114 | // Stop the detection once we've seen the first core. | ||
| 115 | return false; | ||
| 116 | } | ||
| 117 | |||
| 118 | return true; | ||
| 119 | } | ||
| 120 | |||
| 121 | fn finalize(self: *const PowerpcCpuinfoImpl, arch: Target.Cpu.Arch) ?Target.Cpu { | ||
| 122 | const model = self.model orelse Target.Cpu.Model.generic(arch); | ||
| 123 | return Target.Cpu{ | ||
| 124 | .arch = arch, | ||
| 125 | .model = model, | ||
| 126 | .features = model.features, | ||
| 127 | }; | ||
| 128 | } | ||
| 129 | }; | ||
| 130 | |||
| 131 | const PowerpcCpuinfoParser = CpuinfoParser(PowerpcCpuinfoImpl); | ||
| 132 | |||
| 133 | test "cpuinfo: PowerPC" { | ||
| 134 | try testParser(PowerpcCpuinfoParser, &Target.powerpc.cpu.@"970", | ||
| 135 | \\processor	: 0 | ||
| 136 | \\cpu		: PPC970MP, altivec supported | ||
| 137 | \\clock		: 1250.000000MHz | ||
| 138 | \\revision	: 1.1 (pvr 0044 0101) | ||
| 139 | ); | ||
| 140 | try testParser(PowerpcCpuinfoParser, &Target.powerpc.cpu.pwr8, | ||
| 141 | \\processor	: 0 | ||
| 142 | \\cpu		: POWER8 (raw), altivec supported | ||
| 143 | \\clock		: 2926.000000MHz | ||
| 144 | \\revision	: 2.0 (pvr 004d 0200) | ||
| 145 | ); | ||
| 146 | } | ||
| 147 | |||
| 148 | fn testParser(parser: anytype, expected_model: *const Target.Cpu.Model, input: []const u8) !void { | ||
| 149 | var fbs = io.fixedBufferStream(input); | ||
| 150 | const result = try parser.parse(.powerpc, fbs.reader()); | ||
| 151 | testing.expectEqual(expected_model, result.?.model); | ||
| 152 | testing.expect(expected_model.features.eql(result.?.features)); | ||
| 153 | } | ||
| 154 | |||
| 155 | // The generic implementation of a /proc/cpuinfo parser. | ||
| 156 | // For every line it invokes the line_hook method with the key and value strings | ||
| 157 | // as first and second parameters. Returning false from the hook function stops | ||
| 158 | // the iteration without raising an error. | ||
| 159 | // When all the lines have been analyzed the finalize method is called. | ||
| 160 | fn CpuinfoParser(comptime impl: anytype) type { | ||
| 161 | return struct { | ||
| 162 | fn parse(arch: Target.Cpu.Arch, reader: anytype) anyerror!?Target.Cpu { | ||
| 163 | var line_buf: [1024]u8 = undefined; | ||
| 164 | var obj: impl = .{}; | ||
| 165 | |||
| 166 | while (true) { | ||
| 167 | const line = (try reader.readUntilDelimiterOrEof(&line_buf, '\n')) orelse break; | ||
| 168 | const colon_pos = mem.indexOfScalar(u8, line, ':') orelse continue; | ||
| 169 | const key = mem.trimRight(u8, line[0..colon_pos], " \t"); | ||
| 170 | const value = mem.trimLeft(u8, line[colon_pos + 1 ..], " \t"); | ||
| 171 | |||
| 172 | if (!try obj.line_hook(key, value)) | ||
| 173 | break; | ||
| 174 | } | ||
| 175 | |||
| 176 | return obj.finalize(arch); | ||
| 177 | } | ||
| 178 | }; | ||
| 179 | } | ||
| 180 | |||
| 181 | pub fn detectNativeCpuAndFeatures() ?Target.Cpu { | ||
| 182 | var f = fs.openFileAbsolute("/proc/cpuinfo", .{ .intended_io_mode = .blocking }) catch |err| switch (err) { | ||
| 183 | else => return null, | ||
| 184 | }; | ||
| 185 | defer f.close(); | ||
| 186 | |||
| 187 | const current_arch = std.Target.current.cpu.arch; | ||
| 188 | switch (current_arch) { | ||
| 189 | .sparcv9 => { | ||
| 190 | return SparcCpuinfoParser.parse(current_arch, f.reader()) catch null; | ||
| 191 | }, | ||
| 192 | .powerpc, .powerpcle, .powerpc64, .powerpc64le => { | ||
| 193 | return PowerpcCpuinfoParser.parse(current_arch, f.reader()) catch null; | ||
| 194 | }, | ||
| 195 | else => {}, | ||
| 196 | } | ||
| 197 | |||
| 198 | return null; | ||
| 199 | } | ||
src/clang.zig+16| ... | @@ -104,6 +104,16 @@ pub const APFloat = opaque { | ... | @@ -104,6 +104,16 @@ pub const APFloat = opaque { |
| 104 | extern fn ZigClangAPFloat_toString(*const APFloat, precision: c_uint, maxPadding: c_uint, truncateZero: bool) [*:0]const u8; | 104 | extern fn ZigClangAPFloat_toString(*const APFloat, precision: c_uint, maxPadding: c_uint, truncateZero: bool) [*:0]const u8; |
| 105 | }; | 105 | }; |
| 106 | 106 | ||
| 107 | pub const APFloatBaseSemantics = extern enum { | ||
| 108 | IEEEhalf, | ||
| 109 | BFloat, | ||
| 110 | IEEEsingle, | ||
| 111 | IEEEdouble, | ||
| 112 | x86DoubleExtended, | ||
| 113 | IEEEquad, | ||
| 114 | PPCDoubleDouble, | ||
| 115 | }; | ||
| 116 | |||
| 107 | pub const APInt = opaque { | 117 | pub const APInt = opaque { |
| 108 | pub const getLimitedValue = ZigClangAPInt_getLimitedValue; | 118 | pub const getLimitedValue = ZigClangAPInt_getLimitedValue; |
| 109 | extern fn ZigClangAPInt_getLimitedValue(*const APInt, limit: u64) u64; | 119 | extern fn ZigClangAPInt_getLimitedValue(*const APInt, limit: u64) u64; |
| ... | @@ -455,6 +465,12 @@ pub const FileID = opaque {}; | ... | @@ -455,6 +465,12 @@ pub const FileID = opaque {}; |
| 455 | pub const FloatingLiteral = opaque { | 465 | pub const FloatingLiteral = opaque { |
| 456 | pub const getValueAsApproximateDouble = ZigClangFloatingLiteral_getValueAsApproximateDouble; | 466 | pub const getValueAsApproximateDouble = ZigClangFloatingLiteral_getValueAsApproximateDouble; |
| 457 | extern fn ZigClangFloatingLiteral_getValueAsApproximateDouble(*const FloatingLiteral) f64; | 467 | extern fn ZigClangFloatingLiteral_getValueAsApproximateDouble(*const FloatingLiteral) f64; |
| 468 | |||
| 469 | pub const getBeginLoc = ZigClangIntegerLiteral_getBeginLoc; | ||
| 470 | extern fn ZigClangIntegerLiteral_getBeginLoc(*const FloatingLiteral) SourceLocation; | ||
| 471 | |||
| 472 | pub const getRawSemantics = ZigClangFloatingLiteral_getRawSemantics; | ||
| 473 | extern fn ZigClangFloatingLiteral_getRawSemantics(*const FloatingLiteral) APFloatBaseSemantics; | ||
| 458 | }; | 474 | }; |
| 459 | 475 | ||
| 460 | pub const ForStmt = opaque { | 476 | pub const ForStmt = opaque { |
src/codegen.zig+29-17| ... | @@ -449,7 +449,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -449,7 +449,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 449 | .rbrace_src = src_data.rbrace_src, | 449 | .rbrace_src = src_data.rbrace_src, |
| 450 | .source = src_data.source, | 450 | .source = src_data.source, |
| 451 | }; | 451 | }; |
| 452 | defer function.register_manager.deinit(bin_file.allocator); | ||
| 453 | defer function.stack.deinit(bin_file.allocator); | 452 | defer function.stack.deinit(bin_file.allocator); |
| 454 | defer function.exitlude_jump_relocs.deinit(bin_file.allocator); | 453 | defer function.exitlude_jump_relocs.deinit(bin_file.allocator); |
| 455 | 454 | ||
| ... | @@ -779,8 +778,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -779,8 +778,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 779 | branch.inst_table.putAssumeCapacity(inst, .dead); | 778 | branch.inst_table.putAssumeCapacity(inst, .dead); |
| 780 | switch (prev_value) { | 779 | switch (prev_value) { |
| 781 | .register => |reg| { | 780 | .register => |reg| { |
| 782 | const canon_reg = toCanonicalReg(reg); | 781 | // TODO separate architectures with registers from |
| 783 | self.register_manager.freeReg(canon_reg); | 782 | // stack-based architectures (spu_2) |
| 783 | if (callee_preserved_regs.len > 0) { | ||
| 784 | const canon_reg = toCanonicalReg(reg); | ||
| 785 | self.register_manager.freeReg(canon_reg); | ||
| 786 | } | ||
| 784 | }, | 787 | }, |
| 785 | else => {}, // TODO process stack allocation death | 788 | else => {}, // TODO process stack allocation death |
| 786 | } | 789 | } |
| ... | @@ -920,9 +923,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -920,9 +923,12 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 920 | const ptr_bits = arch.ptrBitWidth(); | 923 | const ptr_bits = arch.ptrBitWidth(); |
| 921 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); | 924 | const ptr_bytes: u64 = @divExact(ptr_bits, 8); |
| 922 | if (abi_size <= ptr_bytes) { | 925 | if (abi_size <= ptr_bytes) { |
| 923 | try self.register_manager.registers.ensureCapacity(self.gpa, self.register_manager.registers.count() + 1); | 926 | // TODO separate architectures with registers from |
| 924 | if (self.register_manager.tryAllocReg(inst)) |reg| { | 927 | // stack-based architectures (spu_2) |
| 925 | return MCValue{ .register = registerAlias(reg, abi_size) }; | 928 | if (callee_preserved_regs.len > 0) { |
| 929 | if (self.register_manager.tryAllocReg(inst)) |reg| { | ||
| 930 | return MCValue{ .register = registerAlias(reg, abi_size) }; | ||
| 931 | } | ||
| 926 | } | 932 | } |
| 927 | } | 933 | } |
| 928 | } | 934 | } |
| ... | @@ -952,8 +958,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -952,8 +958,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 952 | /// `reg_owner` is the instruction that gets associated with the register in the register table. | 958 | /// `reg_owner` is the instruction that gets associated with the register in the register table. |
| 953 | /// This can have a side effect of spilling instructions to the stack to free up a register. | 959 | /// This can have a side effect of spilling instructions to the stack to free up a register. |
| 954 | fn copyToNewRegister(self: *Self, reg_owner: *ir.Inst, mcv: MCValue) !MCValue { | 960 | fn copyToNewRegister(self: *Self, reg_owner: *ir.Inst, mcv: MCValue) !MCValue { |
| 955 | try self.register_manager.registers.ensureCapacity(self.gpa, @intCast(u32, self.register_manager.registers.count() + 1)); | ||
| 956 | |||
| 957 | const reg = try self.register_manager.allocReg(reg_owner); | 961 | const reg = try self.register_manager.allocReg(reg_owner); |
| 958 | try self.genSetReg(reg_owner.src, reg_owner.ty, reg, mcv); | 962 | try self.genSetReg(reg_owner.src, reg_owner.ty, reg, mcv); |
| 959 | return MCValue{ .register = reg }; | 963 | return MCValue{ .register = reg }; |
| ... | @@ -1240,10 +1244,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1240,10 +1244,16 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1240 | .register => |reg| { | 1244 | .register => |reg| { |
| 1241 | // If it's in the registers table, need to associate the register with the | 1245 | // If it's in the registers table, need to associate the register with the |
| 1242 | // new instruction. | 1246 | // new instruction. |
| 1243 | if (self.register_manager.registers.getEntry(toCanonicalReg(reg))) |entry| { | 1247 | // TODO separate architectures with registers from |
| 1244 | entry.value = inst; | 1248 | // stack-based architectures (spu_2) |
| 1249 | if (callee_preserved_regs.len > 0) { | ||
| 1250 | if (reg.allocIndex()) |index| { | ||
| 1251 | if (!self.register_manager.isRegFree(reg)) { | ||
| 1252 | self.register_manager.registers[index] = inst; | ||
| 1253 | } | ||
| 1254 | } | ||
| 1255 | log.debug("reusing {} => {*}", .{ reg, inst }); | ||
| 1245 | } | 1256 | } |
| 1246 | log.debug("reusing {} => {*}", .{ reg, inst }); | ||
| 1247 | }, | 1257 | }, |
| 1248 | .stack_offset => |off| { | 1258 | .stack_offset => |off| { |
| 1249 | log.debug("reusing stack offset {} => {*}", .{ off, inst }); | 1259 | log.debug("reusing stack offset {} => {*}", .{ off, inst }); |
| ... | @@ -1738,6 +1748,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1738,6 +1748,8 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1738 | const arg_index = self.arg_index; | 1748 | const arg_index = self.arg_index; |
| 1739 | self.arg_index += 1; | 1749 | self.arg_index += 1; |
| 1740 | 1750 | ||
| 1751 | // TODO separate architectures with registers from | ||
| 1752 | // stack-based architectures (spu_2) | ||
| 1741 | if (callee_preserved_regs.len == 0) { | 1753 | if (callee_preserved_regs.len == 0) { |
| 1742 | return self.fail(inst.base.src, "TODO implement Register enum for {}", .{self.target.cpu.arch}); | 1754 | return self.fail(inst.base.src, "TODO implement Register enum for {}", .{self.target.cpu.arch}); |
| 1743 | } | 1755 | } |
| ... | @@ -1769,7 +1781,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -1769,7 +1781,6 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 1769 | 1781 | ||
| 1770 | switch (mcv) { | 1782 | switch (mcv) { |
| 1771 | .register => |reg| { | 1783 | .register => |reg| { |
| 1772 | try self.register_manager.registers.ensureCapacity(self.gpa, self.register_manager.registers.count() + 1); | ||
| 1773 | self.register_manager.getRegAssumeFree(toCanonicalReg(reg), &inst.base); | 1784 | self.register_manager.getRegAssumeFree(toCanonicalReg(reg), &inst.base); |
| 1774 | }, | 1785 | }, |
| 1775 | else => {}, | 1786 | else => {}, |
| ... | @@ -2075,7 +2086,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2075,7 +2086,11 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2075 | switch (mc_arg) { | 2086 | switch (mc_arg) { |
| 2076 | .none => continue, | 2087 | .none => continue, |
| 2077 | .register => |reg| { | 2088 | .register => |reg| { |
| 2078 | try self.register_manager.getRegWithoutTracking(reg); | 2089 | // TODO prevent this macho if block to be generated for all archs |
| 2090 | switch (arch) { | ||
| 2091 | .x86_64, .aarch64 => try self.register_manager.getRegWithoutTracking(reg), | ||
| 2092 | else => unreachable, | ||
| 2093 | } | ||
| 2079 | try self.genSetReg(arg.src, arg.ty, reg, arg_mcv); | 2094 | try self.genSetReg(arg.src, arg.ty, reg, arg_mcv); |
| 2080 | }, | 2095 | }, |
| 2081 | .stack_offset => { | 2096 | .stack_offset => { |
| ... | @@ -2397,8 +2412,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2397,8 +2412,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2397 | const parent_free_registers = self.register_manager.free_registers; | 2412 | const parent_free_registers = self.register_manager.free_registers; |
| 2398 | var parent_stack = try self.stack.clone(self.gpa); | 2413 | var parent_stack = try self.stack.clone(self.gpa); |
| 2399 | defer parent_stack.deinit(self.gpa); | 2414 | defer parent_stack.deinit(self.gpa); |
| 2400 | var parent_registers = try self.register_manager.registers.clone(self.gpa); | 2415 | const parent_registers = self.register_manager.registers; |
| 2401 | defer parent_registers.deinit(self.gpa); | ||
| 2402 | 2416 | ||
| 2403 | try self.branch_stack.append(.{}); | 2417 | try self.branch_stack.append(.{}); |
| 2404 | 2418 | ||
| ... | @@ -2414,9 +2428,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { | ... | @@ -2414,9 +2428,7 @@ fn Function(comptime arch: std.Target.Cpu.Arch) type { |
| 2414 | var saved_then_branch = self.branch_stack.pop(); | 2428 | var saved_then_branch = self.branch_stack.pop(); |
| 2415 | defer saved_then_branch.deinit(self.gpa); | 2429 | defer saved_then_branch.deinit(self.gpa); |
| 2416 | 2430 | ||
| 2417 | self.register_manager.registers.deinit(self.gpa); | ||
| 2418 | self.register_manager.registers = parent_registers; | 2431 | self.register_manager.registers = parent_registers; |
| 2419 | parent_registers = .{}; | ||
| 2420 | 2432 | ||
| 2421 | self.stack.deinit(self.gpa); | 2433 | self.stack.deinit(self.gpa); |
| 2422 | self.stack = parent_stack; | 2434 | self.stack = parent_stack; |
src/codegen/riscv64.zig+47-10| ... | @@ -1,5 +1,7 @@ | ... | @@ -1,5 +1,7 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const DW = std.dwarf; | 2 | const DW = std.dwarf; |
| 3 | const assert = std.debug.assert; | ||
| 4 | const testing = std.testing; | ||
| 3 | 5 | ||
| 4 | // TODO: this is only tagged to facilitate the monstrosity. | 6 | // TODO: this is only tagged to facilitate the monstrosity. |
| 5 | // Once packed structs work make it packed. | 7 | // Once packed structs work make it packed. |
| ... | @@ -110,7 +112,7 @@ pub const Instruction = union(enum) { | ... | @@ -110,7 +112,7 @@ pub const Instruction = union(enum) { |
| 110 | // -- less burden on callsite, bonus semantic checking | 112 | // -- less burden on callsite, bonus semantic checking |
| 111 | fn bType(op: u7, fn3: u3, r1: Register, r2: Register, imm: i13) Instruction { | 113 | fn bType(op: u7, fn3: u3, r1: Register, r2: Register, imm: i13) Instruction { |
| 112 | const umm = @bitCast(u13, imm); | 114 | const umm = @bitCast(u13, imm); |
| 113 | if (umm % 2 != 0) @panic("Internal error: misaligned branch target"); | 115 | assert(umm % 2 == 0); // misaligned branch target |
| 114 | 116 | ||
| 115 | return Instruction{ | 117 | return Instruction{ |
| 116 | .B = .{ | 118 | .B = .{ |
| ... | @@ -140,15 +142,15 @@ pub const Instruction = union(enum) { | ... | @@ -140,15 +142,15 @@ pub const Instruction = union(enum) { |
| 140 | } | 142 | } |
| 141 | 143 | ||
| 142 | fn jType(op: u7, rd: Register, imm: i21) Instruction { | 144 | fn jType(op: u7, rd: Register, imm: i21) Instruction { |
| 143 | const umm = @bitcast(u21, imm); | 145 | const umm = @bitCast(u21, imm); |
| 144 | if (umm % 2 != 0) @panic("Internal error: misaligned jump target"); | 146 | assert(umm % 2 == 0); // misaligned jump target |
| 145 | 147 | ||
| 146 | return Instruction{ | 148 | return Instruction{ |
| 147 | .J = .{ | 149 | .J = .{ |
| 148 | .opcode = op, | 150 | .opcode = op, |
| 149 | .rd = @enumToInt(rd), | 151 | .rd = @enumToInt(rd), |
| 150 | .imm1_10 = @truncate(u10, umm >> 1), | 152 | .imm1_10 = @truncate(u10, umm >> 1), |
| 151 | .imm11 = @truncate(u1, umm >> 1), | 153 | .imm11 = @truncate(u1, umm >> 11), |
| 152 | .imm12_19 = @truncate(u8, umm >> 12), | 154 | .imm12_19 = @truncate(u8, umm >> 12), |
| 153 | .imm20 = @truncate(u1, umm >> 20), | 155 | .imm20 = @truncate(u1, umm >> 20), |
| 154 | }, | 156 | }, |
| ... | @@ -340,27 +342,27 @@ pub const Instruction = union(enum) { | ... | @@ -340,27 +342,27 @@ pub const Instruction = union(enum) { |
| 340 | 342 | ||
| 341 | // Branch | 343 | // Branch |
| 342 | 344 | ||
| 343 | pub fn beq(r1: Register, r2: Register, offset: u13) Instruction { | 345 | pub fn beq(r1: Register, r2: Register, offset: i13) Instruction { |
| 344 | return bType(0b1100011, 0b000, r1, r2, offset); | 346 | return bType(0b1100011, 0b000, r1, r2, offset); |
| 345 | } | 347 | } |
| 346 | 348 | ||
| 347 | pub fn bne(r1: Register, r2: Register, offset: u13) Instruction { | 349 | pub fn bne(r1: Register, r2: Register, offset: i13) Instruction { |
| 348 | return bType(0b1100011, 0b001, r1, r2, offset); | 350 | return bType(0b1100011, 0b001, r1, r2, offset); |
| 349 | } | 351 | } |
| 350 | 352 | ||
| 351 | pub fn blt(r1: Register, r2: Register, offset: u13) Instruction { | 353 | pub fn blt(r1: Register, r2: Register, offset: i13) Instruction { |
| 352 | return bType(0b1100011, 0b100, r1, r2, offset); | 354 | return bType(0b1100011, 0b100, r1, r2, offset); |
| 353 | } | 355 | } |
| 354 | 356 | ||
| 355 | pub fn bge(r1: Register, r2: Register, offset: u13) Instruction { | 357 | pub fn bge(r1: Register, r2: Register, offset: i13) Instruction { |
| 356 | return bType(0b1100011, 0b101, r1, r2, offset); | 358 | return bType(0b1100011, 0b101, r1, r2, offset); |
| 357 | } | 359 | } |
| 358 | 360 | ||
| 359 | pub fn bltu(r1: Register, r2: Register, offset: u13) Instruction { | 361 | pub fn bltu(r1: Register, r2: Register, offset: i13) Instruction { |
| 360 | return bType(0b1100011, 0b110, r1, r2, offset); | 362 | return bType(0b1100011, 0b110, r1, r2, offset); |
| 361 | } | 363 | } |
| 362 | 364 | ||
| 363 | pub fn bgeu(r1: Register, r2: Register, offset: u13) Instruction { | 365 | pub fn bgeu(r1: Register, r2: Register, offset: i13) Instruction { |
| 364 | return bType(0b1100011, 0b111, r1, r2, offset); | 366 | return bType(0b1100011, 0b111, r1, r2, offset); |
| 365 | } | 367 | } |
| 366 | 368 | ||
| ... | @@ -431,3 +433,38 @@ pub const Register = enum(u5) { | ... | @@ -431,3 +433,38 @@ pub const Register = enum(u5) { |
| 431 | pub const callee_preserved_regs = [_]Register{ | 433 | pub const callee_preserved_regs = [_]Register{ |
| 432 | .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11, | 434 | .s0, .s1, .s2, .s3, .s4, .s5, .s6, .s7, .s8, .s9, .s10, .s11, |
| 433 | }; | 435 | }; |
| 436 | |||
| 437 | test "serialize instructions" { | ||
| 438 | const Testcase = struct { | ||
| 439 | inst: Instruction, | ||
| 440 | expected: u32, | ||
| 441 | }; | ||
| 442 | |||
| 443 | const testcases = [_]Testcase{ | ||
| 444 | .{ // add t6, zero, zero | ||
| 445 | .inst = Instruction.add(.t6, .zero, .zero), | ||
| 446 | .expected = 0b0000000_00000_00000_000_11111_0110011, | ||
| 447 | }, | ||
| 448 | .{ // sd s0, 0x7f(s0) | ||
| 449 | .inst = Instruction.sd(.s0, 0x7f, .s0), | ||
| 450 | .expected = 0b0000011_01000_01000_011_11111_0100011, | ||
| 451 | }, | ||
| 452 | .{ // bne s0, s1, 0x42 | ||
| 453 | .inst = Instruction.bne(.s0, .s1, 0x42), | ||
| 454 | .expected = 0b0_000010_01001_01000_001_0001_0_1100011, | ||
| 455 | }, | ||
| 456 | .{ // j 0x1a | ||
| 457 | .inst = Instruction.jal(.zero, 0x1a), | ||
| 458 | .expected = 0b0_0000001101_0_00000000_00000_1101111, | ||
| 459 | }, | ||
| 460 | .{ // ebreak | ||
| 461 | .inst = Instruction.ebreak, | ||
| 462 | .expected = 0b000000000001_00000_000_00000_1110011, | ||
| 463 | }, | ||
| 464 | }; | ||
| 465 | |||
| 466 | for (testcases) |case| { | ||
| 467 | const actual = case.inst.toU32(); | ||
| 468 | testing.expectEqual(case.expected, actual); | ||
| 469 | } | ||
| 470 | } |
src/libc_installation.zig+9-2| ... | @@ -9,6 +9,7 @@ const build_options = @import("build_options"); | ... | @@ -9,6 +9,7 @@ const build_options = @import("build_options"); |
| 9 | const is_darwin = Target.current.isDarwin(); | 9 | const is_darwin = Target.current.isDarwin(); |
| 10 | const is_windows = Target.current.os.tag == .windows; | 10 | const is_windows = Target.current.os.tag == .windows; |
| 11 | const is_gnu = Target.current.isGnu(); | 11 | const is_gnu = Target.current.isGnu(); |
| 12 | const is_haiku = Target.current.os.tag == .haiku; | ||
| 12 | 13 | ||
| 13 | const log = std.log.scoped(.libc_installation); | 14 | const log = std.log.scoped(.libc_installation); |
| 14 | 15 | ||
| ... | @@ -279,8 +280,14 @@ pub const LibCInstallation = struct { | ... | @@ -279,8 +280,14 @@ pub const LibCInstallation = struct { |
| 279 | return error.CCompilerCannotFindHeaders; | 280 | return error.CCompilerCannotFindHeaders; |
| 280 | } | 281 | } |
| 281 | 282 | ||
| 282 | const include_dir_example_file = "stdlib.h"; | 283 | const include_dir_example_file = if (is_haiku) "posix/stdlib.h" else "stdlib.h"; |
| 283 | const sys_include_dir_example_file = if (is_windows) "sys\\types.h" else "sys/errno.h"; | 284 | const sys_include_dir_example_file = if (is_windows) |
| 285 | "sys\\types.h" | ||
| 286 | else if (is_haiku) | ||
| 287 | "posix/errno.h" | ||
| 288 | else | ||
| 289 | "sys/errno.h" | ||
| 290 | ; | ||
| 284 | 291 | ||
| 285 | var path_i: usize = 0; | 292 | var path_i: usize = 0; |
| 286 | while (path_i < search_paths.items.len) : (path_i += 1) { | 293 | while (path_i < search_paths.items.len) : (path_i += 1) { |
src/register_manager.zig+43-50| ... | @@ -16,7 +16,7 @@ pub fn RegisterManager( | ... | @@ -16,7 +16,7 @@ pub fn RegisterManager( |
| 16 | ) type { | 16 | ) type { |
| 17 | return struct { | 17 | return struct { |
| 18 | /// The key must be canonical register. | 18 | /// The key must be canonical register. |
| 19 | registers: std.AutoHashMapUnmanaged(Register, *ir.Inst) = .{}, | 19 | registers: [callee_preserved_regs.len]?*ir.Inst = [_]?*ir.Inst{null} ** callee_preserved_regs.len, |
| 20 | free_registers: FreeRegInt = math.maxInt(FreeRegInt), | 20 | free_registers: FreeRegInt = math.maxInt(FreeRegInt), |
| 21 | /// Tracks all registers allocated in the course of this function | 21 | /// Tracks all registers allocated in the course of this function |
| 22 | allocated_registers: FreeRegInt = 0, | 22 | allocated_registers: FreeRegInt = 0, |
| ... | @@ -31,14 +31,6 @@ pub fn RegisterManager( | ... | @@ -31,14 +31,6 @@ pub fn RegisterManager( |
| 31 | return @fieldParentPtr(Function, "register_manager", self); | 31 | return @fieldParentPtr(Function, "register_manager", self); |
| 32 | } | 32 | } |
| 33 | 33 | ||
| 34 | pub fn deinit(self: *Self, allocator: *Allocator) void { | ||
| 35 | self.registers.deinit(allocator); | ||
| 36 | } | ||
| 37 | |||
| 38 | fn isTracked(reg: Register) bool { | ||
| 39 | return reg.allocIndex() != null; | ||
| 40 | } | ||
| 41 | |||
| 42 | fn markRegUsed(self: *Self, reg: Register) void { | 34 | fn markRegUsed(self: *Self, reg: Register) void { |
| 43 | if (FreeRegInt == u0) return; | 35 | if (FreeRegInt == u0) return; |
| 44 | const index = reg.allocIndex() orelse return; | 36 | const index = reg.allocIndex() orelse return; |
| ... | @@ -73,13 +65,13 @@ pub fn RegisterManager( | ... | @@ -73,13 +65,13 @@ pub fn RegisterManager( |
| 73 | return self.allocated_registers & @as(FreeRegInt, 1) << shift != 0; | 65 | return self.allocated_registers & @as(FreeRegInt, 1) << shift != 0; |
| 74 | } | 66 | } |
| 75 | 67 | ||
| 76 | /// Before calling, must ensureCapacity + count on self.registers. | ||
| 77 | /// Returns `null` if all registers are allocated. | 68 | /// Returns `null` if all registers are allocated. |
| 78 | pub fn tryAllocRegs(self: *Self, comptime count: comptime_int, insts: [count]*ir.Inst) ?[count]Register { | 69 | pub fn tryAllocRegs(self: *Self, comptime count: comptime_int, insts: [count]*ir.Inst) ?[count]Register { |
| 79 | if (self.tryAllocRegsWithoutTracking(count)) |regs| { | 70 | if (self.tryAllocRegsWithoutTracking(count)) |regs| { |
| 80 | for (regs) |reg, i| { | 71 | for (regs) |reg, i| { |
| 72 | const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null | ||
| 73 | self.registers[index] = insts[i]; | ||
| 81 | self.markRegUsed(reg); | 74 | self.markRegUsed(reg); |
| 82 | self.registers.putAssumeCapacityNoClobber(reg, insts[i]); | ||
| 83 | } | 75 | } |
| 84 | 76 | ||
| 85 | return regs; | 77 | return regs; |
| ... | @@ -88,13 +80,11 @@ pub fn RegisterManager( | ... | @@ -88,13 +80,11 @@ pub fn RegisterManager( |
| 88 | } | 80 | } |
| 89 | } | 81 | } |
| 90 | 82 | ||
| 91 | /// Before calling, must ensureCapacity + 1 on self.registers. | ||
| 92 | /// Returns `null` if all registers are allocated. | 83 | /// Returns `null` if all registers are allocated. |
| 93 | pub fn tryAllocReg(self: *Self, inst: *ir.Inst) ?Register { | 84 | pub fn tryAllocReg(self: *Self, inst: *ir.Inst) ?Register { |
| 94 | return if (tryAllocRegs(self, 1, .{inst})) |regs| regs[0] else null; | 85 | return if (tryAllocRegs(self, 1, .{inst})) |regs| regs[0] else null; |
| 95 | } | 86 | } |
| 96 | 87 | ||
| 97 | /// Before calling, must ensureCapacity + count on self.registers. | ||
| 98 | pub fn allocRegs(self: *Self, comptime count: comptime_int, insts: [count]*ir.Inst) ![count]Register { | 88 | pub fn allocRegs(self: *Self, comptime count: comptime_int, insts: [count]*ir.Inst) ![count]Register { |
| 99 | comptime assert(count > 0 and count <= callee_preserved_regs.len); | 89 | comptime assert(count > 0 and count <= callee_preserved_regs.len); |
| 100 | 90 | ||
| ... | @@ -106,24 +96,22 @@ pub fn RegisterManager( | ... | @@ -106,24 +96,22 @@ pub fn RegisterManager( |
| 106 | std.mem.copy(Register, &regs, callee_preserved_regs[0..count]); | 96 | std.mem.copy(Register, &regs, callee_preserved_regs[0..count]); |
| 107 | 97 | ||
| 108 | for (regs) |reg, i| { | 98 | for (regs) |reg, i| { |
| 99 | const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null | ||
| 109 | if (self.isRegFree(reg)) { | 100 | if (self.isRegFree(reg)) { |
| 110 | self.markRegUsed(reg); | 101 | self.markRegUsed(reg); |
| 111 | self.registers.putAssumeCapacityNoClobber(reg, insts[i]); | ||
| 112 | } else { | 102 | } else { |
| 113 | const regs_entry = self.registers.getEntry(reg).?; | 103 | const spilled_inst = self.registers[index].?; |
| 114 | const spilled_inst = regs_entry.value; | ||
| 115 | regs_entry.value = insts[i]; | ||
| 116 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); | 104 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); |
| 117 | } | 105 | } |
| 106 | self.registers[index] = insts[i]; | ||
| 118 | } | 107 | } |
| 119 | 108 | ||
| 120 | break :blk regs; | 109 | break :blk regs; |
| 121 | }; | 110 | }; |
| 122 | } | 111 | } |
| 123 | 112 | ||
| 124 | /// Before calling, must ensureCapacity + 1 on self.registers. | ||
| 125 | pub fn allocReg(self: *Self, inst: *ir.Inst) !Register { | 113 | pub fn allocReg(self: *Self, inst: *ir.Inst) !Register { |
| 126 | return (try allocRegs(self, 1, .{inst}))[0]; | 114 | return (try self.allocRegs(1, .{inst}))[0]; |
| 127 | } | 115 | } |
| 128 | 116 | ||
| 129 | /// Does not track the registers. | 117 | /// Does not track the registers. |
| ... | @@ -150,37 +138,48 @@ pub fn RegisterManager( | ... | @@ -150,37 +138,48 @@ pub fn RegisterManager( |
| 150 | /// Does not track the register. | 138 | /// Does not track the register. |
| 151 | /// Returns `null` if all registers are allocated. | 139 | /// Returns `null` if all registers are allocated. |
| 152 | pub fn tryAllocRegWithoutTracking(self: *Self) ?Register { | 140 | pub fn tryAllocRegWithoutTracking(self: *Self) ?Register { |
| 153 | return if (tryAllocRegsWithoutTracking(self, 1)) |regs| regs[0] else null; | 141 | return if (self.tryAllocRegsWithoutTracking(1)) |regs| regs[0] else null; |
| 154 | } | 142 | } |
| 155 | 143 | ||
| 156 | /// Does not track the register. | 144 | /// Does not track the registers |
| 157 | pub fn allocRegWithoutTracking(self: *Self) !Register { | 145 | pub fn allocRegsWithoutTracking(self: *Self, comptime count: comptime_int) ![count]Register { |
| 158 | return self.tryAllocRegWithoutTracking() orelse b: { | 146 | return self.tryAllocRegsWithoutTracking(count) orelse blk: { |
| 159 | // We'll take over the first register. Move the instruction that was previously | 147 | // We'll take over the first count registers. Spill |
| 160 | // there to a stack allocation. | 148 | // the instructions that were previously there to a |
| 161 | const reg = callee_preserved_regs[0]; | 149 | // stack allocations. |
| 162 | const regs_entry = self.registers.remove(reg).?; | 150 | var regs: [count]Register = undefined; |
| 163 | const spilled_inst = regs_entry.value; | 151 | std.mem.copy(Register, &regs, callee_preserved_regs[0..count]); |
| 164 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); | ||
| 165 | self.markRegFree(reg); | ||
| 166 | 152 | ||
| 167 | break :b reg; | 153 | for (regs) |reg, i| { |
| 154 | const index = reg.allocIndex().?; // allocIndex() on a callee-preserved reg should never return null | ||
| 155 | if (!self.isRegFree(reg)) { | ||
| 156 | const spilled_inst = self.registers[index].?; | ||
| 157 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); | ||
| 158 | self.registers[index] = null; | ||
| 159 | self.markRegFree(reg); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | |||
| 163 | break :blk regs; | ||
| 168 | }; | 164 | }; |
| 169 | } | 165 | } |
| 170 | 166 | ||
| 167 | /// Does not track the register. | ||
| 168 | pub fn allocRegWithoutTracking(self: *Self) !Register { | ||
| 169 | return (try self.allocRegsWithoutTracking(1))[0]; | ||
| 170 | } | ||
| 171 | |||
| 171 | /// Allocates the specified register with the specified | 172 | /// Allocates the specified register with the specified |
| 172 | /// instruction. Spills the register if it is currently | 173 | /// instruction. Spills the register if it is currently |
| 173 | /// allocated. | 174 | /// allocated. |
| 174 | /// Before calling, must ensureCapacity + 1 on self.registers. | ||
| 175 | pub fn getReg(self: *Self, reg: Register, inst: *ir.Inst) !void { | 175 | pub fn getReg(self: *Self, reg: Register, inst: *ir.Inst) !void { |
| 176 | if (!isTracked(reg)) return; | 176 | const index = reg.allocIndex() orelse return; |
| 177 | 177 | ||
| 178 | if (!self.isRegFree(reg)) { | 178 | if (!self.isRegFree(reg)) { |
| 179 | // Move the instruction that was previously there to a | 179 | // Move the instruction that was previously there to a |
| 180 | // stack allocation. | 180 | // stack allocation. |
| 181 | const regs_entry = self.registers.getEntry(reg).?; | 181 | const spilled_inst = self.registers[index].?; |
| 182 | const spilled_inst = regs_entry.value; | 182 | self.registers[index] = inst; |
| 183 | regs_entry.value = inst; | ||
| 184 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); | 183 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); |
| 185 | } else { | 184 | } else { |
| 186 | self.getRegAssumeFree(reg, inst); | 185 | self.getRegAssumeFree(reg, inst); |
| ... | @@ -190,34 +189,33 @@ pub fn RegisterManager( | ... | @@ -190,34 +189,33 @@ pub fn RegisterManager( |
| 190 | /// Spills the register if it is currently allocated. | 189 | /// Spills the register if it is currently allocated. |
| 191 | /// Does not track the register. | 190 | /// Does not track the register. |
| 192 | pub fn getRegWithoutTracking(self: *Self, reg: Register) !void { | 191 | pub fn getRegWithoutTracking(self: *Self, reg: Register) !void { |
| 193 | if (!isTracked(reg)) return; | 192 | const index = reg.allocIndex() orelse return; |
| 194 | 193 | ||
| 195 | if (!self.isRegFree(reg)) { | 194 | if (!self.isRegFree(reg)) { |
| 196 | // Move the instruction that was previously there to a | 195 | // Move the instruction that was previously there to a |
| 197 | // stack allocation. | 196 | // stack allocation. |
| 198 | const regs_entry = self.registers.remove(reg).?; | 197 | const spilled_inst = self.registers[index].?; |
| 199 | const spilled_inst = regs_entry.value; | ||
| 200 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); | 198 | try self.getFunction().spillInstruction(spilled_inst.src, reg, spilled_inst); |
| 201 | self.markRegFree(reg); | 199 | self.markRegFree(reg); |
| 202 | } | 200 | } |
| 203 | } | 201 | } |
| 204 | 202 | ||
| 205 | /// Allocates the specified register with the specified | 203 | /// Allocates the specified register with the specified |
| 206 | /// instruction. Assumes that the register is free and no | 204 | /// instruction. Asserts that the register is free and no |
| 207 | /// spilling is necessary. | 205 | /// spilling is necessary. |
| 208 | /// Before calling, must ensureCapacity + 1 on self.registers. | ||
| 209 | pub fn getRegAssumeFree(self: *Self, reg: Register, inst: *ir.Inst) void { | 206 | pub fn getRegAssumeFree(self: *Self, reg: Register, inst: *ir.Inst) void { |
| 210 | if (!isTracked(reg)) return; | 207 | const index = reg.allocIndex() orelse return; |
| 211 | 208 | ||
| 212 | self.registers.putAssumeCapacityNoClobber(reg, inst); | 209 | assert(self.registers[index] == null); |
| 210 | self.registers[index] = inst; | ||
| 213 | self.markRegUsed(reg); | 211 | self.markRegUsed(reg); |
| 214 | } | 212 | } |
| 215 | 213 | ||
| 216 | /// Marks the specified register as free | 214 | /// Marks the specified register as free |
| 217 | pub fn freeReg(self: *Self, reg: Register) void { | 215 | pub fn freeReg(self: *Self, reg: Register) void { |
| 218 | if (!isTracked(reg)) return; | 216 | const index = reg.allocIndex() orelse return; |
| 219 | 217 | ||
| 220 | _ = self.registers.remove(reg); | 218 | self.registers[index] = null; |
| 221 | self.markRegFree(reg); | 219 | self.markRegFree(reg); |
| 222 | } | 220 | } |
| 223 | }; | 221 | }; |
| ... | @@ -247,7 +245,6 @@ const MockFunction = struct { | ... | @@ -247,7 +245,6 @@ const MockFunction = struct { |
| 247 | const Self = @This(); | 245 | const Self = @This(); |
| 248 | 246 | ||
| 249 | pub fn deinit(self: *Self) void { | 247 | pub fn deinit(self: *Self) void { |
| 250 | self.register_manager.deinit(self.allocator); | ||
| 251 | self.spilled.deinit(self.allocator); | 248 | self.spilled.deinit(self.allocator); |
| 252 | } | 249 | } |
| 253 | 250 | ||
| ... | @@ -273,7 +270,6 @@ test "tryAllocReg: no spilling" { | ... | @@ -273,7 +270,6 @@ test "tryAllocReg: no spilling" { |
| 273 | std.testing.expect(!function.register_manager.isRegAllocated(.r2)); | 270 | std.testing.expect(!function.register_manager.isRegAllocated(.r2)); |
| 274 | std.testing.expect(!function.register_manager.isRegAllocated(.r3)); | 271 | std.testing.expect(!function.register_manager.isRegAllocated(.r3)); |
| 275 | 272 | ||
| 276 | try function.register_manager.registers.ensureCapacity(allocator, function.register_manager.registers.count() + 2); | ||
| 277 | std.testing.expectEqual(@as(?MockRegister, .r2), function.register_manager.tryAllocReg(&mock_instruction)); | 273 | std.testing.expectEqual(@as(?MockRegister, .r2), function.register_manager.tryAllocReg(&mock_instruction)); |
| 278 | std.testing.expectEqual(@as(?MockRegister, .r3), function.register_manager.tryAllocReg(&mock_instruction)); | 274 | std.testing.expectEqual(@as(?MockRegister, .r3), function.register_manager.tryAllocReg(&mock_instruction)); |
| 279 | std.testing.expectEqual(@as(?MockRegister, null), function.register_manager.tryAllocReg(&mock_instruction)); | 275 | std.testing.expectEqual(@as(?MockRegister, null), function.register_manager.tryAllocReg(&mock_instruction)); |
| ... | @@ -305,7 +301,6 @@ test "allocReg: spilling" { | ... | @@ -305,7 +301,6 @@ test "allocReg: spilling" { |
| 305 | std.testing.expect(!function.register_manager.isRegAllocated(.r2)); | 301 | std.testing.expect(!function.register_manager.isRegAllocated(.r2)); |
| 306 | std.testing.expect(!function.register_manager.isRegAllocated(.r3)); | 302 | std.testing.expect(!function.register_manager.isRegAllocated(.r3)); |
| 307 | 303 | ||
| 308 | try function.register_manager.registers.ensureCapacity(allocator, function.register_manager.registers.count() + 2); | ||
| 309 | std.testing.expectEqual(@as(?MockRegister, .r2), try function.register_manager.allocReg(&mock_instruction)); | 304 | std.testing.expectEqual(@as(?MockRegister, .r2), try function.register_manager.allocReg(&mock_instruction)); |
| 310 | std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction)); | 305 | std.testing.expectEqual(@as(?MockRegister, .r3), try function.register_manager.allocReg(&mock_instruction)); |
| 311 | 306 | ||
| ... | @@ -336,14 +331,12 @@ test "getReg" { | ... | @@ -336,14 +331,12 @@ test "getReg" { |
| 336 | std.testing.expect(!function.register_manager.isRegAllocated(.r2)); | 331 | std.testing.expect(!function.register_manager.isRegAllocated(.r2)); |
| 337 | std.testing.expect(!function.register_manager.isRegAllocated(.r3)); | 332 | std.testing.expect(!function.register_manager.isRegAllocated(.r3)); |
| 338 | 333 | ||
| 339 | try function.register_manager.registers.ensureCapacity(allocator, function.register_manager.registers.count() + 2); | ||
| 340 | try function.register_manager.getReg(.r3, &mock_instruction); | 334 | try function.register_manager.getReg(.r3, &mock_instruction); |
| 341 | 335 | ||
| 342 | std.testing.expect(!function.register_manager.isRegAllocated(.r2)); | 336 | std.testing.expect(!function.register_manager.isRegAllocated(.r2)); |
| 343 | std.testing.expect(function.register_manager.isRegAllocated(.r3)); | 337 | std.testing.expect(function.register_manager.isRegAllocated(.r3)); |
| 344 | 338 | ||
| 345 | // Spill r3 | 339 | // Spill r3 |
| 346 | try function.register_manager.registers.ensureCapacity(allocator, function.register_manager.registers.count() + 2); | ||
| 347 | try function.register_manager.getReg(.r3, &mock_instruction); | 340 | try function.register_manager.getReg(.r3, &mock_instruction); |
| 348 | 341 | ||
| 349 | std.testing.expect(!function.register_manager.isRegAllocated(.r2)); | 342 | std.testing.expect(!function.register_manager.isRegAllocated(.r2)); |
src/stage1/all_types.hpp+1| ... | @@ -84,6 +84,7 @@ enum CallingConvention { | ... | @@ -84,6 +84,7 @@ enum CallingConvention { |
| 84 | CallingConventionAPCS, | 84 | CallingConventionAPCS, |
| 85 | CallingConventionAAPCS, | 85 | CallingConventionAAPCS, |
| 86 | CallingConventionAAPCSVFP, | 86 | CallingConventionAAPCSVFP, |
| 87 | CallingConventionSysV | ||
| 87 | }; | 88 | }; |
| 88 | 89 | ||
| 89 | // This one corresponds to the builtin.zig enum. | 90 | // This one corresponds to the builtin.zig enum. |
src/stage1/analyze.cpp+14-10| ... | @@ -974,6 +974,7 @@ const char *calling_convention_name(CallingConvention cc) { | ... | @@ -974,6 +974,7 @@ const char *calling_convention_name(CallingConvention cc) { |
| 974 | case CallingConventionAAPCS: return "AAPCS"; | 974 | case CallingConventionAAPCS: return "AAPCS"; |
| 975 | case CallingConventionAAPCSVFP: return "AAPCSVFP"; | 975 | case CallingConventionAAPCSVFP: return "AAPCSVFP"; |
| 976 | case CallingConventionInline: return "Inline"; | 976 | case CallingConventionInline: return "Inline"; |
| 977 | case CallingConventionSysV: return "SysV"; | ||
| 977 | } | 978 | } |
| 978 | zig_unreachable(); | 979 | zig_unreachable(); |
| 979 | } | 980 | } |
| ... | @@ -995,6 +996,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) { | ... | @@ -995,6 +996,7 @@ bool calling_convention_allows_zig_types(CallingConvention cc) { |
| 995 | case CallingConventionAPCS: | 996 | case CallingConventionAPCS: |
| 996 | case CallingConventionAAPCS: | 997 | case CallingConventionAAPCS: |
| 997 | case CallingConventionAAPCSVFP: | 998 | case CallingConventionAAPCSVFP: |
| 999 | case CallingConventionSysV: | ||
| 998 | return false; | 1000 | return false; |
| 999 | } | 1001 | } |
| 1000 | zig_unreachable(); | 1002 | zig_unreachable(); |
| ... | @@ -1969,6 +1971,10 @@ Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_ | ... | @@ -1969,6 +1971,10 @@ Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_ |
| 1969 | case CallingConventionAAPCSVFP: | 1971 | case CallingConventionAAPCSVFP: |
| 1970 | if (!target_is_arm(g->zig_target)) | 1972 | if (!target_is_arm(g->zig_target)) |
| 1971 | allowed_platforms = "ARM"; | 1973 | allowed_platforms = "ARM"; |
| 1974 | break; | ||
| 1975 | case CallingConventionSysV: | ||
| 1976 | if (g->zig_target->arch != ZigLLVM_x86_64) | ||
| 1977 | allowed_platforms = "x86_64"; | ||
| 1972 | } | 1978 | } |
| 1973 | if (allowed_platforms != nullptr) { | 1979 | if (allowed_platforms != nullptr) { |
| 1974 | add_node_error(g, source_node, buf_sprintf( | 1980 | add_node_error(g, source_node, buf_sprintf( |
| ... | @@ -3805,6 +3811,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { | ... | @@ -3805,6 +3811,7 @@ static void resolve_decl_fn(CodeGen *g, TldFn *tld_fn) { |
| 3805 | case CallingConventionAPCS: | 3811 | case CallingConventionAPCS: |
| 3806 | case CallingConventionAAPCS: | 3812 | case CallingConventionAAPCS: |
| 3807 | case CallingConventionAAPCSVFP: | 3813 | case CallingConventionAAPCSVFP: |
| 3814 | case CallingConventionSysV: | ||
| 3808 | add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), | 3815 | add_fn_export(g, fn_table_entry, buf_ptr(&fn_table_entry->symbol_name), |
| 3809 | GlobalLinkageIdStrong, fn_cc); | 3816 | GlobalLinkageIdStrong, fn_cc); |
| 3810 | break; | 3817 | break; |
| ... | @@ -4769,11 +4776,11 @@ Error type_is_nonnull_ptr2(CodeGen *g, ZigType *type, bool *result) { | ... | @@ -4769,11 +4776,11 @@ Error type_is_nonnull_ptr2(CodeGen *g, ZigType *type, bool *result) { |
| 4769 | return ErrorNone; | 4776 | return ErrorNone; |
| 4770 | } | 4777 | } |
| 4771 | 4778 | ||
| 4772 | static uint32_t get_async_frame_align_bytes(CodeGen *g) { | 4779 | uint32_t get_async_frame_align_bytes(CodeGen *g) { |
| 4773 | uint32_t a = g->pointer_size_bytes * 2; | 4780 | // Due to how the frame structure is built the minimum alignment is the one |
| 4774 | // promises have at least alignment 8 so that we can have 3 extra bits when doing atomicrmw | 4781 | // of a usize (or pointer). |
| 4775 | if (a < 8) a = 8; | 4782 | // label (grep this): [fn_frame_struct_layout] |
| 4776 | return a; | 4783 | return max(g->builtin_types.entry_usize->abi_align, target_fn_align(g->zig_target)); |
| 4777 | } | 4784 | } |
| 4778 | 4785 | ||
| 4779 | uint32_t get_ptr_align(CodeGen *g, ZigType *type) { | 4786 | uint32_t get_ptr_align(CodeGen *g, ZigType *type) { |
| ... | @@ -4789,11 +4796,8 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) { | ... | @@ -4789,11 +4796,8 @@ uint32_t get_ptr_align(CodeGen *g, ZigType *type) { |
| 4789 | return (ptr_type->data.pointer.explicit_alignment == 0) ? | 4796 | return (ptr_type->data.pointer.explicit_alignment == 0) ? |
| 4790 | get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment; | 4797 | get_abi_alignment(g, ptr_type->data.pointer.child_type) : ptr_type->data.pointer.explicit_alignment; |
| 4791 | } else if (ptr_type->id == ZigTypeIdFn) { | 4798 | } else if (ptr_type->id == ZigTypeIdFn) { |
| 4792 | // I tried making this use LLVMABIAlignmentOfType but it trips this assertion in LLVM: | 4799 | return (ptr_type->data.fn.fn_type_id.alignment == 0) ? |
| 4793 | // "Cannot getTypeInfo() on a type that is unsized!" | 4800 | target_fn_ptr_align(g->zig_target) : ptr_type->data.fn.fn_type_id.alignment; |
| 4794 | // when getting the alignment of `?fn() callconv(.C) void`. | ||
| 4795 | // See http://lists.llvm.org/pipermail/llvm-dev/2018-September/126142.html | ||
| 4796 | return (ptr_type->data.fn.fn_type_id.alignment == 0) ? 1 : ptr_type->data.fn.fn_type_id.alignment; | ||
| 4797 | } else if (ptr_type->id == ZigTypeIdAnyFrame) { | 4801 | } else if (ptr_type->id == ZigTypeIdAnyFrame) { |
| 4798 | return get_async_frame_align_bytes(g); | 4802 | return get_async_frame_align_bytes(g); |
| 4799 | } else { | 4803 | } else { |
src/stage1/analyze.hpp+1| ... | @@ -47,6 +47,7 @@ ZigType *get_test_fn_type(CodeGen *g); | ... | @@ -47,6 +47,7 @@ ZigType *get_test_fn_type(CodeGen *g); |
| 47 | ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type); | 47 | ZigType *get_any_frame_type(CodeGen *g, ZigType *result_type); |
| 48 | bool handle_is_ptr(CodeGen *g, ZigType *type_entry); | 48 | bool handle_is_ptr(CodeGen *g, ZigType *type_entry); |
| 49 | Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_node, CallingConvention cc); | 49 | Error emit_error_unless_callconv_allowed_for_target(CodeGen *g, AstNode *source_node, CallingConvention cc); |
| 50 | uint32_t get_async_frame_align_bytes(CodeGen *g); | ||
| 50 | 51 | ||
| 51 | bool type_has_bits(CodeGen *g, ZigType *type_entry); | 52 | bool type_has_bits(CodeGen *g, ZigType *type_entry); |
| 52 | Error type_has_bits2(CodeGen *g, ZigType *type_entry, bool *result); | 53 | Error type_has_bits2(CodeGen *g, ZigType *type_entry, bool *result); |
src/stage1/codegen.cpp+5| ... | @@ -204,6 +204,9 @@ static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) { | ... | @@ -204,6 +204,9 @@ static ZigLLVM_CallingConv get_llvm_cc(CodeGen *g, CallingConvention cc) { |
| 204 | case CallingConventionSignal: | 204 | case CallingConventionSignal: |
| 205 | assert(g->zig_target->arch == ZigLLVM_avr); | 205 | assert(g->zig_target->arch == ZigLLVM_avr); |
| 206 | return ZigLLVM_AVR_SIGNAL; | 206 | return ZigLLVM_AVR_SIGNAL; |
| 207 | case CallingConventionSysV: | ||
| 208 | assert(g->zig_target->arch == ZigLLVM_x86_64); | ||
| 209 | return ZigLLVM_X86_64_SysV; | ||
| 207 | } | 210 | } |
| 208 | zig_unreachable(); | 211 | zig_unreachable(); |
| 209 | } | 212 | } |
| ... | @@ -348,6 +351,7 @@ static bool cc_want_sret_attr(CallingConvention cc) { | ... | @@ -348,6 +351,7 @@ static bool cc_want_sret_attr(CallingConvention cc) { |
| 348 | case CallingConventionAPCS: | 351 | case CallingConventionAPCS: |
| 349 | case CallingConventionAAPCS: | 352 | case CallingConventionAAPCS: |
| 350 | case CallingConventionAAPCSVFP: | 353 | case CallingConventionAAPCSVFP: |
| 354 | case CallingConventionSysV: | ||
| 351 | return true; | 355 | return true; |
| 352 | case CallingConventionAsync: | 356 | case CallingConventionAsync: |
| 353 | case CallingConventionUnspecified: | 357 | case CallingConventionUnspecified: |
| ... | @@ -9079,6 +9083,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { | ... | @@ -9079,6 +9083,7 @@ Buf *codegen_generate_builtin_source(CodeGen *g) { |
| 9079 | static_assert(CallingConventionAPCS == 11, ""); | 9083 | static_assert(CallingConventionAPCS == 11, ""); |
| 9080 | static_assert(CallingConventionAAPCS == 12, ""); | 9084 | static_assert(CallingConventionAAPCS == 12, ""); |
| 9081 | static_assert(CallingConventionAAPCSVFP == 13, ""); | 9085 | static_assert(CallingConventionAAPCSVFP == 13, ""); |
| 9086 | static_assert(CallingConventionSysV == 14, ""); | ||
| 9082 | 9087 | ||
| 9083 | static_assert(BuiltinPtrSizeOne == 0, ""); | 9088 | static_assert(BuiltinPtrSizeOne == 0, ""); |
| 9084 | static_assert(BuiltinPtrSizeMany == 1, ""); | 9089 | static_assert(BuiltinPtrSizeMany == 1, ""); |
src/stage1/ir.cpp+9-4| ... | @@ -19216,6 +19216,7 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport | ... | @@ -19216,6 +19216,7 @@ static IrInstGen *ir_analyze_instruction_export(IrAnalyze *ira, IrInstSrcExport |
| 19216 | case CallingConventionAPCS: | 19216 | case CallingConventionAPCS: |
| 19217 | case CallingConventionAAPCS: | 19217 | case CallingConventionAAPCS: |
| 19218 | case CallingConventionAAPCSVFP: | 19218 | case CallingConventionAAPCSVFP: |
| 19219 | case CallingConventionSysV: | ||
| 19219 | add_fn_export(ira->codegen, fn_entry, buf_ptr(symbol_name), global_linkage_id, cc); | 19220 | add_fn_export(ira->codegen, fn_entry, buf_ptr(symbol_name), global_linkage_id, cc); |
| 19220 | fn_entry->section_name = section_name; | 19221 | fn_entry->section_name = section_name; |
| 19221 | break; | 19222 | break; |
| ... | @@ -20659,8 +20660,12 @@ static IrInstGen *analyze_casted_new_stack(IrAnalyze *ira, IrInst* source_instr, | ... | @@ -20659,8 +20660,12 @@ static IrInstGen *analyze_casted_new_stack(IrAnalyze *ira, IrInst* source_instr, |
| 20659 | get_fn_frame_type(ira->codegen, fn_entry), false); | 20660 | get_fn_frame_type(ira->codegen, fn_entry), false); |
| 20660 | return ir_implicit_cast(ira, new_stack, needed_frame_type); | 20661 | return ir_implicit_cast(ira, new_stack, needed_frame_type); |
| 20661 | } else { | 20662 | } else { |
| 20663 | // XXX The stack alignment is hardcoded to 16 here and in | ||
| 20664 | // std.Target.stack_align. | ||
| 20665 | const uint32_t required_align = is_async_call_builtin ? | ||
| 20666 | get_async_frame_align_bytes(ira->codegen) : 16; | ||
| 20662 | ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, | 20667 | ZigType *u8_ptr = get_pointer_to_type_extra(ira->codegen, ira->codegen->builtin_types.entry_u8, |
| 20663 | false, false, PtrLenUnknown, target_fn_align(ira->codegen->zig_target), 0, 0, false); | 20668 | false, false, PtrLenUnknown, required_align, 0, 0, false); |
| 20664 | ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); | 20669 | ZigType *u8_slice = get_slice_type(ira->codegen, u8_ptr); |
| 20665 | ira->codegen->need_frame_size_prefix_data = true; | 20670 | ira->codegen->need_frame_size_prefix_data = true; |
| 20666 | return ir_implicit_cast2(ira, new_stack_src, new_stack, u8_slice); | 20671 | return ir_implicit_cast2(ira, new_stack_src, new_stack, u8_slice); |
| ... | @@ -26079,11 +26084,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy | ... | @@ -26079,11 +26084,11 @@ static Error ir_make_type_info_value(IrAnalyze *ira, IrInst* source_instr, ZigTy |
| 26079 | fields[0]->special = ConstValSpecialStatic; | 26084 | fields[0]->special = ConstValSpecialStatic; |
| 26080 | fields[0]->type = get_builtin_type(ira->codegen, "CallingConvention"); | 26085 | fields[0]->type = get_builtin_type(ira->codegen, "CallingConvention"); |
| 26081 | bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.fn.fn_type_id.cc); | 26086 | bigint_init_unsigned(&fields[0]->data.x_enum_tag, type_entry->data.fn.fn_type_id.cc); |
| 26082 | // alignment: u29 | 26087 | // alignment: comptime_int |
| 26083 | ensure_field_index(result->type, "alignment", 1); | 26088 | ensure_field_index(result->type, "alignment", 1); |
| 26084 | fields[1]->special = ConstValSpecialStatic; | 26089 | fields[1]->special = ConstValSpecialStatic; |
| 26085 | fields[1]->type = ira->codegen->builtin_types.entry_num_lit_int; | 26090 | fields[1]->type = ira->codegen->builtin_types.entry_num_lit_int; |
| 26086 | bigint_init_unsigned(&fields[1]->data.x_bigint, type_entry->data.fn.fn_type_id.alignment); | 26091 | bigint_init_unsigned(&fields[1]->data.x_bigint, get_ptr_align(ira->codegen, type_entry)); |
| 26087 | // is_generic: bool | 26092 | // is_generic: bool |
| 26088 | ensure_field_index(result->type, "is_generic", 2); | 26093 | ensure_field_index(result->type, "is_generic", 2); |
| 26089 | bool is_generic = type_entry->data.fn.is_generic; | 26094 | bool is_generic = type_entry->data.fn.is_generic; |
| ... | @@ -30095,7 +30100,7 @@ static IrInstGen *ir_align_cast(IrAnalyze *ira, IrInstGen *target, uint32_t alig | ... | @@ -30095,7 +30100,7 @@ static IrInstGen *ir_align_cast(IrAnalyze *ira, IrInstGen *target, uint32_t alig |
| 30095 | fn_type_id.alignment = align_bytes; | 30100 | fn_type_id.alignment = align_bytes; |
| 30096 | result_type = get_fn_type(ira->codegen, &fn_type_id); | 30101 | result_type = get_fn_type(ira->codegen, &fn_type_id); |
| 30097 | } else if (target_type->id == ZigTypeIdAnyFrame) { | 30102 | } else if (target_type->id == ZigTypeIdAnyFrame) { |
| 30098 | if (align_bytes >= target_fn_align(ira->codegen->zig_target)) { | 30103 | if (align_bytes >= get_async_frame_align_bytes(ira->codegen)) { |
| 30099 | result_type = target_type; | 30104 | result_type = target_type; |
| 30100 | } else { | 30105 | } else { |
| 30101 | ir_add_error(ira, &target->base, buf_sprintf("sub-aligned anyframe not allowed")); | 30106 | ir_add_error(ira, &target->base, buf_sprintf("sub-aligned anyframe not allowed")); |
src/stage1/target.cpp+32-1| ... | @@ -1253,6 +1253,37 @@ bool target_is_ppc(const ZigTarget *target) { | ... | @@ -1253,6 +1253,37 @@ bool target_is_ppc(const ZigTarget *target) { |
| 1253 | target->arch == ZigLLVM_ppc64le; | 1253 | target->arch == ZigLLVM_ppc64le; |
| 1254 | } | 1254 | } |
| 1255 | 1255 | ||
| 1256 | // Returns the minimum alignment for every function pointer on the given | ||
| 1257 | // architecture. | ||
| 1258 | unsigned target_fn_ptr_align(const ZigTarget *target) { | ||
| 1259 | // TODO This is a pessimization but is always correct. | ||
| 1260 | return 1; | ||
| 1261 | } | ||
| 1262 | |||
| 1263 | // Returns the minimum alignment for every function on the given architecture. | ||
| 1256 | unsigned target_fn_align(const ZigTarget *target) { | 1264 | unsigned target_fn_align(const ZigTarget *target) { |
| 1257 | return 16; | 1265 | switch (target->arch) { |
| 1266 | case ZigLLVM_riscv32: | ||
| 1267 | case ZigLLVM_riscv64: | ||
| 1268 | // TODO If the C extension is not present the value is 4. | ||
| 1269 | return 2; | ||
| 1270 | case ZigLLVM_ppc: | ||
| 1271 | case ZigLLVM_ppcle: | ||
| 1272 | case ZigLLVM_ppc64: | ||
| 1273 | case ZigLLVM_ppc64le: | ||
| 1274 | case ZigLLVM_aarch64: | ||
| 1275 | case ZigLLVM_aarch64_be: | ||
| 1276 | case ZigLLVM_aarch64_32: | ||
| 1277 | case ZigLLVM_sparc: | ||
| 1278 | case ZigLLVM_sparcel: | ||
| 1279 | case ZigLLVM_sparcv9: | ||
| 1280 | case ZigLLVM_mips: | ||
| 1281 | case ZigLLVM_mipsel: | ||
| 1282 | case ZigLLVM_mips64: | ||
| 1283 | case ZigLLVM_mips64el: | ||
| 1284 | return 4; | ||
| 1285 | |||
| 1286 | default: | ||
| 1287 | return 1; | ||
| 1288 | } | ||
| 1258 | } | 1289 | } |
src/stage1/target.hpp+1| ... | @@ -98,6 +98,7 @@ size_t target_libc_count(void); | ... | @@ -98,6 +98,7 @@ size_t target_libc_count(void); |
| 98 | void target_libc_enum(size_t index, ZigTarget *out_target); | 98 | void target_libc_enum(size_t index, ZigTarget *out_target); |
| 99 | bool target_libc_needs_crti_crtn(const ZigTarget *target); | 99 | bool target_libc_needs_crti_crtn(const ZigTarget *target); |
| 100 | 100 | ||
| 101 | unsigned target_fn_ptr_align(const ZigTarget *target); | ||
| 101 | unsigned target_fn_align(const ZigTarget *target); | 102 | unsigned target_fn_align(const ZigTarget *target); |
| 102 | 103 | ||
| 103 | #endif | 104 | #endif |
src/translate_c.zig+27-12| ... | @@ -8,6 +8,7 @@ const ctok = std.c.tokenizer; | ... | @@ -8,6 +8,7 @@ const ctok = std.c.tokenizer; |
| 8 | const CToken = std.c.Token; | 8 | const CToken = std.c.Token; |
| 9 | const mem = std.mem; | 9 | const mem = std.mem; |
| 10 | const math = std.math; | 10 | const math = std.math; |
| 11 | const meta = std.meta; | ||
| 11 | const ast = @import("translate_c/ast.zig"); | 12 | const ast = @import("translate_c/ast.zig"); |
| 12 | const Node = ast.Node; | 13 | const Node = ast.Node; |
| 13 | const Tag = Node.Tag; | 14 | const Tag = Node.Tag; |
| ... | @@ -1741,7 +1742,7 @@ fn transImplicitCastExpr( | ... | @@ -1741,7 +1742,7 @@ fn transImplicitCastExpr( |
| 1741 | } | 1742 | } |
| 1742 | 1743 | ||
| 1743 | fn isBuiltinDefined(name: []const u8) bool { | 1744 | fn isBuiltinDefined(name: []const u8) bool { |
| 1744 | inline for (std.meta.declarations(c_builtins)) |decl| { | 1745 | inline for (meta.declarations(c_builtins)) |decl| { |
| 1745 | if (std.mem.eql(u8, name, decl.name)) return true; | 1746 | if (std.mem.eql(u8, name, decl.name)) return true; |
| 1746 | } | 1747 | } |
| 1747 | return false; | 1748 | return false; |
| ... | @@ -3157,7 +3158,7 @@ const ClangFunctionType = union(enum) { | ... | @@ -3157,7 +3158,7 @@ const ClangFunctionType = union(enum) { |
| 3157 | NoProto: *const clang.FunctionType, | 3158 | NoProto: *const clang.FunctionType, |
| 3158 | 3159 | ||
| 3159 | fn getReturnType(self: @This()) clang.QualType { | 3160 | fn getReturnType(self: @This()) clang.QualType { |
| 3160 | switch (@as(std.meta.Tag(@This()), self)) { | 3161 | switch (@as(meta.Tag(@This()), self)) { |
| 3161 | .Proto => return self.Proto.getReturnType(), | 3162 | .Proto => return self.Proto.getReturnType(), |
| 3162 | .NoProto => return self.NoProto.getReturnType(), | 3163 | .NoProto => return self.NoProto.getReturnType(), |
| 3163 | } | 3164 | } |
| ... | @@ -3539,7 +3540,7 @@ fn transCPtrCast( | ... | @@ -3539,7 +3540,7 @@ fn transCPtrCast( |
| 3539 | expr | 3540 | expr |
| 3540 | else blk: { | 3541 | else blk: { |
| 3541 | const child_type_node = try transQualType(c, scope, child_type, loc); | 3542 | const child_type_node = try transQualType(c, scope, child_type, loc); |
| 3542 | const alignof = try Tag.alignof.create(c.arena, child_type_node); | 3543 | const alignof = try Tag.std_meta_alignment.create(c.arena, child_type_node); |
| 3543 | const align_cast = try Tag.align_cast.create(c.arena, .{ .lhs = alignof, .rhs = expr }); | 3544 | const align_cast = try Tag.align_cast.create(c.arena, .{ .lhs = alignof, .rhs = expr }); |
| 3544 | break :blk align_cast; | 3545 | break :blk align_cast; |
| 3545 | }; | 3546 | }; |
| ... | @@ -3547,9 +3548,22 @@ fn transCPtrCast( | ... | @@ -3547,9 +3548,22 @@ fn transCPtrCast( |
| 3547 | } | 3548 | } |
| 3548 | } | 3549 | } |
| 3549 | 3550 | ||
| 3550 | fn transFloatingLiteral(c: *Context, scope: *Scope, stmt: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node { | 3551 | fn transFloatingLiteral(c: *Context, scope: *Scope, expr: *const clang.FloatingLiteral, used: ResultUsed) TransError!Node { |
| 3552 | switch (expr.getRawSemantics()) { | ||
| 3553 | .IEEEhalf, // f16 | ||
| 3554 | .IEEEsingle, // f32 | ||
| 3555 | .IEEEdouble, // f64 | ||
| 3556 | => {}, | ||
| 3557 | else => |format| return fail( | ||
| 3558 | c, | ||
| 3559 | error.UnsupportedTranslation, | ||
| 3560 | expr.getBeginLoc(), | ||
| 3561 | "unsupported floating point constant format {}", | ||
| 3562 | .{format}, | ||
| 3563 | ), | ||
| 3564 | } | ||
| 3551 | // TODO use something more accurate | 3565 | // TODO use something more accurate |
| 3552 | var dbl = stmt.getValueAsApproximateDouble(); | 3566 | var dbl = expr.getValueAsApproximateDouble(); |
| 3553 | const is_negative = dbl < 0; | 3567 | const is_negative = dbl < 0; |
| 3554 | if (is_negative) dbl = -dbl; | 3568 | if (is_negative) dbl = -dbl; |
| 3555 | const str = if (dbl == std.math.floor(dbl)) | 3569 | const str = if (dbl == std.math.floor(dbl)) |
| ... | @@ -4093,7 +4107,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node { | ... | @@ -4093,7 +4107,7 @@ fn transCreateNodeAPInt(c: *Context, int: *const clang.APSInt) !Node { |
| 4093 | } | 4107 | } |
| 4094 | 4108 | ||
| 4095 | fn transCreateNodeNumber(c: *Context, num: anytype, num_kind: enum { int, float }) !Node { | 4109 | fn transCreateNodeNumber(c: *Context, num: anytype, num_kind: enum { int, float }) !Node { |
| 4096 | const fmt_s = if (comptime std.meta.trait.isNumber(@TypeOf(num))) "{d}" else "{s}"; | 4110 | const fmt_s = if (comptime meta.trait.isNumber(@TypeOf(num))) "{d}" else "{s}"; |
| 4097 | const str = try std.fmt.allocPrint(c.arena, fmt_s, .{num}); | 4111 | const str = try std.fmt.allocPrint(c.arena, fmt_s, .{num}); |
| 4098 | if (num_kind == .float) | 4112 | if (num_kind == .float) |
| 4099 | return Tag.float_literal.create(c.arena, str) | 4113 | return Tag.float_literal.create(c.arena, str) |
| ... | @@ -4402,6 +4416,7 @@ fn transCC( | ... | @@ -4402,6 +4416,7 @@ fn transCC( |
| 4402 | .X86ThisCall => return CallingConvention.Thiscall, | 4416 | .X86ThisCall => return CallingConvention.Thiscall, |
| 4403 | .AAPCS => return CallingConvention.AAPCS, | 4417 | .AAPCS => return CallingConvention.AAPCS, |
| 4404 | .AAPCS_VFP => return CallingConvention.AAPCSVFP, | 4418 | .AAPCS_VFP => return CallingConvention.AAPCSVFP, |
| 4419 | .X86_64SysV => return CallingConvention.SysV, | ||
| 4405 | else => return fail( | 4420 | else => return fail( |
| 4406 | c, | 4421 | c, |
| 4407 | error.UnsupportedType, | 4422 | error.UnsupportedType, |
| ... | @@ -4848,12 +4863,12 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node { | ... | @@ -4848,12 +4863,12 @@ fn parseCNumLit(c: *Context, m: *MacroCtx) ParseError!Node { |
| 4848 | // make the output less noisy by skipping promoteIntLiteral where | 4863 | // make the output less noisy by skipping promoteIntLiteral where |
| 4849 | // it's guaranteed to not be required because of C standard type constraints | 4864 | // it's guaranteed to not be required because of C standard type constraints |
| 4850 | const guaranteed_to_fit = switch (suffix) { | 4865 | const guaranteed_to_fit = switch (suffix) { |
| 4851 | .none => if (math.cast(i16, value)) |_| true else |_| false, | 4866 | .none => !meta.isError(math.cast(i16, value)), |
| 4852 | .u => if (math.cast(u16, value)) |_| true else |_| false, | 4867 | .u => !meta.isError(math.cast(u16, value)), |
| 4853 | .l => if (math.cast(i32, value)) |_| true else |_| false, | 4868 | .l => !meta.isError(math.cast(i32, value)), |
| 4854 | .lu => if (math.cast(u32, value)) |_| true else |_| false, | 4869 | .lu => !meta.isError(math.cast(u32, value)), |
| 4855 | .ll => if (math.cast(i64, value)) |_| true else |_| false, | 4870 | .ll => !meta.isError(math.cast(i64, value)), |
| 4856 | .llu => if (math.cast(u64, value)) |_| true else |_| false, | 4871 | .llu => !meta.isError(math.cast(u64, value)), |
| 4857 | .f => unreachable, | 4872 | .f => unreachable, |
| 4858 | }; | 4873 | }; |
| 4859 | 4874 |
src/translate_c/ast.zig+11-1| ... | @@ -120,8 +120,11 @@ pub const Node = extern union { | ... | @@ -120,8 +120,11 @@ pub const Node = extern union { |
| 120 | std_math_Log2Int, | 120 | std_math_Log2Int, |
| 121 | /// @intCast(lhs, rhs) | 121 | /// @intCast(lhs, rhs) |
| 122 | int_cast, | 122 | int_cast, |
| 123 | /// @rem(lhs, rhs) | 123 | /// @import("std").meta.promoteIntLiteral(value, type, radix) |
| 124 | std_meta_promoteIntLiteral, | 124 | std_meta_promoteIntLiteral, |
| 125 | /// @import("std").meta.alignment(value) | ||
| 126 | std_meta_alignment, | ||
| 127 | /// @rem(lhs, rhs) | ||
| 125 | rem, | 128 | rem, |
| 126 | /// @divTrunc(lhs, rhs) | 129 | /// @divTrunc(lhs, rhs) |
| 127 | div_trunc, | 130 | div_trunc, |
| ... | @@ -260,6 +263,7 @@ pub const Node = extern union { | ... | @@ -260,6 +263,7 @@ pub const Node = extern union { |
| 260 | .switch_else, | 263 | .switch_else, |
| 261 | .block_single, | 264 | .block_single, |
| 262 | .std_meta_sizeof, | 265 | .std_meta_sizeof, |
| 266 | .std_meta_alignment, | ||
| 263 | .bool_to_int, | 267 | .bool_to_int, |
| 264 | .sizeof, | 268 | .sizeof, |
| 265 | .alignof, | 269 | .alignof, |
| ... | @@ -876,6 +880,11 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { | ... | @@ -876,6 +880,11 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex { |
| 876 | const import_node = try renderStdImport(c, "meta", "promoteIntLiteral"); | 880 | const import_node = try renderStdImport(c, "meta", "promoteIntLiteral"); |
| 877 | return renderCall(c, import_node, &.{ payload.type, payload.value, payload.radix }); | 881 | return renderCall(c, import_node, &.{ payload.type, payload.value, payload.radix }); |
| 878 | }, | 882 | }, |
| 883 | .std_meta_alignment => { | ||
| 884 | const payload = node.castTag(.std_meta_alignment).?.data; | ||
| 885 | const import_node = try renderStdImport(c, "meta", "alignment"); | ||
| 886 | return renderCall(c, import_node, &.{payload}); | ||
| 887 | }, | ||
| 879 | .std_meta_sizeof => { | 888 | .std_meta_sizeof => { |
| 880 | const payload = node.castTag(.std_meta_sizeof).?.data; | 889 | const payload = node.castTag(.std_meta_sizeof).?.data; |
| 881 | const import_node = try renderStdImport(c, "meta", "sizeof"); | 890 | const import_node = try renderStdImport(c, "meta", "sizeof"); |
| ... | @@ -2144,6 +2153,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { | ... | @@ -2144,6 +2153,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex { |
| 2144 | .typeof, | 2153 | .typeof, |
| 2145 | .typeinfo, | 2154 | .typeinfo, |
| 2146 | .std_meta_sizeof, | 2155 | .std_meta_sizeof, |
| 2156 | .std_meta_alignment, | ||
| 2147 | .std_meta_cast, | 2157 | .std_meta_cast, |
| 2148 | .std_meta_promoteIntLiteral, | 2158 | .std_meta_promoteIntLiteral, |
| 2149 | .std_meta_vector, | 2159 | .std_meta_vector, |
src/zig_clang.cpp+5| ... | @@ -2528,6 +2528,11 @@ double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatin | ... | @@ -2528,6 +2528,11 @@ double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatin |
| 2528 | return casted->getValueAsApproximateDouble(); | 2528 | return casted->getValueAsApproximateDouble(); |
| 2529 | } | 2529 | } |
| 2530 | 2530 | ||
| 2531 | ZigClangAPFloatBase_Semantics ZigClangFloatingLiteral_getRawSemantics(const ZigClangFloatingLiteral *self) { | ||
| 2532 | auto casted = reinterpret_cast<const clang::FloatingLiteral *>(self); | ||
| 2533 | return static_cast<ZigClangAPFloatBase_Semantics>(casted->getRawSemantics()); | ||
| 2534 | } | ||
| 2535 | |||
| 2531 | enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self) { | 2536 | enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self) { |
| 2532 | auto casted = reinterpret_cast<const clang::StringLiteral *>(self); | 2537 | auto casted = reinterpret_cast<const clang::StringLiteral *>(self); |
| 2533 | return (ZigClangStringLiteral_StringKind)casted->getKind(); | 2538 | return (ZigClangStringLiteral_StringKind)casted->getKind(); |
src/zig_clang.h+11| ... | @@ -881,6 +881,16 @@ enum ZigClangAPFloat_roundingMode { | ... | @@ -881,6 +881,16 @@ enum ZigClangAPFloat_roundingMode { |
| 881 | ZigClangAPFloat_roundingMode_Invalid = -1, | 881 | ZigClangAPFloat_roundingMode_Invalid = -1, |
| 882 | }; | 882 | }; |
| 883 | 883 | ||
| 884 | enum ZigClangAPFloatBase_Semantics { | ||
| 885 | ZigClangAPFloatBase_Semantics_IEEEhalf, | ||
| 886 | ZigClangAPFloatBase_Semantics_BFloat, | ||
| 887 | ZigClangAPFloatBase_Semantics_IEEEsingle, | ||
| 888 | ZigClangAPFloatBase_Semantics_IEEEdouble, | ||
| 889 | ZigClangAPFloatBase_Semantics_x87DoubleExtended, | ||
| 890 | ZigClangAPFloatBase_Semantics_IEEEquad, | ||
| 891 | ZigClangAPFloatBase_Semantics_PPCDoubleDouble, | ||
| 892 | }; | ||
| 893 | |||
| 884 | enum ZigClangStringLiteral_StringKind { | 894 | enum ZigClangStringLiteral_StringKind { |
| 885 | ZigClangStringLiteral_StringKind_Ascii, | 895 | ZigClangStringLiteral_StringKind_Ascii, |
| 886 | ZigClangStringLiteral_StringKind_Wide, | 896 | ZigClangStringLiteral_StringKind_Wide, |
| ... | @@ -1142,6 +1152,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDeclStmt_getBeginLoc(const st | ... | @@ -1142,6 +1152,7 @@ ZIG_EXTERN_C struct ZigClangSourceLocation ZigClangDeclStmt_getBeginLoc(const st |
| 1142 | ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST, | 1152 | ZIG_EXTERN_C unsigned ZigClangAPFloat_convertToHexString(const struct ZigClangAPFloat *self, char *DST, |
| 1143 | unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM); | 1153 | unsigned HexDigits, bool UpperCase, enum ZigClangAPFloat_roundingMode RM); |
| 1144 | ZIG_EXTERN_C double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self); | 1154 | ZIG_EXTERN_C double ZigClangFloatingLiteral_getValueAsApproximateDouble(const ZigClangFloatingLiteral *self); |
| 1155 | ZIG_EXTERN_C ZigClangAPFloatBase_Semantics ZigClangFloatingLiteral_getRawSemantics(const ZigClangFloatingLiteral *self); | ||
| 1145 | 1156 | ||
| 1146 | ZIG_EXTERN_C enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self); | 1157 | ZIG_EXTERN_C enum ZigClangStringLiteral_StringKind ZigClangStringLiteral_getKind(const struct ZigClangStringLiteral *self); |
| 1147 | ZIG_EXTERN_C uint32_t ZigClangStringLiteral_getCodeUnit(const struct ZigClangStringLiteral *self, size_t i); | 1158 | ZIG_EXTERN_C uint32_t ZigClangStringLiteral_getCodeUnit(const struct ZigClangStringLiteral *self, size_t i); |
test/compile_errors.zig+3-1| ... | @@ -2136,7 +2136,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { | ... | @@ -2136,7 +2136,9 @@ pub fn addCases(cases: *tests.CompileErrorContext) void { |
| 2136 | \\} | 2136 | \\} |
| 2137 | \\fn func() callconv(.Async) void {} | 2137 | \\fn func() callconv(.Async) void {} |
| 2138 | , &[_][]const u8{ | 2138 | , &[_][]const u8{ |
| 2139 | "tmp.zig:4:21: error: expected type '[]align(16) u8', found '*[64]u8'", | 2139 | // Split the check in two as the alignment value is target dependent. |
| 2140 | "tmp.zig:4:21: error: expected type '[]align(", | ||
| 2141 | ") u8', found '*[64]u8'", | ||
| 2140 | }); | 2142 | }); |
| 2141 | 2143 | ||
| 2142 | cases.add("atomic orderings of fence Acquire or stricter", | 2144 | cases.add("atomic orderings of fence Acquire or stricter", |
test/stage1/behavior/type_info.zig+1-1| ... | @@ -306,7 +306,7 @@ test "type info: function type info" { | ... | @@ -306,7 +306,7 @@ test "type info: function type info" { |
| 306 | fn testFunction() void { | 306 | fn testFunction() void { |
| 307 | const fn_info = @typeInfo(@TypeOf(foo)); | 307 | const fn_info = @typeInfo(@TypeOf(foo)); |
| 308 | expect(fn_info == .Fn); | 308 | expect(fn_info == .Fn); |
| 309 | expect(fn_info.Fn.alignment == 0); | 309 | expect(fn_info.Fn.alignment > 0); |
| 310 | expect(fn_info.Fn.calling_convention == .C); | 310 | expect(fn_info.Fn.calling_convention == .C); |
| 311 | expect(!fn_info.Fn.is_generic); | 311 | expect(!fn_info.Fn.is_generic); |
| 312 | expect(fn_info.Fn.args.len == 2); | 312 | expect(fn_info.Fn.args.len == 2); |
test/stage2/riscv64.zig created+45| ... | @@ -0,0 +1,45 @@ | ||
| 1 | const std = @import("std"); | ||
| 2 | const TestContext = @import("../../src/test.zig").TestContext; | ||
| 3 | |||
| 4 | const linux_riscv64 = std.zig.CrossTarget{ | ||
| 5 | .cpu_arch = .riscv64, | ||
| 6 | .os_tag = .linux, | ||
| 7 | }; | ||
| 8 | |||
| 9 | pub fn addCases(ctx: *TestContext) !void { | ||
| 10 | { | ||
| 11 | var case = ctx.exe("riscv64 hello world", linux_riscv64); | ||
| 12 | // Regular old hello world | ||
| 13 | case.addCompareOutput( | ||
| 14 | \\export fn _start() noreturn { | ||
| 15 | \\ print(); | ||
| 16 | \\ | ||
| 17 | \\ exit(); | ||
| 18 | \\} | ||
| 19 | \\ | ||
| 20 | \\fn print() void { | ||
| 21 | \\ asm volatile ("ecall" | ||
| 22 | \\ : | ||
| 23 | \\ : [number] "{a7}" (64), | ||
| 24 | \\ [arg1] "{a0}" (1), | ||
| 25 | \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")), | ||
| 26 | \\ [arg3] "{a2}" ("Hello, World!\n".len) | ||
| 27 | \\ : "rcx", "r11", "memory" | ||
| 28 | \\ ); | ||
| 29 | \\ return; | ||
| 30 | \\} | ||
| 31 | \\ | ||
| 32 | \\fn exit() noreturn { | ||
| 33 | \\ asm volatile ("ecall" | ||
| 34 | \\ : | ||
| 35 | \\ : [number] "{a7}" (94), | ||
| 36 | \\ [arg1] "{a0}" (0) | ||
| 37 | \\ : "rcx", "r11", "memory" | ||
| 38 | \\ ); | ||
| 39 | \\ unreachable; | ||
| 40 | \\} | ||
| 41 | , | ||
| 42 | "Hello, World!\n", | ||
| 43 | ); | ||
| 44 | } | ||
| 45 | } | ||
test/stage2/test.zig+1-41| ... | @@ -11,11 +11,6 @@ const linux_x64 = std.zig.CrossTarget{ | ... | @@ -11,11 +11,6 @@ const linux_x64 = std.zig.CrossTarget{ |
| 11 | .os_tag = .linux, | 11 | .os_tag = .linux, |
| 12 | }; | 12 | }; |
| 13 | 13 | ||
| 14 | const linux_riscv64 = std.zig.CrossTarget{ | ||
| 15 | .cpu_arch = .riscv64, | ||
| 16 | .os_tag = .linux, | ||
| 17 | }; | ||
| 18 | |||
| 19 | pub fn addCases(ctx: *TestContext) !void { | 14 | pub fn addCases(ctx: *TestContext) !void { |
| 20 | try @import("cbe.zig").addCases(ctx); | 15 | try @import("cbe.zig").addCases(ctx); |
| 21 | try @import("spu-ii.zig").addCases(ctx); | 16 | try @import("spu-ii.zig").addCases(ctx); |
| ... | @@ -24,6 +19,7 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -24,6 +19,7 @@ pub fn addCases(ctx: *TestContext) !void { |
| 24 | try @import("llvm.zig").addCases(ctx); | 19 | try @import("llvm.zig").addCases(ctx); |
| 25 | try @import("wasm.zig").addCases(ctx); | 20 | try @import("wasm.zig").addCases(ctx); |
| 26 | try @import("darwin.zig").addCases(ctx); | 21 | try @import("darwin.zig").addCases(ctx); |
| 22 | try @import("riscv64.zig").addCases(ctx); | ||
| 27 | 23 | ||
| 28 | { | 24 | { |
| 29 | var case = ctx.exe("hello world with updates", linux_x64); | 25 | var case = ctx.exe("hello world with updates", linux_x64); |
| ... | @@ -137,42 +133,6 @@ pub fn addCases(ctx: *TestContext) !void { | ... | @@ -137,42 +133,6 @@ pub fn addCases(ctx: *TestContext) !void { |
| 137 | ); | 133 | ); |
| 138 | } | 134 | } |
| 139 | 135 | ||
| 140 | { | ||
| 141 | var case = ctx.exe("riscv64 hello world", linux_riscv64); | ||
| 142 | // Regular old hello world | ||
| 143 | case.addCompareOutput( | ||
| 144 | \\export fn _start() noreturn { | ||
| 145 | \\ print(); | ||
| 146 | \\ | ||
| 147 | \\ exit(); | ||
| 148 | \\} | ||
| 149 | \\ | ||
| 150 | \\fn print() void { | ||
| 151 | \\ asm volatile ("ecall" | ||
| 152 | \\ : | ||
| 153 | \\ : [number] "{a7}" (64), | ||
| 154 | \\ [arg1] "{a0}" (1), | ||
| 155 | \\ [arg2] "{a1}" (@ptrToInt("Hello, World!\n")), | ||
| 156 | \\ [arg3] "{a2}" ("Hello, World!\n".len) | ||
| 157 | \\ : "rcx", "r11", "memory" | ||
| 158 | \\ ); | ||
| 159 | \\ return; | ||
| 160 | \\} | ||
| 161 | \\ | ||
| 162 | \\fn exit() noreturn { | ||
| 163 | \\ asm volatile ("ecall" | ||
| 164 | \\ : | ||
| 165 | \\ : [number] "{a7}" (94), | ||
| 166 | \\ [arg1] "{a0}" (0) | ||
| 167 | \\ : "rcx", "r11", "memory" | ||
| 168 | \\ ); | ||
| 169 | \\ unreachable; | ||
| 170 | \\} | ||
| 171 | , | ||
| 172 | "Hello, World!\n", | ||
| 173 | ); | ||
| 174 | } | ||
| 175 | |||
| 176 | { | 136 | { |
| 177 | var case = ctx.exe("adding numbers at comptime", linux_x64); | 137 | var case = ctx.exe("adding numbers at comptime", linux_x64); |
| 178 | case.addCompareOutput( | 138 | case.addCompareOutput( |
test/translate_c.zig+9-11| ... | @@ -1363,7 +1363,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -1363,7 +1363,7 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1363 | , &[_][]const u8{ | 1363 | , &[_][]const u8{ |
| 1364 | \\pub export fn ptrcast() [*c]f32 { | 1364 | \\pub export fn ptrcast() [*c]f32 { |
| 1365 | \\ var a: [*c]c_int = undefined; | 1365 | \\ var a: [*c]c_int = undefined; |
| 1366 | \\ return @ptrCast([*c]f32, @alignCast(@alignOf(f32), a)); | 1366 | \\ return @ptrCast([*c]f32, @alignCast(@import("std").meta.alignment(f32), a)); |
| 1367 | \\} | 1367 | \\} |
| 1368 | }); | 1368 | }); |
| 1369 | 1369 | ||
| ... | @@ -1387,16 +1387,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -1387,16 +1387,16 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 1387 | \\pub export fn test_ptr_cast() void { | 1387 | \\pub export fn test_ptr_cast() void { |
| 1388 | \\ var p: ?*c_void = undefined; | 1388 | \\ var p: ?*c_void = undefined; |
| 1389 | \\ { | 1389 | \\ { |
| 1390 | \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); | 1390 | \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@import("std").meta.alignment(u8), p)); |
| 1391 | \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); | 1391 | \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@import("std").meta.alignment(c_short), p)); |
| 1392 | \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); | 1392 | \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@import("std").meta.alignment(c_int), p)); |
| 1393 | \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); | 1393 | \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@import("std").meta.alignment(c_longlong), p)); |
| 1394 | \\ } | 1394 | \\ } |
| 1395 | \\ { | 1395 | \\ { |
| 1396 | \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@alignOf(u8), p)); | 1396 | \\ var to_char: [*c]u8 = @ptrCast([*c]u8, @alignCast(@import("std").meta.alignment(u8), p)); |
| 1397 | \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@alignOf(c_short), p)); | 1397 | \\ var to_short: [*c]c_short = @ptrCast([*c]c_short, @alignCast(@import("std").meta.alignment(c_short), p)); |
| 1398 | \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@alignOf(c_int), p)); | 1398 | \\ var to_int: [*c]c_int = @ptrCast([*c]c_int, @alignCast(@import("std").meta.alignment(c_int), p)); |
| 1399 | \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@alignOf(c_longlong), p)); | 1399 | \\ var to_longlong: [*c]c_longlong = @ptrCast([*c]c_longlong, @alignCast(@import("std").meta.alignment(c_longlong), p)); |
| 1400 | \\ } | 1400 | \\ } |
| 1401 | \\} | 1401 | \\} |
| 1402 | }); | 1402 | }); |
| ... | @@ -3028,7 +3028,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -3028,7 +3028,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3028 | \\void call() { | 3028 | \\void call() { |
| 3029 | \\ fn_int(3.0f); | 3029 | \\ fn_int(3.0f); |
| 3030 | \\ fn_int(3.0); | 3030 | \\ fn_int(3.0); |
| 3031 | \\ fn_int(3.0L); | ||
| 3032 | \\ fn_int('ABCD'); | 3031 | \\ fn_int('ABCD'); |
| 3033 | \\ fn_f32(3); | 3032 | \\ fn_f32(3); |
| 3034 | \\ fn_f64(3); | 3033 | \\ fn_f64(3); |
| ... | @@ -3053,7 +3052,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { | ... | @@ -3053,7 +3052,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void { |
| 3053 | \\pub export fn call() void { | 3052 | \\pub export fn call() void { |
| 3054 | \\ fn_int(@floatToInt(c_int, 3.0)); | 3053 | \\ fn_int(@floatToInt(c_int, 3.0)); |
| 3055 | \\ fn_int(@floatToInt(c_int, 3.0)); | 3054 | \\ fn_int(@floatToInt(c_int, 3.0)); |
| 3056 | \\ fn_int(@floatToInt(c_int, 3.0)); | ||
| 3057 | \\ fn_int(@as(c_int, 1094861636)); | 3055 | \\ fn_int(@as(c_int, 1094861636)); |
| 3058 | \\ fn_f32(@intToFloat(f32, @as(c_int, 3))); | 3056 | \\ fn_f32(@intToFloat(f32, @as(c_int, 3))); |
| 3059 | \\ fn_f64(@intToFloat(f64, @as(c_int, 3))); | 3057 | \\ fn_f64(@intToFloat(f64, @as(c_int, 3))); |