Skip to content

Commit 491d807

Browse files
committed
Add extended_platform_key_abi
1 parent 9332d77 commit 491d807

File tree

2 files changed

+79
-2
lines changed

2 files changed

+79
-2
lines changed

src/Platforms.jl

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
using Pkg.Artifacts, Pkg.BinaryPlatforms, Logging
22

3-
export AnyPlatform, ExtendedPlatform, base_platform
3+
export AnyPlatform, ExtendedPlatform, base_platform, extended_platform_key_abi
44

55
"""
66
AnyPlatform()
@@ -207,3 +207,55 @@ function Pkg.Artifacts.pack_platform!(meta::Dict, p::ExtendedPlatform)
207207
# override the default ones
208208
Artifacts.pack_platform!(meta, base_platform(p))
209209
end
210+
211+
# Get the list of CPU features for the host system querying libLLVM
212+
function get_cpu_features()
213+
if VERSION < v"1.4"
214+
error("Cannot automatically detect the features of the CPU with this version of Julia!")
215+
end
216+
features = filter(f -> startswith(f, "+"),
217+
split(unsafe_string(ccall(:LLVMGetHostCPUFeatures, Cstring, ())),
218+
","))
219+
return sort!(replace.(features, r"^\+" => ""))
220+
end
221+
222+
# Get the microarchitecture of a CPU from the list of its features.
223+
# TODO: support other architectures, like armv7l and aarch64.
224+
function march(cpu_features::Vector{String})
225+
# List of CPU features from https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html
226+
if all(in(cpu_features), ("mmx", "sse", "sse2")) # Generic x86_64
227+
if all(in(cpu_features), ("sse3", "ssse3", "sse4.1", "sse4.2", "popcnt", "avx", "aes", "pclmul")) # avx
228+
if all(in(cpu_features), ("movbe", "avx2", "fsgsbase", "rdrnd", "fma", "bmi", "bmi2", "f16c")) # avx2
229+
# Some names are different: ADCX -> ADX, PREFETCHW -> PRFCHW
230+
if all(in(cpu_features), ("pku", "rdseed", "adx", "prfchw", "clflushopt", "xsavec", "xsaves", "avx512f", "clwb", "avx512vl", "avx512bw", "avx512dq", "avx512cd")) # avx512
231+
return "avx512"
232+
end
233+
return "avx2"
234+
end
235+
return "avx"
236+
end
237+
return "x86_64"
238+
else
239+
@warn "Cannot determine the microarchitecture for the given set of features!"
240+
return nothing
241+
end
242+
end
243+
244+
# NOTE: the keyword arguments are *not* part of the public API, they're only
245+
# used for testing purposes and they may change in the future.
246+
"""
247+
extended_platform_key_abi()
248+
249+
Returns the `Platform` representing the current platform. It is an
250+
[`ExtendedPlatform`](@ref) if it possible to detect additional features, like
251+
the microarchitecture.
252+
"""
253+
function extended_platform_key_abi(; p::Platform = platform_key_abi(),
254+
cpu_features::Vector{String} = get_cpu_features())
255+
256+
if arch(p) == :x86_64
257+
return ExtendedPlatform(p; march=march(cpu_features))
258+
else
259+
return p
260+
end
261+
end

test/platforms.jl

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
using Test
22
using Pkg, Pkg.PlatformEngines, Pkg.BinaryPlatforms, Pkg.Artifacts
33
using BinaryBuilderBase
4-
using BinaryBuilderBase: abi_agnostic, get_concrete_platform, march
4+
using BinaryBuilderBase: abi_agnostic, get_concrete_platform, march, get_cpu_features
55

66
@testset "Supported Platforms" begin
77
all = supported_platforms()
@@ -205,6 +205,31 @@ end
205205
# Extending different platforms
206206
@test !platforms_match(ExtendedPlatform(Linux(:i686); cuda="10.1"), ExtendedPlatform(FreeBSD(:x86_64); cuda="11.1"))
207207
end
208+
209+
@testset "extended_platform_key_abi" begin
210+
if VERSION >= v"1.4"
211+
@test get_cpu_features() isa Vector{String}
212+
else
213+
@test_throws ErrorException get_cpu_features()
214+
end
215+
216+
@test @test_logs (:warn, r"^Cannot determine the microarchitecture") march(String[]) === nothing
217+
for (cpu_features, μarch) in (
218+
(["mmx", "sse", "sse2"], "x86_64"),
219+
# The following sets of CPU features are obtained on real machines
220+
(["64bit", "aes", "avx", "cmov", "cx16", "fma4", "lzcnt", "mmx", "pclmul", "popcnt", "prfchw", "sahf", "sse", "sse2", "sse3", "sse4.1", "sse4.2", "sse4a", "ssse3", "xop", "xsave"], "avx"),
221+
(["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"),
222+
(["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"),
223+
(["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"),
224+
(["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")
225+
)
226+
@test march(cpu_features) == μarch
227+
p = Linux(:x86_64)
228+
@test extended_platform_key_abi(; p=p, cpu_features=cpu_features) == ExtendedPlatform(p; march=μarch)
229+
end
230+
p = Linux(:i686)
231+
@test extended_platform_key_abi(; p=p, cpu_features=String[]) == p
232+
end
208233
end
209234

210235
@testset "AnyPlatform" begin

0 commit comments

Comments
 (0)