From 491d8073050993034e60e548efc46016058a4e51 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mos=C3=A8=20Giordano?= Date: Mon, 22 Jun 2020 00:16:28 +0100 Subject: [PATCH] Add `extended_platform_key_abi` --- src/Platforms.jl | 54 ++++++++++++++++++++++++++++++++++++++++++++++- test/platforms.jl | 27 +++++++++++++++++++++++- 2 files changed, 79 insertions(+), 2 deletions(-) diff --git a/src/Platforms.jl b/src/Platforms.jl index 1187a0f5..fe27bc96 100644 --- a/src/Platforms.jl +++ b/src/Platforms.jl @@ -1,6 +1,6 @@ using Pkg.Artifacts, Pkg.BinaryPlatforms, Logging -export AnyPlatform, ExtendedPlatform, base_platform +export AnyPlatform, ExtendedPlatform, base_platform, extended_platform_key_abi """ AnyPlatform() @@ -207,3 +207,55 @@ function Pkg.Artifacts.pack_platform!(meta::Dict, p::ExtendedPlatform) # override the default ones Artifacts.pack_platform!(meta, base_platform(p)) end + +# Get the list of CPU features for the host system querying libLLVM +function get_cpu_features() + if VERSION < v"1.4" + error("Cannot automatically detect the features of the CPU with this version of Julia!") + end + features = filter(f -> startswith(f, "+"), + split(unsafe_string(ccall(:LLVMGetHostCPUFeatures, Cstring, ())), + ",")) + return sort!(replace.(features, r"^\+" => "")) +end + +# Get the microarchitecture of a CPU from the list of its features. +# TODO: support other architectures, like armv7l and aarch64. +function march(cpu_features::Vector{String}) + # List of CPU features from https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html + if all(in(cpu_features), ("mmx", "sse", "sse2")) # Generic x86_64 + if all(in(cpu_features), ("sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx", "aes", "pclmul")) # avx + if all(in(cpu_features), ("movbe", "avx2", "fsgsbase", "rdrnd", "fma", "bmi", "bmi2", "f16c")) # avx2 + # Some names are different: ADCX -> ADX, PREFETCHW -> PRFCHW + if all(in(cpu_features), ("pku", "rdseed", "adx", "prfchw", "clflushopt", "xsavec", "xsaves", "avx512f", "clwb", "avx512vl", "avx512bw", "avx512dq", "avx512cd")) # avx512 + return "avx512" + end + return "avx2" + end + return "avx" + end + return "x86_64" + else + @warn "Cannot determine the microarchitecture for the given set of features!" + return nothing + end +end + +# NOTE: the keyword arguments are *not* part of the public API, they're only +# used for testing purposes and they may change in the future. +""" + extended_platform_key_abi() + +Returns the `Platform` representing the current platform. It is an +[`ExtendedPlatform`](@ref) if it possible to detect additional features, like +the microarchitecture. +""" +function extended_platform_key_abi(; p::Platform = platform_key_abi(), + cpu_features::Vector{String} = get_cpu_features()) + + if arch(p) == :x86_64 + return ExtendedPlatform(p; march=march(cpu_features)) + else + return p + end +end diff --git a/test/platforms.jl b/test/platforms.jl index 741c65a9..c848b7c1 100644 --- a/test/platforms.jl +++ b/test/platforms.jl @@ -1,7 +1,7 @@ using Test using Pkg, Pkg.PlatformEngines, Pkg.BinaryPlatforms, Pkg.Artifacts using BinaryBuilderBase -using BinaryBuilderBase: abi_agnostic, get_concrete_platform, march +using BinaryBuilderBase: abi_agnostic, get_concrete_platform, march, get_cpu_features @testset "Supported Platforms" begin all = supported_platforms() @@ -205,6 +205,31 @@ end # Extending different platforms @test !platforms_match(ExtendedPlatform(Linux(:i686); cuda="10.1"), ExtendedPlatform(FreeBSD(:x86_64); cuda="11.1")) end + + @testset "extended_platform_key_abi" begin + if VERSION >= v"1.4" + @test get_cpu_features() isa Vector{String} + else + @test_throws ErrorException get_cpu_features() + end + + @test @test_logs (:warn, r"^Cannot determine the microarchitecture") march(String[]) === nothing + for (cpu_features, μarch) in ( + (["mmx", "sse", "sse2"], "x86_64"), + # The following sets of CPU features are obtained on real machines + (["64bit", "aes", "avx", "cmov", "cx16", "fma4", "lzcnt", "mmx", "pclmul", "popcnt", "prfchw", "sahf", "sse", "sse2", "sse3", "sse4.1", "sse4.2", "sse4a", "ssse3", "xop", "xsave"], "avx"), + (["64bit", "aes", "avx", "avx2", "bmi", "bmi2", "cmov", "cx16", "cx8", "f16c", "fma", "fsgsbase", "fxsr", "invpcid", "lzcnt", "mmx", "movbe", "pclmul", "popcnt", "rdrnd", "sahf", "sse", "sse2", "sse3", "sse4.1", "sse4.2", "ssse3", "xsave", "xsaveopt"], "avx2"), + (["64bit", "aes", "avx", "avx2", "bmi", "bmi2", "cmov", "cx16", "f16c", "fma", "fsgsbase", "invpcid", "lzcnt", "mmx", "movbe", "pclmul", "popcnt", "rdrnd", "sahf", "sse", "sse2", "sse3", "sse4.1", "sse4.2", "ssse3", "xsave", "xsaveopt"], "avx2"), + (["64bit", "adx", "aes", "avx", "avx2", "bmi", "bmi2", "clflushopt", "clwb", "clzero", "cmov", "cx16", "f16c", "fma", "fsgsbase", "lzcnt", "mmx", "movbe", "mwaitx", "pclmul", "popcnt", "prfchw", "rdpid", "rdrnd", "rdseed", "sahf", "sha", "sse", "sse2", "sse3", "sse4.1", "sse4.2", "sse4a", "ssse3", "wbnoinvd", "xsave", "xsavec", "xsaveopt", "xsaves"], "avx2"), + (["64bit", "adx", "aes", "avx", "avx2", "avx512bw", "avx512cd", "avx512dq", "avx512f", "avx512vl", "avx512vnni", "bmi", "bmi2", "clflushopt", "clwb", "cmov", "cx16", "cx8", "f16c", "fma", "fsgsbase", "fxsr", "invpcid", "lzcnt", "mmx", "movbe", "mpx", "pclmul", "pku", "popcnt", "prfchw", "rdrnd", "rdseed", "rtm", "sahf", "sse", "sse2", "sse3", "sse4.1", "sse4.2", "ssse3", "xsave", "xsavec", "xsaveopt", "xsaves"], "avx512") + ) + @test march(cpu_features) == μarch + p = Linux(:x86_64) + @test extended_platform_key_abi(; p=p, cpu_features=cpu_features) == ExtendedPlatform(p; march=μarch) + end + p = Linux(:i686) + @test extended_platform_key_abi(; p=p, cpu_features=String[]) == p + end end @testset "AnyPlatform" begin