| author | |
| committer | |
| log | b6bb0ee1acd6fb9e3360f35d7b63687f755785f6 |
| tree | 34f42b24cc683d13a9e78bd27f914dfee00c37b0 |
| parent | 28353b315935e54b497f4abb875fac387e20f65f |
| parent | 84d5cc31c560749eda1e36b7bc9e6cf542eee550 |
Conflicts:
* lib/std/os/linux/tls.zig
* test/behavior/align.zig
* test/behavior/atomics.zig
* test/behavior/vector.zig22 files changed, 305 insertions(+), 55 deletions(-)
lib/std/os/bits/linux.zig+1-1| ... | @@ -18,7 +18,7 @@ pub usingnamespace switch (arch) { | ... | @@ -18,7 +18,7 @@ pub usingnamespace switch (arch) { |
| 18 | .i386 => @import("linux/i386.zig"), | 18 | .i386 => @import("linux/i386.zig"), |
| 19 | .x86_64 => @import("linux/x86_64.zig"), | 19 | .x86_64 => @import("linux/x86_64.zig"), |
| 20 | .aarch64 => @import("linux/arm64.zig"), | 20 | .aarch64 => @import("linux/arm64.zig"), |
| 21 | .arm => @import("linux/arm-eabi.zig"), | 21 | .arm, .thumb => @import("linux/arm-eabi.zig"), |
| 22 | .riscv64 => @import("linux/riscv64.zig"), | 22 | .riscv64 => @import("linux/riscv64.zig"), |
| 23 | .sparcv9 => @import("linux/sparc64.zig"), | 23 | .sparcv9 => @import("linux/sparc64.zig"), |
| 24 | .mips, .mipsel => @import("linux/mips.zig"), | 24 | .mips, .mipsel => @import("linux/mips.zig"), |
lib/std/os/linux.zig+1| ... | @@ -24,6 +24,7 @@ pub usingnamespace switch (native_arch) { | ... | @@ -24,6 +24,7 @@ pub usingnamespace switch (native_arch) { |
| 24 | .x86_64 => @import("linux/x86_64.zig"), | 24 | .x86_64 => @import("linux/x86_64.zig"), |
| 25 | .aarch64 => @import("linux/arm64.zig"), | 25 | .aarch64 => @import("linux/arm64.zig"), |
| 26 | .arm => @import("linux/arm-eabi.zig"), | 26 | .arm => @import("linux/arm-eabi.zig"), |
| 27 | .thumb => @import("linux/thumb.zig"), | ||
| 27 | .riscv64 => @import("linux/riscv64.zig"), | 28 | .riscv64 => @import("linux/riscv64.zig"), |
| 28 | .sparcv9 => @import("linux/sparc64.zig"), | 29 | .sparcv9 => @import("linux/sparc64.zig"), |
| 29 | .mips, .mipsel => @import("linux/mips.zig"), | 30 | .mips, .mipsel => @import("linux/mips.zig"), |
lib/std/os/linux/thumb.zig created+168| ... | @@ -0,0 +1,168 @@ | ||
| 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. | ||
| 6 | usingnamespace @import("../bits.zig"); | ||
| 7 | |||
| 8 | // The syscall interface is identical to the ARM one but we're facing an extra | ||
| 9 | // challenge: r7, the register where the syscall number is stored, may be | ||
| 10 | // reserved for the frame pointer. | ||
| 11 | // Save and restore r7 around the syscall without touching the stack pointer not | ||
| 12 | // to break the frame chain. | ||
| 13 | |||
| 14 | pub fn syscall0(number: SYS) usize { | ||
| 15 | @setRuntimeSafety(false); | ||
| 16 | |||
| 17 | var buf: [2]usize = .{ @enumToInt(number), undefined }; | ||
| 18 | return asm volatile ( | ||
| 19 | \\ str r7, [%[tmp], #4] | ||
| 20 | \\ ldr r7, [%[tmp]] | ||
| 21 | \\ svc #0 | ||
| 22 | \\ ldr r7, [%[tmp], #4] | ||
| 23 | : [ret] "={r0}" (-> usize) | ||
| 24 | : [tmp] "{r1}" (buf) | ||
| 25 | : "memory" | ||
| 26 | ); | ||
| 27 | } | ||
| 28 | |||
| 29 | pub fn syscall1(number: SYS, arg1: usize) usize { | ||
| 30 | @setRuntimeSafety(false); | ||
| 31 | |||
| 32 | var buf: [2]usize = .{ @enumToInt(number), undefined }; | ||
| 33 | return asm volatile ( | ||
| 34 | \\ str r7, [%[tmp], #4] | ||
| 35 | \\ ldr r7, [%[tmp]] | ||
| 36 | \\ svc #0 | ||
| 37 | \\ ldr r7, [%[tmp], #4] | ||
| 38 | : [ret] "={r0}" (-> usize) | ||
| 39 | : [tmp] "{r1}" (buf), | ||
| 40 | [arg1] "{r0}" (arg1) | ||
| 41 | : "memory" | ||
| 42 | ); | ||
| 43 | } | ||
| 44 | |||
| 45 | pub fn syscall2(number: SYS, arg1: usize, arg2: usize) usize { | ||
| 46 | @setRuntimeSafety(false); | ||
| 47 | |||
| 48 | var buf: [2]usize = .{ @enumToInt(number), undefined }; | ||
| 49 | return asm volatile ( | ||
| 50 | \\ str r7, [%[tmp], #4] | ||
| 51 | \\ ldr r7, [%[tmp]] | ||
| 52 | \\ svc #0 | ||
| 53 | \\ ldr r7, [%[tmp], #4] | ||
| 54 | : [ret] "={r0}" (-> usize) | ||
| 55 | : [tmp] "{r2}" (buf), | ||
| 56 | [arg1] "{r0}" (arg1), | ||
| 57 | [arg2] "{r1}" (arg2) | ||
| 58 | : "memory" | ||
| 59 | ); | ||
| 60 | } | ||
| 61 | |||
| 62 | pub fn syscall3(number: SYS, arg1: usize, arg2: usize, arg3: usize) usize { | ||
| 63 | @setRuntimeSafety(false); | ||
| 64 | |||
| 65 | var buf: [2]usize = .{ @enumToInt(number), undefined }; | ||
| 66 | return asm volatile ( | ||
| 67 | \\ str r7, [%[tmp], #4] | ||
| 68 | \\ ldr r7, [%[tmp]] | ||
| 69 | \\ svc #0 | ||
| 70 | \\ ldr r7, [%[tmp], #4] | ||
| 71 | : [ret] "={r0}" (-> usize) | ||
| 72 | : [tmp] "{r3}" (buf), | ||
| 73 | [arg1] "{r0}" (arg1), | ||
| 74 | [arg2] "{r1}" (arg2), | ||
| 75 | [arg3] "{r2}" (arg3) | ||
| 76 | : "memory" | ||
| 77 | ); | ||
| 78 | } | ||
| 79 | |||
| 80 | pub fn syscall4(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize) usize { | ||
| 81 | @setRuntimeSafety(false); | ||
| 82 | |||
| 83 | var buf: [2]usize = .{ @enumToInt(number), undefined }; | ||
| 84 | return asm volatile ( | ||
| 85 | \\ str r7, [%[tmp], #4] | ||
| 86 | \\ ldr r7, [%[tmp]] | ||
| 87 | \\ svc #0 | ||
| 88 | \\ ldr r7, [%[tmp], #4] | ||
| 89 | : [ret] "={r0}" (-> usize) | ||
| 90 | : [tmp] "{r4}" (buf), | ||
| 91 | [arg1] "{r0}" (arg1), | ||
| 92 | [arg2] "{r1}" (arg2), | ||
| 93 | [arg3] "{r2}" (arg3), | ||
| 94 | [arg4] "{r3}" (arg4) | ||
| 95 | : "memory" | ||
| 96 | ); | ||
| 97 | } | ||
| 98 | |||
| 99 | pub fn syscall5(number: SYS, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) usize { | ||
| 100 | @setRuntimeSafety(false); | ||
| 101 | |||
| 102 | var buf: [2]usize = .{ @enumToInt(number), undefined }; | ||
| 103 | return asm volatile ( | ||
| 104 | \\ str r7, [%[tmp], #4] | ||
| 105 | \\ ldr r7, [%[tmp]] | ||
| 106 | \\ svc #0 | ||
| 107 | \\ ldr r7, [%[tmp], #4] | ||
| 108 | : [ret] "={r0}" (-> usize) | ||
| 109 | : [tmp] "{r5}" (buf), | ||
| 110 | [arg1] "{r0}" (arg1), | ||
| 111 | [arg2] "{r1}" (arg2), | ||
| 112 | [arg3] "{r2}" (arg3), | ||
| 113 | [arg4] "{r3}" (arg4), | ||
| 114 | [arg5] "{r4}" (arg5) | ||
| 115 | : "memory" | ||
| 116 | ); | ||
| 117 | } | ||
| 118 | |||
| 119 | pub fn syscall6( | ||
| 120 | number: SYS, | ||
| 121 | arg1: usize, | ||
| 122 | arg2: usize, | ||
| 123 | arg3: usize, | ||
| 124 | arg4: usize, | ||
| 125 | arg5: usize, | ||
| 126 | arg6: usize, | ||
| 127 | ) usize { | ||
| 128 | @setRuntimeSafety(false); | ||
| 129 | |||
| 130 | var buf: [2]usize = .{ @enumToInt(number), undefined }; | ||
| 131 | return asm volatile ( | ||
| 132 | \\ str r7, [%[tmp], #4] | ||
| 133 | \\ ldr r7, [%[tmp]] | ||
| 134 | \\ svc #0 | ||
| 135 | \\ ldr r7, [%[tmp], #4] | ||
| 136 | : [ret] "={r0}" (-> usize) | ||
| 137 | : [tmp] "{r6}" (buf), | ||
| 138 | [arg1] "{r0}" (arg1), | ||
| 139 | [arg2] "{r1}" (arg2), | ||
| 140 | [arg3] "{r2}" (arg3), | ||
| 141 | [arg4] "{r3}" (arg4), | ||
| 142 | [arg5] "{r4}" (arg5), | ||
| 143 | [arg6] "{r5}" (arg6) | ||
| 144 | : "memory" | ||
| 145 | ); | ||
| 146 | } | ||
| 147 | |||
| 148 | /// This matches the libc clone function. | ||
| 149 | pub extern fn clone(func: fn (arg: usize) callconv(.C) u8, stack: usize, flags: u32, arg: usize, ptid: *i32, tls: usize, ctid: *i32) usize; | ||
| 150 | |||
| 151 | pub fn restore() callconv(.Naked) void { | ||
| 152 | return asm volatile ( | ||
| 153 | \\ mov r7, %[number] | ||
| 154 | \\ svc #0 | ||
| 155 | : | ||
| 156 | : [number] "I" (@enumToInt(SYS.sigreturn)) | ||
| 157 | ); | ||
| 158 | } | ||
| 159 | |||
| 160 | pub fn restore_rt() callconv(.Naked) void { | ||
| 161 | return asm volatile ( | ||
| 162 | \\ mov r7, %[number] | ||
| 163 | \\ svc #0 | ||
| 164 | : | ||
| 165 | : [number] "I" (@enumToInt(SYS.rt_sigreturn)) | ||
| 166 | : "memory" | ||
| 167 | ); | ||
| 168 | } | ||
lib/std/os/linux/tls.zig+3-3| ... | @@ -53,7 +53,7 @@ const TLSVariant = enum { | ... | @@ -53,7 +53,7 @@ const TLSVariant = enum { |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| 55 | const tls_variant = switch (native_arch) { | 55 | const tls_variant = switch (native_arch) { |
| 56 | .arm, .armeb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI, | 56 | .arm, .armeb, .thumb, .aarch64, .aarch64_be, .riscv32, .riscv64, .mips, .mipsel, .powerpc, .powerpc64, .powerpc64le => TLSVariant.VariantI, |
| 57 | .x86_64, .i386, .sparcv9 => TLSVariant.VariantII, | 57 | .x86_64, .i386, .sparcv9 => TLSVariant.VariantII, |
| 58 | else => @compileError("undefined tls_variant for this architecture"), | 58 | else => @compileError("undefined tls_variant for this architecture"), |
| 59 | }; | 59 | }; |
| ... | @@ -62,7 +62,7 @@ const tls_variant = switch (native_arch) { | ... | @@ -62,7 +62,7 @@ const tls_variant = switch (native_arch) { |
| 62 | const tls_tcb_size = switch (native_arch) { | 62 | const tls_tcb_size = switch (native_arch) { |
| 63 | // ARM EABI mandates enough space for two pointers: the first one points to | 63 | // ARM EABI mandates enough space for two pointers: the first one points to |
| 64 | // the DTV while the second one is unspecified but reserved | 64 | // the DTV while the second one is unspecified but reserved |
| 65 | .arm, .armeb, .aarch64, .aarch64_be => 2 * @sizeOf(usize), | 65 | .arm, .armeb, .thumb, .aarch64, .aarch64_be => 2 * @sizeOf(usize), |
| 66 | // One pointer-sized word that points either to the DTV or the TCB itself | 66 | // One pointer-sized word that points either to the DTV or the TCB itself |
| 67 | else => @sizeOf(usize), | 67 | else => @sizeOf(usize), |
| 68 | }; | 68 | }; |
| ... | @@ -150,7 +150,7 @@ pub fn setThreadPointer(addr: usize) void { | ... | @@ -150,7 +150,7 @@ pub fn setThreadPointer(addr: usize) void { |
| 150 | : [addr] "r" (addr) | 150 | : [addr] "r" (addr) |
| 151 | ); | 151 | ); |
| 152 | }, | 152 | }, |
| 153 | .arm => { | 153 | .arm, .thumb => { |
| 154 | const rc = std.os.linux.syscall1(.set_tls, addr); | 154 | const rc = std.os.linux.syscall1(.set_tls, addr); |
| 155 | assert(rc == 0); | 155 | assert(rc == 0); |
| 156 | }, | 156 | }, |
lib/std/os/test.zig+2| ... | @@ -43,6 +43,8 @@ test "chdir smoke test" { | ... | @@ -43,6 +43,8 @@ test "chdir smoke test" { |
| 43 | // Next, change current working directory to one level above | 43 | // Next, change current working directory to one level above |
| 44 | const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute | 44 | const parent = fs.path.dirname(old_cwd) orelse unreachable; // old_cwd should be absolute |
| 45 | try os.chdir(parent); | 45 | try os.chdir(parent); |
| 46 | // Restore cwd because process may have other tests that do not tolerate chdir. | ||
| 47 | defer os.chdir(old_cwd) catch unreachable; | ||
| 46 | var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; | 48 | var new_cwd_buf: [fs.MAX_PATH_BYTES]u8 = undefined; |
| 47 | const new_cwd = try os.getcwd(new_cwd_buf[0..]); | 49 | const new_cwd = try os.getcwd(new_cwd_buf[0..]); |
| 48 | expect(mem.eql(u8, parent, new_cwd)); | 50 | expect(mem.eql(u8, parent, new_cwd)); |
lib/std/special/c.zig+1-1| ... | @@ -388,7 +388,7 @@ fn clone() callconv(.Naked) void { | ... | @@ -388,7 +388,7 @@ fn clone() callconv(.Naked) void { |
| 388 | \\ svc #0 | 388 | \\ svc #0 |
| 389 | ); | 389 | ); |
| 390 | }, | 390 | }, |
| 391 | .arm => { | 391 | .arm, .thumb => { |
| 392 | // __clone(func, stack, flags, arg, ptid, tls, ctid) | 392 | // __clone(func, stack, flags, arg, ptid, tls, ctid) |
| 393 | // r0, r1, r2, r3, +0, +4, +8 | 393 | // r0, r1, r2, r3, +0, +4, +8 |
| 394 | 394 |
lib/std/special/compiler_rt/clzsi2.zig+20-7| ... | @@ -26,6 +26,8 @@ fn __clzsi2_generic(a: i32) callconv(.C) i32 { | ... | @@ -26,6 +26,8 @@ fn __clzsi2_generic(a: i32) callconv(.C) i32 { |
| 26 | } | 26 | } |
| 27 | 27 | ||
| 28 | fn __clzsi2_thumb1() callconv(.Naked) void { | 28 | fn __clzsi2_thumb1() callconv(.Naked) void { |
| 29 | @setRuntimeSafety(false); | ||
| 30 | |||
| 29 | // Similar to the generic version with the last two rounds replaced by a LUT | 31 | // Similar to the generic version with the last two rounds replaced by a LUT |
| 30 | asm volatile ( | 32 | asm volatile ( |
| 31 | \\ movs r1, #32 | 33 | \\ movs r1, #32 |
| ... | @@ -58,6 +60,8 @@ fn __clzsi2_thumb1() callconv(.Naked) void { | ... | @@ -58,6 +60,8 @@ fn __clzsi2_thumb1() callconv(.Naked) void { |
| 58 | } | 60 | } |
| 59 | 61 | ||
| 60 | fn __clzsi2_arm32() callconv(.Naked) void { | 62 | fn __clzsi2_arm32() callconv(.Naked) void { |
| 63 | @setRuntimeSafety(false); | ||
| 64 | |||
| 61 | asm volatile ( | 65 | asm volatile ( |
| 62 | \\ // Assumption: n != 0 | 66 | \\ // Assumption: n != 0 |
| 63 | \\ // r0: n | 67 | \\ // r0: n |
| ... | @@ -104,13 +108,22 @@ fn __clzsi2_arm32() callconv(.Naked) void { | ... | @@ -104,13 +108,22 @@ fn __clzsi2_arm32() callconv(.Naked) void { |
| 104 | unreachable; | 108 | unreachable; |
| 105 | } | 109 | } |
| 106 | 110 | ||
| 107 | pub const __clzsi2 = switch (std.Target.current.cpu.arch) { | 111 | pub const __clzsi2 = impl: { |
| 108 | .arm, .armeb => if (std.Target.arm.featureSetHas(std.Target.current.cpu.features, .noarm)) | 112 | switch (std.Target.current.cpu.arch) { |
| 109 | __clzsi2_thumb1 | 113 | .arm, .armeb, .thumb, .thumbeb => { |
| 110 | else | 114 | const use_thumb1 = |
| 111 | __clzsi2_arm32, | 115 | (std.Target.current.cpu.arch.isThumb() or |
| 112 | .thumb, .thumbeb => __clzsi2_thumb1, | 116 | std.Target.arm.featureSetHas(std.Target.current.cpu.features, .noarm)) and |
| 113 | else => __clzsi2_generic, | 117 | !std.Target.arm.featureSetHas(std.Target.current.cpu.features, .thumb2); |
| 118 | |||
| 119 | if (use_thumb1) break :impl __clzsi2_thumb1 | ||
| 120 | // From here on we're either targeting Thumb2 or ARM. | ||
| 121 | else if (!std.Target.current.cpu.arch.isThumb()) break :impl __clzsi2_arm32 | ||
| 122 | // Use the generic implementation otherwise. | ||
| 123 | else break :impl __clzsi2_generic; | ||
| 124 | }, | ||
| 125 | else => break :impl __clzsi2_generic, | ||
| 126 | } | ||
| 114 | }; | 127 | }; |
| 115 | 128 | ||
| 116 | test "test clzsi2" { | 129 | test "test clzsi2" { |
lib/std/special/compiler_rt/clzsi2_test.zig+2| ... | @@ -7,6 +7,8 @@ const clzsi2 = @import("clzsi2.zig"); | ... | @@ -7,6 +7,8 @@ const clzsi2 = @import("clzsi2.zig"); |
| 7 | const testing = @import("std").testing; | 7 | const testing = @import("std").testing; |
| 8 | 8 | ||
| 9 | fn test__clzsi2(a: u32, expected: i32) void { | 9 | fn test__clzsi2(a: u32, expected: i32) void { |
| 10 | // XXX At high optimization levels this test may be horribly miscompiled if | ||
| 11 | // one of the naked implementations is selected. | ||
| 10 | var nakedClzsi2 = clzsi2.__clzsi2; | 12 | var nakedClzsi2 = clzsi2.__clzsi2; |
| 11 | var actualClzsi2 = @ptrCast(fn (a: i32) callconv(.C) i32, nakedClzsi2); | 13 | var actualClzsi2 = @ptrCast(fn (a: i32) callconv(.C) i32, nakedClzsi2); |
| 12 | var x = @bitCast(i32, a); | 14 | var x = @bitCast(i32, a); |
lib/std/start.zig+1-1| ... | @@ -182,7 +182,7 @@ fn _start() callconv(.Naked) noreturn { | ... | @@ -182,7 +182,7 @@ fn _start() callconv(.Naked) noreturn { |
| 182 | : [argc] "={esp}" (-> [*]usize) | 182 | : [argc] "={esp}" (-> [*]usize) |
| 183 | ); | 183 | ); |
| 184 | }, | 184 | }, |
| 185 | .aarch64, .aarch64_be, .arm, .armeb => { | 185 | .aarch64, .aarch64_be, .arm, .armeb, .thumb => { |
| 186 | argc_argv_ptr = asm volatile ( | 186 | argc_argv_ptr = asm volatile ( |
| 187 | \\ mov fp, #0 | 187 | \\ mov fp, #0 |
| 188 | \\ mov lr, #0 | 188 | \\ mov lr, #0 |
lib/std/zig/system.zig+9| ... | @@ -350,6 +350,15 @@ pub const NativeTargetInfo = struct { | ... | @@ -350,6 +350,15 @@ pub const NativeTargetInfo = struct { |
| 350 | } | 350 | } |
| 351 | } | 351 | } |
| 352 | }, | 352 | }, |
| 353 | .arm, .armeb => { | ||
| 354 | // XXX What do we do if the target has the noarm feature? | ||
| 355 | // What do we do if the user specifies +thumb_mode? | ||
| 356 | }, | ||
| 357 | .thumb, .thumbeb => { | ||
| 358 | result.target.cpu.features.addFeature( | ||
| 359 | @enumToInt(std.Target.arm.Feature.thumb_mode), | ||
| 360 | ); | ||
| 361 | }, | ||
| 353 | else => {}, | 362 | else => {}, |
| 354 | } | 363 | } |
| 355 | cross_target.updateCpuFeatures(&result.target.cpu.features); | 364 | cross_target.updateCpuFeatures(&result.target.cpu.features); |
src/link/MachO/Archive.zig+6-3| ... | @@ -16,7 +16,7 @@ allocator: *Allocator, | ... | @@ -16,7 +16,7 @@ allocator: *Allocator, |
| 16 | arch: ?std.Target.Cpu.Arch = null, | 16 | arch: ?std.Target.Cpu.Arch = null, |
| 17 | file: ?fs.File = null, | 17 | file: ?fs.File = null, |
| 18 | header: ?ar_hdr = null, | 18 | header: ?ar_hdr = null, |
| 19 | name: ?[]u8 = null, | 19 | name: ?[]const u8 = null, |
| 20 | 20 | ||
| 21 | /// Parsed table of contents. | 21 | /// Parsed table of contents. |
| 22 | /// Each symbol name points to a list of all definition | 22 | /// Each symbol name points to a list of all definition |
| ... | @@ -195,7 +195,7 @@ fn parseTableOfContents(self: *Archive, reader: anytype) !void { | ... | @@ -195,7 +195,7 @@ fn parseTableOfContents(self: *Archive, reader: anytype) !void { |
| 195 | } | 195 | } |
| 196 | 196 | ||
| 197 | /// Caller owns the Object instance. | 197 | /// Caller owns the Object instance. |
| 198 | pub fn parseObject(self: Archive, offset: u32) !Object { | 198 | pub fn parseObject(self: Archive, offset: u32) !*Object { |
| 199 | var reader = self.file.?.reader(); | 199 | var reader = self.file.?.reader(); |
| 200 | try reader.context.seekTo(offset); | 200 | try reader.context.seekTo(offset); |
| 201 | 201 | ||
| ... | @@ -217,7 +217,10 @@ pub fn parseObject(self: Archive, offset: u32) !Object { | ... | @@ -217,7 +217,10 @@ pub fn parseObject(self: Archive, offset: u32) !Object { |
| 217 | break :name try std.fmt.allocPrint(self.allocator, "{s}({s})", .{ path, object_name }); | 217 | break :name try std.fmt.allocPrint(self.allocator, "{s}({s})", .{ path, object_name }); |
| 218 | }; | 218 | }; |
| 219 | 219 | ||
| 220 | var object = Object.init(self.allocator); | 220 | var object = try self.allocator.create(Object); |
| 221 | errdefer self.allocator.destroy(object); | ||
| 222 | |||
| 223 | object.* = Object.init(self.allocator); | ||
| 221 | object.arch = self.arch.?; | 224 | object.arch = self.arch.?; |
| 222 | object.file = try fs.cwd().openFile(self.name.?, .{}); | 225 | object.file = try fs.cwd().openFile(self.name.?, .{}); |
| 223 | object.name = name; | 226 | object.name = name; |
src/link/MachO/Object.zig+21-5| ... | @@ -22,7 +22,7 @@ arch: ?std.Target.Cpu.Arch = null, | ... | @@ -22,7 +22,7 @@ arch: ?std.Target.Cpu.Arch = null, |
| 22 | header: ?macho.mach_header_64 = null, | 22 | header: ?macho.mach_header_64 = null, |
| 23 | file: ?fs.File = null, | 23 | file: ?fs.File = null, |
| 24 | file_offset: ?u32 = null, | 24 | file_offset: ?u32 = null, |
| 25 | name: ?[]u8 = null, | 25 | name: ?[]const u8 = null, |
| 26 | 26 | ||
| 27 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, | 27 | load_commands: std.ArrayListUnmanaged(LoadCommand) = .{}, |
| 28 | sections: std.ArrayListUnmanaged(Section) = .{}, | 28 | sections: std.ArrayListUnmanaged(Section) = .{}, |
| ... | @@ -343,14 +343,22 @@ pub fn parseSymbols(self: *Object) !void { | ... | @@ -343,14 +343,22 @@ pub fn parseSymbols(self: *Object) !void { |
| 343 | _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff); | 343 | _ = try self.file.?.preadAll(strtab, symtab_cmd.stroff); |
| 344 | 344 | ||
| 345 | for (slice) |sym| { | 345 | for (slice) |sym| { |
| 346 | const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx)); | ||
| 347 | |||
| 346 | if (Symbol.isStab(sym)) { | 348 | if (Symbol.isStab(sym)) { |
| 347 | log.err("TODO handle stabs embedded within object files", .{}); | 349 | log.err("stab {s} in {s}", .{ sym_name, self.name.? }); |
| 348 | return error.HandleStabsInObjects; | 350 | return error.UnhandledSymbolType; |
| 351 | } | ||
| 352 | if (Symbol.isIndr(sym)) { | ||
| 353 | log.err("indirect symbol {s} in {s}", .{ sym_name, self.name.? }); | ||
| 354 | return error.UnhandledSymbolType; | ||
| 355 | } | ||
| 356 | if (Symbol.isAbs(sym)) { | ||
| 357 | log.err("absolute symbol {s} in {s}", .{ sym_name, self.name.? }); | ||
| 358 | return error.UnhandledSymbolType; | ||
| 349 | } | 359 | } |
| 350 | 360 | ||
| 351 | const sym_name = mem.spanZ(@ptrCast([*:0]const u8, strtab.ptr + sym.n_strx)); | ||
| 352 | const name = try self.allocator.dupe(u8, sym_name); | 361 | const name = try self.allocator.dupe(u8, sym_name); |
| 353 | |||
| 354 | const symbol: *Symbol = symbol: { | 362 | const symbol: *Symbol = symbol: { |
| 355 | if (Symbol.isSect(sym)) { | 363 | if (Symbol.isSect(sym)) { |
| 356 | const linkage: Symbol.Regular.Linkage = linkage: { | 364 | const linkage: Symbol.Regular.Linkage = linkage: { |
| ... | @@ -374,6 +382,14 @@ pub fn parseSymbols(self: *Object) !void { | ... | @@ -374,6 +382,14 @@ pub fn parseSymbols(self: *Object) !void { |
| 374 | break :symbol &regular.base; | 382 | break :symbol &regular.base; |
| 375 | } | 383 | } |
| 376 | 384 | ||
| 385 | if (sym.n_value != 0) { | ||
| 386 | log.err("common symbol {s} in {s}", .{ sym_name, self.name.? }); | ||
| 387 | return error.UnhandledSymbolType; | ||
| 388 | // const comm_size = sym.n_value; | ||
| 389 | // const comm_align = (sym.n_desc >> 8) & 0x0f; | ||
| 390 | // log.warn("Common symbol: size 0x{x}, align 0x{x}", .{ comm_size, comm_align }); | ||
| 391 | } | ||
| 392 | |||
| 377 | const undef = try self.allocator.create(Symbol.Unresolved); | 393 | const undef = try self.allocator.create(Symbol.Unresolved); |
| 378 | errdefer self.allocator.destroy(undef); | 394 | errdefer self.allocator.destroy(undef); |
| 379 | undef.* = .{ | 395 | undef.* = .{ |
src/link/MachO/Symbol.zig+10| ... | @@ -133,6 +133,16 @@ pub fn isUndf(sym: macho.nlist_64) bool { | ... | @@ -133,6 +133,16 @@ pub fn isUndf(sym: macho.nlist_64) bool { |
| 133 | return type_ == macho.N_UNDF; | 133 | return type_ == macho.N_UNDF; |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | pub fn isIndr(sym: macho.nlist_64) bool { | ||
| 137 | const type_ = macho.N_TYPE & sym.n_type; | ||
| 138 | return type_ == macho.N_INDR; | ||
| 139 | } | ||
| 140 | |||
| 141 | pub fn isAbs(sym: macho.nlist_64) bool { | ||
| 142 | const type_ = macho.N_TYPE & sym.n_type; | ||
| 143 | return type_ == macho.N_ABS; | ||
| 144 | } | ||
| 145 | |||
| 136 | pub fn isWeakDef(sym: macho.nlist_64) bool { | 146 | pub fn isWeakDef(sym: macho.nlist_64) bool { |
| 137 | return (sym.n_desc & macho.N_WEAK_DEF) != 0; | 147 | return (sym.n_desc & macho.N_WEAK_DEF) != 0; |
| 138 | } | 148 | } |
src/link/MachO/Zld.zig+21-10| ... | @@ -82,7 +82,7 @@ unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, | ... | @@ -82,7 +82,7 @@ unresolved: std.StringArrayHashMapUnmanaged(*Symbol) = .{}, |
| 82 | strtab: std.ArrayListUnmanaged(u8) = .{}, | 82 | strtab: std.ArrayListUnmanaged(u8) = .{}, |
| 83 | strtab_dir: std.StringHashMapUnmanaged(u32) = .{}, | 83 | strtab_dir: std.StringHashMapUnmanaged(u32) = .{}, |
| 84 | 84 | ||
| 85 | threadlocal_offsets: std.ArrayListUnmanaged(u64) = .{}, | 85 | threadlocal_offsets: std.ArrayListUnmanaged(TlvOffset) = .{}, // TODO merge with Symbol abstraction |
| 86 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, | 86 | local_rebases: std.ArrayListUnmanaged(Pointer) = .{}, |
| 87 | stubs: std.ArrayListUnmanaged(*Symbol) = .{}, | 87 | stubs: std.ArrayListUnmanaged(*Symbol) = .{}, |
| 88 | got_entries: std.ArrayListUnmanaged(*Symbol) = .{}, | 88 | got_entries: std.ArrayListUnmanaged(*Symbol) = .{}, |
| ... | @@ -92,6 +92,15 @@ stub_helper_stubs_start_off: ?u64 = null, | ... | @@ -92,6 +92,15 @@ stub_helper_stubs_start_off: ?u64 = null, |
| 92 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, | 92 | mappings: std.AutoHashMapUnmanaged(MappingKey, SectionMapping) = .{}, |
| 93 | unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, | 93 | unhandled_sections: std.AutoHashMapUnmanaged(MappingKey, u0) = .{}, |
| 94 | 94 | ||
| 95 | const TlvOffset = struct { | ||
| 96 | source_addr: u64, | ||
| 97 | offset: u64, | ||
| 98 | |||
| 99 | fn cmp(context: void, a: TlvOffset, b: TlvOffset) bool { | ||
| 100 | return a.source_addr < b.source_addr; | ||
| 101 | } | ||
| 102 | }; | ||
| 103 | |||
| 95 | const MappingKey = struct { | 104 | const MappingKey = struct { |
| 96 | object_id: u16, | 105 | object_id: u16, |
| 97 | source_sect_id: u16, | 106 | source_sect_id: u16, |
| ... | @@ -277,7 +286,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | ... | @@ -277,7 +286,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 277 | 286 | ||
| 278 | object.* = Object.init(self.allocator); | 287 | object.* = Object.init(self.allocator); |
| 279 | object.arch = self.arch.?; | 288 | object.arch = self.arch.?; |
| 280 | object.name = try self.allocator.dupe(u8, input.name); | 289 | object.name = input.name; |
| 281 | object.file = input.file; | 290 | object.file = input.file; |
| 282 | try object.parse(); | 291 | try object.parse(); |
| 283 | try self.objects.append(self.allocator, object); | 292 | try self.objects.append(self.allocator, object); |
| ... | @@ -288,7 +297,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { | ... | @@ -288,7 +297,7 @@ fn parseInputFiles(self: *Zld, files: []const []const u8) !void { |
| 288 | 297 | ||
| 289 | archive.* = Archive.init(self.allocator); | 298 | archive.* = Archive.init(self.allocator); |
| 290 | archive.arch = self.arch.?; | 299 | archive.arch = self.arch.?; |
| 291 | archive.name = try self.allocator.dupe(u8, input.name); | 300 | archive.name = input.name; |
| 292 | archive.file = input.file; | 301 | archive.file = input.file; |
| 293 | try archive.parse(); | 302 | try archive.parse(); |
| 294 | try self.archives.append(self.allocator, archive); | 303 | try self.archives.append(self.allocator, archive); |
| ... | @@ -1362,10 +1371,7 @@ fn resolveSymbols(self: *Zld) !void { | ... | @@ -1362,10 +1371,7 @@ fn resolveSymbols(self: *Zld) !void { |
| 1362 | }; | 1371 | }; |
| 1363 | assert(offsets.items.len > 0); | 1372 | assert(offsets.items.len > 0); |
| 1364 | 1373 | ||
| 1365 | const object = try self.allocator.create(Object); | 1374 | const object = try archive.parseObject(offsets.items[0]); |
| 1366 | errdefer self.allocator.destroy(object); | ||
| 1367 | |||
| 1368 | object.* = try archive.parseObject(offsets.items[0]); | ||
| 1369 | try self.objects.append(self.allocator, object); | 1375 | try self.objects.append(self.allocator, object); |
| 1370 | try self.resolveSymbolsInObject(object); | 1376 | try self.resolveSymbolsInObject(object); |
| 1371 | 1377 | ||
| ... | @@ -1567,7 +1573,10 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { | ... | @@ -1567,7 +1573,10 @@ fn resolveRelocsAndWriteSections(self: *Zld) !void { |
| 1567 | }; | 1573 | }; |
| 1568 | // Since we require TLV data to always preceed TLV bss section, we calculate | 1574 | // Since we require TLV data to always preceed TLV bss section, we calculate |
| 1569 | // offsets wrt to the former if it is defined; otherwise, wrt to the latter. | 1575 | // offsets wrt to the former if it is defined; otherwise, wrt to the latter. |
| 1570 | try self.threadlocal_offsets.append(self.allocator, args.target_addr - base_addr); | 1576 | try self.threadlocal_offsets.append(self.allocator, .{ |
| 1577 | .source_addr = args.source_addr, | ||
| 1578 | .offset = args.target_addr - base_addr, | ||
| 1579 | }); | ||
| 1571 | } | 1580 | } |
| 1572 | }, | 1581 | }, |
| 1573 | .got_page, .got_page_off, .got_load, .got => { | 1582 | .got_page, .got_page_off, .got_load, .got => { |
| ... | @@ -2093,10 +2102,12 @@ fn flush(self: *Zld) !void { | ... | @@ -2093,10 +2102,12 @@ fn flush(self: *Zld) !void { |
| 2093 | var stream = std.io.fixedBufferStream(buffer); | 2102 | var stream = std.io.fixedBufferStream(buffer); |
| 2094 | var writer = stream.writer(); | 2103 | var writer = stream.writer(); |
| 2095 | 2104 | ||
| 2105 | std.sort.sort(TlvOffset, self.threadlocal_offsets.items, {}, TlvOffset.cmp); | ||
| 2106 | |||
| 2096 | const seek_amt = 2 * @sizeOf(u64); | 2107 | const seek_amt = 2 * @sizeOf(u64); |
| 2097 | while (self.threadlocal_offsets.popOrNull()) |offset| { | 2108 | for (self.threadlocal_offsets.items) |tlv| { |
| 2098 | try writer.context.seekBy(seek_amt); | 2109 | try writer.context.seekBy(seek_amt); |
| 2099 | try writer.writeIntLittle(u64, offset); | 2110 | try writer.writeIntLittle(u64, tlv.offset); |
| 2100 | } | 2111 | } |
| 2101 | 2112 | ||
| 2102 | try self.file.?.pwriteAll(buffer, sect.offset); | 2113 | try self.file.?.pwriteAll(buffer, sect.offset); |
src/link/MachO/reloc/aarch64.zig+1-1| ... | @@ -25,7 +25,7 @@ pub const Branch = struct { | ... | @@ -25,7 +25,7 @@ pub const Branch = struct { |
| 25 | log.debug(" | displacement 0x{x}", .{displacement}); | 25 | log.debug(" | displacement 0x{x}", .{displacement}); |
| 26 | 26 | ||
| 27 | var inst = branch.inst; | 27 | var inst = branch.inst; |
| 28 | inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement) >> 2); | 28 | inst.unconditional_branch_immediate.imm26 = @truncate(u26, @bitCast(u28, displacement >> 2)); |
| 29 | mem.writeIntLittle(u32, branch.base.code[0..4], inst.toU32()); | 29 | mem.writeIntLittle(u32, branch.base.code[0..4], inst.toU32()); |
| 30 | } | 30 | } |
| 31 | }; | 31 | }; |
src/stage1/codegen.cpp+3-1| ... | @@ -4880,6 +4880,9 @@ static LLVMValueRef ir_render_asm_gen(CodeGen *g, IrExecutableGen *executable, I | ... | @@ -4880,6 +4880,9 @@ static LLVMValueRef ir_render_asm_gen(CodeGen *g, IrExecutableGen *executable, I |
| 4880 | type_ref = get_llvm_type(g, wider_type); | 4880 | type_ref = get_llvm_type(g, wider_type); |
| 4881 | value_ref = gen_widen_or_shorten(g, false, type, wider_type, value_ref); | 4881 | value_ref = gen_widen_or_shorten(g, false, type, wider_type, value_ref); |
| 4882 | } | 4882 | } |
| 4883 | } else if (handle_is_ptr(g, type)) { | ||
| 4884 | ZigType *gen_type = get_pointer_to_type(g, type, true); | ||
| 4885 | type_ref = get_llvm_type(g, gen_type); | ||
| 4883 | } | 4886 | } |
| 4884 | 4887 | ||
| 4885 | param_types[param_index] = type_ref; | 4888 | param_types[param_index] = type_ref; |
| ... | @@ -9302,7 +9305,6 @@ static void init(CodeGen *g) { | ... | @@ -9302,7 +9305,6 @@ static void init(CodeGen *g) { |
| 9302 | char *layout_str = LLVMCopyStringRepOfTargetData(g->target_data_ref); | 9305 | char *layout_str = LLVMCopyStringRepOfTargetData(g->target_data_ref); |
| 9303 | LLVMSetDataLayout(g->module, layout_str); | 9306 | LLVMSetDataLayout(g->module, layout_str); |
| 9304 | 9307 | ||
| 9305 | |||
| 9306 | assert(g->pointer_size_bytes == LLVMPointerSize(g->target_data_ref)); | 9308 | assert(g->pointer_size_bytes == LLVMPointerSize(g->target_data_ref)); |
| 9307 | g->is_big_endian = (LLVMByteOrder(g->target_data_ref) == LLVMBigEndian); | 9309 | g->is_big_endian = (LLVMByteOrder(g->target_data_ref) == LLVMBigEndian); |
| 9308 | 9310 |
src/stage1/parser.cpp+10-1| ... | @@ -825,7 +825,16 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { | ... | @@ -825,7 +825,16 @@ static AstNode *ast_parse_fn_proto(ParseContext *pc) { |
| 825 | AstNode *return_type = nullptr; | 825 | AstNode *return_type = nullptr; |
| 826 | if (anytype == nullptr) { | 826 | if (anytype == nullptr) { |
| 827 | exmark = eat_token_if(pc, TokenIdBang); | 827 | exmark = eat_token_if(pc, TokenIdBang); |
| 828 | return_type = ast_expect(pc, ast_parse_type_expr); | 828 | return_type = ast_parse_type_expr(pc); |
| 829 | if (return_type == nullptr) { | ||
| 830 | Token *next = peek_token(pc); | ||
| 831 | ast_error( | ||
| 832 | pc, | ||
| 833 | next, | ||
| 834 | "expected return type (use 'void' to return nothing), found: '%s'", | ||
| 835 | token_name(next->id) | ||
| 836 | ); | ||
| 837 | } | ||
| 829 | } | 838 | } |
| 830 | 839 | ||
| 831 | AstNode *res = ast_create_node(pc, NodeTypeFnProto, first); | 840 | AstNode *res = ast_create_node(pc, NodeTypeFnProto, first); |
test/behavior/align.zig+3| ... | @@ -142,6 +142,7 @@ fn alignedBig() align(16) i32 { | ... | @@ -142,6 +142,7 @@ fn alignedBig() align(16) i32 { |
| 142 | test "@alignCast functions" { | 142 | test "@alignCast functions" { |
| 143 | // function alignment is a compile error on wasm32/wasm64 | 143 | // function alignment is a compile error on wasm32/wasm64 |
| 144 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; | 144 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; |
| 145 | if (native_arch == .thumb) return error.SkipZigTest; | ||
| 145 | 146 | ||
| 146 | expect(fnExpectsOnly1(simple4) == 0x19); | 147 | expect(fnExpectsOnly1(simple4) == 0x19); |
| 147 | } | 148 | } |
| ... | @@ -158,6 +159,7 @@ fn simple4() align(4) i32 { | ... | @@ -158,6 +159,7 @@ fn simple4() align(4) i32 { |
| 158 | test "generic function with align param" { | 159 | test "generic function with align param" { |
| 159 | // function alignment is a compile error on wasm32/wasm64 | 160 | // function alignment is a compile error on wasm32/wasm64 |
| 160 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; | 161 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; |
| 162 | if (native_arch == .thumb) return error.SkipZigTest; | ||
| 161 | 163 | ||
| 162 | expect(whyWouldYouEverDoThis(1) == 0x1); | 164 | expect(whyWouldYouEverDoThis(1) == 0x1); |
| 163 | expect(whyWouldYouEverDoThis(4) == 0x1); | 165 | expect(whyWouldYouEverDoThis(4) == 0x1); |
| ... | @@ -339,6 +341,7 @@ test "align(@alignOf(T)) T does not force resolution of T" { | ... | @@ -339,6 +341,7 @@ test "align(@alignOf(T)) T does not force resolution of T" { |
| 339 | test "align(N) on functions" { | 341 | test "align(N) on functions" { |
| 340 | // function alignment is a compile error on wasm32/wasm64 | 342 | // function alignment is a compile error on wasm32/wasm64 |
| 341 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; | 343 | if (native_arch == .wasm32 or native_arch == .wasm64) return error.SkipZigTest; |
| 344 | if (native_arch == .thumb) return error.SkipZigTest; | ||
| 342 | 345 | ||
| 343 | expect((@ptrToInt(overaligned_fn) & (0x1000 - 1)) == 0); | 346 | expect((@ptrToInt(overaligned_fn) & (0x1000 - 1)) == 0); |
| 344 | } | 347 | } |
test/behavior/asm.zig+15| ... | @@ -87,6 +87,21 @@ test "sized integer/float in asm input" { | ... | @@ -87,6 +87,21 @@ test "sized integer/float in asm input" { |
| 87 | ); | 87 | ); |
| 88 | } | 88 | } |
| 89 | 89 | ||
| 90 | test "struct/array/union types as input values" { | ||
| 91 | asm volatile ("" | ||
| 92 | : | ||
| 93 | : [_] "m" (@as([1]u32, undefined)) | ||
| 94 | ); // fails | ||
| 95 | asm volatile ("" | ||
| 96 | : | ||
| 97 | : [_] "m" (@as(struct { x: u32, y: u8 }, undefined)) | ||
| 98 | ); // fails | ||
| 99 | asm volatile ("" | ||
| 100 | : | ||
| 101 | : [_] "m" (@as(union { x: u32, y: u8 }, undefined)) | ||
| 102 | ); // fails | ||
| 103 | } | ||
| 104 | |||
| 90 | extern fn this_is_my_alias() i32; | 105 | extern fn this_is_my_alias() i32; |
| 91 | 106 | ||
| 92 | export fn derp() i32 { | 107 | export fn derp() i32 { |
test/behavior/async_fn.zig+4-1| ... | @@ -1,5 +1,5 @@ | ... | @@ -1,5 +1,5 @@ |
| 1 | const std = @import("std"); | 1 | const std = @import("std"); |
| 2 | const builtin = std.builtin; | 2 | const builtin = @import("builtin"); |
| 3 | const expect = std.testing.expect; | 3 | const expect = std.testing.expect; |
| 4 | const expectEqual = std.testing.expectEqual; | 4 | const expectEqual = std.testing.expectEqual; |
| 5 | const expectEqualStrings = std.testing.expectEqualStrings; | 5 | const expectEqualStrings = std.testing.expectEqualStrings; |
| ... | @@ -110,6 +110,9 @@ test "calling an inferred async function" { | ... | @@ -110,6 +110,9 @@ test "calling an inferred async function" { |
| 110 | } | 110 | } |
| 111 | 111 | ||
| 112 | test "@frameSize" { | 112 | test "@frameSize" { |
| 113 | if (builtin.target.cpu.arch == .thumb or builtin.target.cpu.arch == .thumbeb) | ||
| 114 | return error.SkipZigTest; | ||
| 115 | |||
| 113 | const S = struct { | 116 | const S = struct { |
| 114 | fn doTheTest() void { | 117 | fn doTheTest() void { |
| 115 | { | 118 | { |
test/behavior/atomics.zig+3-5| ... | @@ -149,12 +149,10 @@ fn testAtomicStore() void { | ... | @@ -149,12 +149,10 @@ fn testAtomicStore() void { |
| 149 | } | 149 | } |
| 150 | 150 | ||
| 151 | test "atomicrmw with floats" { | 151 | test "atomicrmw with floats" { |
| 152 | if (builtin.target.cpu.arch == .aarch64 or | 152 | switch (builtin.target.cpu.arch) { |
| 153 | builtin.target.cpu.arch == .arm or | ||
| 154 | builtin.target.cpu.arch == .riscv64) | ||
| 155 | { | ||
| 156 | // https://github.com/ziglang/zig/issues/4457 | 153 | // https://github.com/ziglang/zig/issues/4457 |
| 157 | return error.SkipZigTest; | 154 | .aarch64, .arm, .thumb, .riscv64 => return error.SkipZigTest, |
| 155 | else => {}, | ||
| 158 | } | 156 | } |
| 159 | testAtomicRmwFloat(); | 157 | testAtomicRmwFloat(); |
| 160 | comptime testAtomicRmwFloat(); | 158 | comptime testAtomicRmwFloat(); |
test/behavior/vector.zig-15| ... | @@ -510,21 +510,6 @@ test "vector reduce operation" { | ... | @@ -510,21 +510,6 @@ test "vector reduce operation" { |
| 510 | const N = @typeInfo(@TypeOf(x)).Array.len; | 510 | const N = @typeInfo(@TypeOf(x)).Array.len; |
| 511 | const TX = @typeInfo(@TypeOf(x)).Array.child; | 511 | const TX = @typeInfo(@TypeOf(x)).Array.child; |
| 512 | 512 | ||
| 513 | // wasmtime: unknown import: `env::fminf` has not been defined | ||
| 514 | // https://github.com/ziglang/zig/issues/8131 | ||
| 515 | switch (builtin.target.cpu.arch) { | ||
| 516 | .wasm32 => switch (@typeInfo(TX)) { | ||
| 517 | .Float => switch (op) { | ||
| 518 | .Min, | ||
| 519 | .Max, | ||
| 520 | => return, | ||
| 521 | else => {}, | ||
| 522 | }, | ||
| 523 | else => {}, | ||
| 524 | }, | ||
| 525 | else => {}, | ||
| 526 | } | ||
| 527 | |||
| 528 | var r = @reduce(op, @as(Vector(N, TX), x)); | 513 | var r = @reduce(op, @as(Vector(N, TX), x)); |
| 529 | switch (@typeInfo(TX)) { | 514 | switch (@typeInfo(TX)) { |
| 530 | .Int, .Bool => expectEqual(expected, r), | 515 | .Int, .Bool => expectEqual(expected, r), |