diff --git a/lib/std/zig/target.zig b/lib/std/zig/target.zig index 3f4f135470fa6a578e01e7f8a324083fb10e7423..7dc176756ec65c3ec9b4737c40c1a2c8314aed66 100644 --- a/lib/std/zig/target.zig +++ b/lib/std/zig/target.zig @@ -537,6 +537,164 @@ pub fn compilerRtFloatAbi(target: *const std.Target, bits: u16) std.Target.Abi.F return .hard; } +fn supportedCompatArch(host: *const std.Target, arch: std.Target.Cpu.Arch) bool { + // aarch64-freebsd and aarch64-linux can technically run 32-bit ARM binaries, but that depends + // on AArch32 support in the CPU. Since modern AArch64 CPUs have largely dropped this support, + // avoid reporting compatibility for 32-bit here since we'd just build a bunch of test binaries + // that never get run anyway. This added almost an hour's worth of useless work to aarch64-linux + // CI, for example. + // + // riscv64-linux and riscv64-netbsd similarly support 32-bit binaries. However, this requires a + // very recent kernel and for the kernel feature to be enabled. Additionally, contemporary + // RISC-V hardware is just too slow to justify building the 32-bit binaries. + return switch (host.os.tag) { + .illumos => switch (host.cpu.arch) { + .x86_64 => arch == .x86, + else => false, + }, + .linux => switch (host.cpu.arch) { + .mips64 => arch == .mips, + .mips64el => arch == .mipsel, + .powerpc64 => arch == .powerpc, + .sparc64 => arch == .sparc, + .x86_64 => arch == .x86, + else => false, + }, + .netbsd => switch (host.cpu.arch) { + .sparc64 => arch == .sparc, + .x86_64 => arch == .x86, + else => false, + }, + .windows => switch (host.cpu.arch) { + .x86_64 => arch == .x86, + else => false, + }, + else => false, + }; +} + +/// Intended for test code to determine whether it makes sense to run a test for a particular target +/// on the host. This is not an objective check; it is best-effort and also makes subjective +/// judgements for some targets. +pub fn isNative(query: *const std.Target.Query, target: *const std.Target, host: *const std.Target) bool { + if (query.isNative()) return true; + + if (target.cpu.arch != host.cpu.arch and !supportedCompatArch(host, target.cpu.arch)) + return false; + + if (target.os.tag != host.os.tag) + return false; + + // This check is really only necessary for the case where `host.cpu.arch.isAarch64()` and + // `target.cpu.arch.isArm()`. As they are wholly separate `std.Target` families with their own + // feature bits, the logic below would produce complete nonsense. + // + // This does mean that we aren't actually checking feature compatibility between these two + // families even though we should. That's not a problem currently, but in the future, we may + // need to add a special code path just for this specific case... + if (target.cpu.arch.family() != host.cpu.arch.family()) + return true; + + // Remove features that don't actually affect compatibility. + const irrelevant: std.Target.Cpu.Feature.Set = switch (host.cpu.arch) { + .x86_64 => std.Target.x86.featureSet(&.{ + .@"16bit_mode", + .@"32bit_mode", + .@"64bit", + .false_deps_bls, + .false_deps_compress, + .false_deps_expand, + .false_deps_getmant, + .false_deps_lzcnt, + .false_deps_mulc, + .false_deps_mullq, + .false_deps_perm, + .false_deps_popcnt, + .false_deps_range, + .false_deps_tzcnt, + .fast_11bytenop, + .fast_15bytenop, + .fast_7bytenop, + .fast_bextr, + .fast_dpwssd, + .fast_gather, + .fast_hops, + .fast_imm16, + .fast_lzcnt, + .fast_movbe, + .fast_scalar_fsqrt, + .fast_scalar_shift_masks, + .fast_shld_rotate, + .fast_variable_crosslane_shuffle, + .fast_variable_perlane_shuffle, + .fast_vector_fsqrt, + .fast_vector_shift_masks, + .faster_shift_than_shuffle, + .no_bypass_delay, + .no_bypass_delay_blend, + .no_bypass_delay_mov, + .no_bypass_delay_shuffle, + .prefer_128_bit, + .prefer_256_bit, + .prefer_legacy_setcc, + .prefer_mask_registers, + .prefer_movmsk_over_vtest, + .prefer_ndd_mem, + .prefer_no_gather, + .prefer_no_scatter, + .slow_3ops_lea, + .slow_incdec, + .slow_indirect_call, + .slow_lea, + .slow_pmaddwd, + .slow_pmulld, + .slow_pmullq, + .slow_shld, + .slow_two_mem_ops, + .slow_unaligned_mem_16, + .slow_unaligned_mem_32, + }), + .aarch64, .aarch64_be => std.Target.aarch64.featureSet(&.{ + .addr_lsl_slow_14, + .align_cmp_csel_pairs, + .alu_lsl_fast, + .avoid_ldapur, + .disable_fast_inc_vl, + .exynos_cheap_as_move, + .fast_ld1_single, + .fixed_load_latency_4, + .fuse_address, + .fuse_addsub_2reg_const1, + .fuse_adrp_add, + .fuse_aes, + .fuse_arith_logic, + .fuse_crypto_eor, + .fuse_csel, + .fuse_cset, + .fuse_fcsel, + .fuse_literals, + .has_limited_64bit_vector_mul_bandwidth, + .predictable_select_expensive, + .slow_misaligned_128store, + .slow_paired_128, + .slow_strqro_store, + .use_experimental_zeroing_pseudos, + .use_fixed_over_scalable_if_equal_cost, + .use_postra_scheduler, + .use_reciprocal_square_root, + .use_wzr_to_vec_move, + }), + else => .empty, + }; + var set = target.cpu.features; + set.removeFeatureSet(irrelevant); + + if (!host.cpu.features.isSuperSetOf(set)) + return false; + + return true; +} + const std = @import("std"); const assert = std.debug.assert; const Allocator = std.mem.Allocator; diff --git a/test/src/Cases.zig b/test/src/Cases.zig index b4fe4e65337b070c8ae99e867c418657b607b0d8..c6b3eb07d1ed6efdfd626952bac4ce484ca4efef 100644 --- a/test/src/Cases.zig +++ b/test/src/Cases.zig @@ -495,7 +495,7 @@ pub fn lowerToBuildSteps( if (case.case.? == .Error and options.skip_compile_errors) continue; - if (options.skip_non_native and !@import("../tests.zig").isNative(&case.target, &b.graph.host.result)) + if (options.skip_non_native and !std.zig.target.isNative(&case.target.query, &case.target.result, &b.graph.host.result)) continue; if (options.skip_spirv and case.target.query.cpu_arch != null and case.target.query.cpu_arch.?.isSpirV()) continue; diff --git a/test/src/ErrorTrace.zig b/test/src/ErrorTrace.zig index 57b26d492fe9a59fa741cd219cc9d27ec9d93ead..8a09ccee4088fa98658c24a6a2382d4e3f7593a4 100644 --- a/test/src/ErrorTrace.zig +++ b/test/src/ErrorTrace.zig @@ -385,7 +385,7 @@ pub fn addCases(self: *ErrorTrace) void { if (!self.options.test_extra_targets and params.extra_target) continue; - if (self.options.skip_non_native and !tests.isNative(&resolved_target, &b.graph.host.result)) continue; + if (self.options.skip_non_native and !std.zig.target.isNative(&resolved_target.query, &resolved_target.result, &b.graph.host.result)) continue; if (self.options.skip_freebsd and target.os.tag == .freebsd) continue; if (self.options.skip_netbsd and target.os.tag == .netbsd) continue; diff --git a/test/src/StackTrace.zig b/test/src/StackTrace.zig index 156ac8984eaaca578e3752533d8f775029e030c2..c0ebbd71f86f08401b612f99513d06796b44bfd8 100644 --- a/test/src/StackTrace.zig +++ b/test/src/StackTrace.zig @@ -995,7 +995,7 @@ pub fn addCases(self: *StackTrace) void { if (!self.options.test_extra_targets and params.extra_target) continue; - if (self.options.skip_non_native and !tests.isNative(&resolved_target, &b.graph.host.result)) continue; + if (self.options.skip_non_native and !std.zig.target.isNative(&resolved_target.query, &resolved_target.result, &b.graph.host.result)) continue; if (self.options.skip_freebsd and target.os.tag == .freebsd) continue; if (self.options.skip_netbsd and target.os.tag == .netbsd) continue; diff --git a/test/tests.zig b/test/tests.zig index c3c501c99d71403862b8f3bcbea7be5367184ae7..46fa29e9312190350e72deed1848fa27336a9a94 100644 --- a/test/tests.zig +++ b/test/tests.zig @@ -2323,162 +2323,6 @@ pub const debugger_matrix: []const RunnerTarget = &.{ }, }; -fn supportedCompatArch(host: *const std.Target, arch: std.Target.Cpu.Arch) bool { - // aarch64-freebsd and aarch64-linux can technically run 32-bit ARM binaries, but that depends - // on AArch32 support in the CPU. Since modern AArch64 CPUs have largely dropped this support, - // avoid reporting compatibility for 32-bit here since we'd just build a bunch of test binaries - // that never get run anyway. This added almost an hour's worth of useless work to aarch64-linux - // CI, for example. - // - // riscv64-linux and riscv64-netbsd similarly support 32-bit binaries. However, this requires a - // very recent kernel and for the kernel feature to be enabled. Additionally, contemporary - // RISC-V hardware is just too slow to justify building the 32-bit binaries. - return switch (host.os.tag) { - .illumos => switch (host.cpu.arch) { - .x86_64 => arch == .x86, - else => false, - }, - .linux => switch (host.cpu.arch) { - .mips64 => arch == .mips, - .mips64el => arch == .mipsel, - .powerpc64 => arch == .powerpc, - .sparc64 => arch == .sparc, - .x86_64 => arch == .x86, - else => false, - }, - .netbsd => switch (host.cpu.arch) { - .sparc64 => arch == .sparc, - .x86_64 => arch == .x86, - else => false, - }, - .windows => switch (host.cpu.arch) { - .x86_64 => arch == .x86, - else => false, - }, - else => false, - }; -} - -pub fn isNative(actual_target: *const std.Build.ResolvedTarget, host: *const std.Target) bool { - if (actual_target.query.isNative()) return true; - const actual = &actual_target.result; - - if (actual.cpu.arch != host.cpu.arch and !supportedCompatArch(host, actual.cpu.arch)) - return false; - - if (actual.os.tag != host.os.tag) - return false; - - // This check is really only necessary for the case where `host.cpu.arch.isAarch64()` and - // `actual.cpu.arch.isArm()`. As they are wholly separate `std.Target` families with their own - // feature bits, the logic below would produce complete nonsense. - // - // This does mean that we aren't actually checking feature compatibility between these two - // families even though we should. That's not a problem currently, but in the future, we may - // need to add a special code path just for this specific case... - if (actual.cpu.arch.family() != host.cpu.arch.family()) - return true; - - // Remove features that don't actually affect compatibility. - const irrelevant: std.Target.Cpu.Feature.Set = switch (host.cpu.arch) { - .x86_64 => std.Target.x86.featureSet(&.{ - .@"16bit_mode", - .@"32bit_mode", - .@"64bit", - .false_deps_bls, - .false_deps_compress, - .false_deps_expand, - .false_deps_getmant, - .false_deps_lzcnt, - .false_deps_mulc, - .false_deps_mullq, - .false_deps_perm, - .false_deps_popcnt, - .false_deps_range, - .false_deps_tzcnt, - .fast_11bytenop, - .fast_15bytenop, - .fast_7bytenop, - .fast_bextr, - .fast_dpwssd, - .fast_gather, - .fast_hops, - .fast_imm16, - .fast_lzcnt, - .fast_movbe, - .fast_scalar_fsqrt, - .fast_scalar_shift_masks, - .fast_shld_rotate, - .fast_variable_crosslane_shuffle, - .fast_variable_perlane_shuffle, - .fast_vector_fsqrt, - .fast_vector_shift_masks, - .faster_shift_than_shuffle, - .no_bypass_delay, - .no_bypass_delay_blend, - .no_bypass_delay_mov, - .no_bypass_delay_shuffle, - .prefer_128_bit, - .prefer_256_bit, - .prefer_legacy_setcc, - .prefer_mask_registers, - .prefer_movmsk_over_vtest, - .prefer_ndd_mem, - .prefer_no_gather, - .prefer_no_scatter, - .slow_3ops_lea, - .slow_incdec, - .slow_indirect_call, - .slow_lea, - .slow_pmaddwd, - .slow_pmulld, - .slow_pmullq, - .slow_shld, - .slow_two_mem_ops, - .slow_unaligned_mem_16, - .slow_unaligned_mem_32, - }), - .aarch64, .aarch64_be => std.Target.aarch64.featureSet(&.{ - .addr_lsl_slow_14, - .align_cmp_csel_pairs, - .alu_lsl_fast, - .avoid_ldapur, - .disable_fast_inc_vl, - .exynos_cheap_as_move, - .fast_ld1_single, - .fixed_load_latency_4, - .fuse_address, - .fuse_addsub_2reg_const1, - .fuse_adrp_add, - .fuse_aes, - .fuse_arith_logic, - .fuse_crypto_eor, - .fuse_csel, - .fuse_cset, - .fuse_fcsel, - .fuse_literals, - .has_limited_64bit_vector_mul_bandwidth, - .predictable_select_expensive, - .slow_misaligned_128store, - .slow_paired_128, - .slow_strqro_store, - .use_experimental_zeroing_pseudos, - .use_fixed_over_scalable_if_equal_cost, - .use_postra_scheduler, - .use_reciprocal_square_root, - .use_wzr_to_vec_move, - }), - else => .empty, - }; - var set = actual.cpu.features; - set.removeFeatureSet(irrelevant); - - if (!host.cpu.features.isSuperSetOf(set)) - return false; - - return true; -} - pub fn addStackTraceTests(b: *std.Build, options: StackTracesContext.Options) *Step { const step = b.step("test-stack-traces", "Run the stack trace tests"); @@ -2830,7 +2674,7 @@ pub fn addModuleTests(b: *std.Build, options: ModuleTestOptions) *Step { if (!options.test_extra_targets and test_target.extra_target) continue; - if (options.skip_non_native and !isNative(&resolved_target, &b.graph.host.result)) + if (options.skip_non_native and !std.zig.target.isNative(&resolved_target.query, &resolved_target.result, &b.graph.host.result)) continue; const target = &resolved_target.result; @@ -3156,7 +3000,7 @@ pub fn addCAbiTests(b: *std.Build, options: CAbiTestOptions) *Step { const triple_txt = resolved_target.query.zigTriple(b.allocator) catch @panic("OOM"); const target = &resolved_target.result; - if (options.skip_non_native and !isNative(&resolved_target, &b.graph.host.result)) + if (options.skip_non_native and !std.zig.target.isNative(&resolved_target.query, &resolved_target.result, &b.graph.host.result)) continue; if (options.test_target_filters.len > 0) { @@ -3249,7 +3093,7 @@ pub fn addLinkTests(b: *std.Build, options: LinkTestOptions) *Step { for (link_targets) |link_target| { const resolved_target = b.resolveTargetQuery(link_target.target); - if (options.skip_non_native and !isNative(&resolved_target, &b.graph.host.result)) + if (options.skip_non_native and !std.zig.target.isNative(&resolved_target.query, &resolved_target.result, &b.graph.host.result)) continue; const target = &resolved_target.result; @@ -3399,7 +3243,7 @@ pub fn addRunnerTests( for (matrix) |test_target| { const resolved_target = b.resolveTargetQuery(test_target.target); - if (options.skip_non_native and !isNative(&resolved_target, &b.graph.host.result)) + if (options.skip_non_native and !std.zig.target.isNative(&resolved_target.query, &resolved_target.result, &b.graph.host.result)) continue; const target = &resolved_target.result;