Skip to content

Commit 0f782b2

Browse files
authored
Merge pull request #37479 from giordano/mg/cpuid
2 parents 9b81a8a + f1bb7df commit 0f782b2

File tree

5 files changed

+123
-4
lines changed

5 files changed

+123
-4
lines changed

base/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/features_h.jl
12
/pcre_h.jl
23
/errno_h.jl
34
/build_h.jl

base/Makefile

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ else
1212
CPP_STDOUT := $(CPP) -E
1313
endif
1414

15-
all: $(addprefix $(BUILDDIR)/,pcre_h.jl errno_h.jl build_h.jl.phony file_constants.jl uv_constants.jl version_git.jl.phony)
15+
all: $(addprefix $(BUILDDIR)/,pcre_h.jl errno_h.jl build_h.jl.phony features_h.jl file_constants.jl uv_constants.jl version_git.jl.phony)
1616

1717
PCRE_CONST := 0x[0-9a-fA-F]+|[0-9]+|\([\-0-9]+\)
1818
ifeq ($(USE_SYSTEM_PCRE), 1)
@@ -21,6 +21,18 @@ else
2121
PCRE_INCL_PATH := $(build_includedir)/pcre2.h
2222
endif
2323

24+
define parse_features
25+
@echo "# $(2) features" >> $@
26+
@$(call PRINT_PERL, cat ../src/features_$(1).h | perl -lne 'print "const JL_$(2)_$$1 = UInt32($$2)" if /^\s*JL_FEATURE_DEF(?:_NAME)?\(\s*(\w+)\s*,\s*([^,]+)\s*,.*\)\s*(?:\/\/.*)?$$/' >> $@)
27+
@echo >> $@
28+
endef
29+
30+
$(BUILDDIR)/features_h.jl: ../src/features_x86.h ../src/features_aarch32.h ../src/features_aarch64.h
31+
@-rm -f $@
32+
@$(call parse_features,x86,X86)
33+
@$(call parse_features,aarch32,AArch32)
34+
@$(call parse_features,aarch64,AArch64)
35+
2436
$(BUILDDIR)/pcre_h.jl: $(PCRE_INCL_PATH)
2537
@$(call PRINT_PERL, $(CPP) -D PCRE2_CODE_UNIT_WIDTH=8 -dM $< | perl -nle '/^\s*#define\s+PCRE2_(\w*)\s*\(?($(PCRE_CONST))\)?u?\s*$$/ and print index($$1, "ERROR_") == 0 ? "const $$1 = Cint($$2)" : "const $$1 = UInt32($$2)"' | LC_ALL=C sort > $@)
2638

@@ -236,6 +248,7 @@ clean:
236248
-rm -f $(BUILDDIR)/errno_h.jl
237249
-rm -f $(BUILDDIR)/build_h.jl
238250
-rm -f $(BUILDDIR)/build_h.jl.phony
251+
-rm -f $(BUILDDIR)/features_h.jl
239252
-rm -f $(BUILDDIR)/uv_constants.jl
240253
-rm -f $(BUILDDIR)/file_constants.jl
241254
-rm -f $(BUILDDIR)/version_git.jl

base/binaryplatforms.jl

Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,74 @@ export AbstractPlatform, Platform, HostPlatform, platform_dlext, tags, arch, os,
77
select_platform, platforms_match, platform_name
88
import .Libc.Libdl
99

10+
### Submodule with information about CPU features
11+
module CPUID
12+
13+
export cpu_isa
14+
15+
"""
16+
ISA(features::Set{UInt32})
17+
18+
A structure which represents the Instruction Set Architecture (ISA) of a
19+
computer. It holds the `Set` of features of the CPU.
20+
21+
The numerical values of the features are automatically generated from the C
22+
source code of Julia and stored in the `features_h.jl` Julia file.
23+
"""
24+
struct ISA
25+
features::Set{UInt32}
26+
end
27+
28+
Base.:<=(a::ISA, b::ISA) = a.features <= b.features
29+
Base.:<(a::ISA, b::ISA) = a.features < b.features
30+
Base.isless(a::ISA, b::ISA) = a < b
31+
32+
include("features_h.jl")
33+
34+
# Keep in sync with `arch_march_isa_mapping`.
35+
const ISAs_by_family = Dict(
36+
"x86_64" => (
37+
# Source: https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html.
38+
# Implicit in all sets, because always required: mmx, sse, sse2
39+
"x86_64" => ISA(Set{UInt32}()),
40+
"core2" => ISA(Set((JL_X86_sse3, JL_X86_ssse3))),
41+
"nehalem" => ISA(Set((JL_X86_sse3, JL_X86_ssse3, JL_X86_sse41, JL_X86_sse42, JL_X86_popcnt))),
42+
"sandybridge" => ISA(Set((JL_X86_sse3, JL_X86_ssse3, JL_X86_sse41, JL_X86_sse42, JL_X86_popcnt, JL_X86_avx, JL_X86_aes, JL_X86_pclmul))),
43+
"haswell" => ISA(Set((JL_X86_movbe, JL_X86_sse3, JL_X86_ssse3, JL_X86_sse41, JL_X86_sse42, JL_X86_popcnt, JL_X86_avx, JL_X86_avx2, JL_X86_aes, JL_X86_pclmul, JL_X86_fsgsbase, JL_X86_rdrnd, JL_X86_fma, JL_X86_bmi, JL_X86_bmi2, JL_X86_f16c))),
44+
"skylake" => ISA(Set((JL_X86_movbe, JL_X86_sse3, JL_X86_ssse3, JL_X86_sse41, JL_X86_sse42, JL_X86_popcnt, JL_X86_avx, JL_X86_avx2, JL_X86_aes, JL_X86_pclmul, JL_X86_fsgsbase, JL_X86_rdrnd, JL_X86_fma, JL_X86_bmi, JL_X86_bmi2, JL_X86_f16c, JL_X86_rdseed, JL_X86_adx, JL_X86_prfchw, JL_X86_clflushopt, JL_X86_xsavec, JL_X86_xsaves))),
45+
"skylake_avx512" => ISA(Set((JL_X86_movbe, JL_X86_sse3, JL_X86_ssse3, JL_X86_sse41, JL_X86_sse42, JL_X86_popcnt, JL_X86_pku, JL_X86_avx, JL_X86_avx2, JL_X86_aes, JL_X86_pclmul, JL_X86_fsgsbase, JL_X86_rdrnd, JL_X86_fma, JL_X86_bmi, JL_X86_bmi2, JL_X86_f16c, JL_X86_rdseed, JL_X86_adx, JL_X86_prfchw, JL_X86_clflushopt, JL_X86_xsavec, JL_X86_xsaves, JL_X86_avx512f, JL_X86_clwb, JL_X86_avx512vl, JL_X86_avx512bw, JL_X86_avx512dq, JL_X86_avx512cd))),
46+
),
47+
"arm" => (
48+
"armv7l" => ISA(Set{UInt32}()),
49+
"armv7l_neon" => ISA(Set((JL_AArch32_neon,))),
50+
"armv7l_neon_vfp4" => ISA(Set((JL_AArch32_neon, JL_AArch32_vfp4))),
51+
),
52+
"aarch64" => (
53+
# Implicit in all sets, because always required: fp, asimd
54+
"armv8.0_a" => ISA(Set{UInt32}()),
55+
"armv8.1_a" => ISA(Set((JL_AArch64_lse, JL_AArch64_crc, JL_AArch64_rdm))),
56+
"armv8.2_a_crypto" => ISA(Set((JL_AArch64_lse, JL_AArch64_crc, JL_AArch64_rdm, JL_AArch64_aes, JL_AArch64_sha2))),
57+
"armv8.4_a_crypto_sve" => ISA(Set((JL_AArch64_lse, JL_AArch64_crc, JL_AArch64_rdm, JL_AArch64_fp16fml, JL_AArch64_dotprod, JL_AArch64_aes, JL_AArch64_sha2, JL_AArch64_dotprod, JL_AArch64_sve))),
58+
),
59+
)
60+
61+
test_cpu_feature(feature::UInt32) = ccall(:jl_test_cpu_feature, Bool, (UInt32,), feature)
62+
cpu_family() = String(Sys.ARCH)
63+
64+
"""
65+
cpu_isa()
66+
67+
Return the [`ISA`](@ref) (instruction set architecture) of the current CPU.
68+
"""
69+
function cpu_isa()
70+
all_features = last(last(get(ISAs_by_family, cpu_family(), "" => [ISA(Set{UInt32}())]))).features
71+
return ISA(Set{UInt32}(feat for feat in all_features if test_cpu_feature(feat)))
72+
end
73+
74+
end # module CPUID
75+
76+
using .CPUID
77+
1078
# This exists to ease compatibility with old-style Platform objects
1179
abstract type AbstractPlatform; end
1280

@@ -567,6 +635,31 @@ const arch_mapping = Dict(
567635
"armv6l" => "armv6l",
568636
"powerpc64le" => "p(ower)?pc64le",
569637
)
638+
# Keep this in sync with `CPUID.ISAs_by_family`
639+
const arch_march_isa_mapping = let
640+
function get_set(arch, name)
641+
all = CPUID.ISAs_by_family[arch]
642+
return all[findfirst(x -> x.first == name, all)].second
643+
end
644+
Dict(
645+
"x86_64" => Dict{String,CPUID.ISA}(
646+
"x86_64" => get_set("x86_64", "x86_64"),
647+
"avx" => get_set("x86_64", "sandybridge"),
648+
"avx2" => get_set("x86_64", "haswell"),
649+
"avx512" => get_set("x86_64", "skylake_avx512"),
650+
),
651+
"armv7l" => Dict{String,CPUID.ISA}(
652+
"armv7l" => get_set("arm", "armv7l"),
653+
"neon" => get_set("arm", "armv7l_neon"),
654+
"vfp4" => get_set("arm", "armv7l_neon_vfp4"),
655+
),
656+
"aarch64" => Dict{String,CPUID.ISA}(
657+
"armv8" => get_set("aarch64", "armv8.0_a"),
658+
"thunderx2" => get_set("aarch64", "armv8.1_a"),
659+
"carmel" => get_set("aarch64", "armv8.2_a_crypto"),
660+
),
661+
)
662+
end
570663
const os_mapping = Dict(
571664
"macos" => "-apple-darwin[\\d\\.]*",
572665
"freebsd" => "-(.*-)?freebsd[\\d\\.]*",

src/processor.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ typedef enum {
123123
} jl_cpu_feature_t;
124124
#undef JL_FEATURE_DEF_NAME
125125

126-
int jl_test_cpu_feature(jl_cpu_feature_t feature);
126+
JL_DLLEXPORT int jl_test_cpu_feature(jl_cpu_feature_t feature);
127127

128128
static const uint32_t jl_sysimg_tag_mask = 0x80000000u;
129129
static const uint32_t jl_sysimg_val_mask = ~((uint32_t)0x80000000u);

test/binaryplatforms.jl

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,16 @@
1-
using Test, Base.BinaryPlatforms
1+
using Test, Base.BinaryPlatforms, Base.BinaryPlatforms.CPUID
2+
3+
@testset "CPUID" begin
4+
@test CPUID.cpu_isa() isa CPUID.ISA
5+
6+
get_x86_64(n) = (CPUID.ISAs_by_family["x86_64"][n].second)
7+
@test get_x86_64(2) < get_x86_64(4)
8+
@test get_x86_64(5) <= get_x86_64(5)
9+
@test get_x86_64(3) >= get_x86_64(3)
10+
@test get_x86_64(7) >= get_x86_64(1)
11+
@test sort([get_x86_64(6), get_x86_64(4), get_x86_64(2), get_x86_64(4)]) ==
12+
[get_x86_64(2), get_x86_64(4), get_x86_64(4), get_x86_64(6)]
13+
end
214

315
# Helper constructor to create a Platform with `validate_strict` set to `true`.
416
P(args...; kwargs...) = Platform(args...; validate_strict=true, kwargs...)
@@ -363,4 +375,4 @@ end
363375
@test !platforms_match(ac, bc)
364376
@test platforms_match(ac, ac)
365377
@test platforms_match(bc, bc)
366-
end
378+
end

0 commit comments

Comments
 (0)