Skip to content

Commit 661bf30

Browse files
feat: added x86 C compilation and CI pipeline for testing x86 intrinsics
1 parent 20b5d3b commit 661bf30

File tree

6 files changed

+158585
-31
lines changed

6 files changed

+158585
-31
lines changed

Cargo.lock

Lines changed: 51 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ci/run.sh

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,12 @@ case ${TARGET} in
161161
TEST_CXX_COMPILER="clang++-19"
162162
TEST_RUNNER="${CARGO_TARGET_ARMV7_UNKNOWN_LINUX_GNUEABIHF_RUNNER}"
163163
;;
164+
165+
x86_64-unknown-linux-gnu*)
166+
TEST_CPPFLAGS="-fuse-ld=lld -I/usr/include/x86_64-linux-gnu/"
167+
TEST_CXX_COMPILER="clang++-19"
168+
TEST_RUNNER="${CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_RUNNER}"
169+
;;
164170
*)
165171
;;
166172

@@ -189,6 +195,14 @@ case "${TARGET}" in
189195
--linker "${CARGO_TARGET_AARCH64_BE_UNKNOWN_LINUX_GNU_LINKER}" \
190196
--cxx-toolchain-dir "${AARCH64_BE_TOOLCHAIN}"
191197
;;
198+
x86_64-unknown-linux-gnu*)
199+
CPPFLAGS="${TEST_CPPFLAGS}" RUSTFLAGS="${HOST_RUSTFLAGS}" RUST_LOG=warn \
200+
cargo run "${INTRINSIC_TEST}" "${PROFILE}" \
201+
--bin intrinsic-test -- intrinsics_data/x86-intel.xml \
202+
--runner "${TEST_RUNNER}" \
203+
--cppcompiler "${TEST_CXX_COMPILER}" \
204+
--target "${TARGET}"
205+
;;
192206
*)
193207
;;
194208
esac
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
use crate::common::compile_c::CompilationCommandBuilder;
2+
use crate::common::gen_c::compile_c_programs;
3+
4+
pub fn compile_c_x86(
5+
intrinsics_name_list: &[String],
6+
compiler: &str,
7+
target: &str,
8+
cxx_toolchain_dir: Option<&str>,
9+
) -> bool {
10+
// -ffp-contract=off emulates Rust's approach of not fusing separate mul-add operations
11+
let mut command = CompilationCommandBuilder::new()
12+
.add_arch_flags(vec![
13+
"avx",
14+
"avx2",
15+
"avx512f",
16+
"avx512cd",
17+
"avx512dq",
18+
"avx512vl",
19+
"avx512bw",
20+
"avx512bf16",
21+
"avx512bitalg",
22+
"lzcnt",
23+
"popcnt",
24+
"adx",
25+
"aes",
26+
])
27+
.set_compiler(compiler)
28+
.set_target(target)
29+
.set_opt_level("2")
30+
.set_cxx_toolchain_dir(cxx_toolchain_dir)
31+
.set_project_root("c_programs")
32+
.add_extra_flags(vec!["-ffp-contract=off", "-Wno-narrowing"]);
33+
34+
// if !target.contains("64") {
35+
// command = command.add_arch_flags(vec!["faminmax", "lut", "sha3"]);
36+
// }
37+
38+
/*
39+
* clang++ cannot link an aarch64_be object file, so we invoke
40+
* aarch64_be-unknown-linux-gnu's C++ linker. This ensures that we
41+
* are testing the intrinsics against LLVM.
42+
*
43+
* Note: setting `--sysroot=<...>` which is the obvious thing to do
44+
* does not work as it gets caught up with `#include_next <stdlib.h>`
45+
* not existing...
46+
*/
47+
// if target.contains("aarch64_be") {
48+
// command = command
49+
// .set_linker(
50+
// cxx_toolchain_dir.unwrap_or("").to_string() + "/bin/aarch64_be-none-linux-gnu-g++",
51+
// )
52+
// .set_include_paths(vec![
53+
// "/include",
54+
// "/aarch64_be-none-linux-gnu/include",
55+
// "/aarch64_be-none-linux-gnu/include/c++/14.2.1",
56+
// "/aarch64_be-none-linux-gnu/include/c++/14.2.1/aarch64_be-none-linux-gnu",
57+
// "/aarch64_be-none-linux-gnu/include/c++/14.2.1/backward",
58+
// "/aarch64_be-none-linux-gnu/libc/usr/include",
59+
// ]);
60+
// }
61+
62+
if !compiler.contains("clang") {
63+
command = command.add_extra_flag("-flax-vector-conversions");
64+
}
65+
66+
let compiler_commands = intrinsics_name_list
67+
.iter()
68+
.map(|intrinsic_name| {
69+
command
70+
.clone()
71+
.set_input_name(intrinsic_name)
72+
.set_output_name(intrinsic_name)
73+
.make_string()
74+
})
75+
.collect::<Vec<_>>();
76+
77+
compile_c_programs(&compiler_commands)
78+
}

crates/intrinsic-test/src/x86/config.rs

Lines changed: 6 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -15,27 +15,11 @@ struct Hex<T>(T);
1515
"#;
1616

1717
pub const X86_CONFIGURATIONS: &str = r#"
18-
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_avx512))]
19-
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_avx2))]
20-
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_avx))]
21-
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_sse42))]
22-
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_sse41))]
23-
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_ssse3))]
24-
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_sse3))]
25-
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_sse2))]
26-
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_sse))]
27-
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_avx512))]
28-
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_avx2))]
29-
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_avx))]
30-
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_fma))]
31-
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_aes))]
32-
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_sha))]
33-
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_bmi1))]
34-
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_bmi2))]
35-
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_lzcnt))]
36-
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_popcnt))]
37-
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_rdrand))]
38-
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_rdseed))]
39-
#![cfg_attr(any(target_arch = "x86", target_arch = "x86_64"), feature(stdarch_x86_mmx))]
18+
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_avx512_bf16))]
19+
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_avx512_f16))]
20+
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_rtm))]
21+
#![cfg_attr(target_arch = "x86", feature(stdarch_x86_rtm))]
22+
#![cfg_attr(target_arch = "x86_64", feature(x86_amx_intrinsics))]
23+
#![cfg_attr(target_arch = "x86_64", feature(stdarch_x86_avx512_f16))]
4024
#![feature(fmt_helpers_for_derive)]
4125
"#;

crates/intrinsic-test/src/x86/mod.rs

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
mod compile;
12
mod config;
23
mod constraint;
34
mod intrinsic;
@@ -11,6 +12,7 @@ use crate::common::gen_rust::compile_rust_programs;
1112
use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition};
1213
use crate::common::intrinsic_helpers::TypeKind;
1314
use crate::common::write_file::{write_c_testfiles, write_rust_testfiles};
15+
use crate::x86::compile::compile_c_x86;
1416
use crate::x86::config::{F16_FORMATTING_DEF, X86_CONFIGURATIONS};
1517
use config::build_notices;
1618
use intrinsic::X86IntrinsicType;
@@ -23,11 +25,10 @@ pub struct X86ArchitectureTest {
2325

2426
impl SupportedArchitectureTest for X86ArchitectureTest {
2527
fn create(cli_options: ProcessedCli) -> Box<Self> {
26-
let mut intrinsics =
28+
let intrinsics =
2729
get_xml_intrinsics(&cli_options.filename).expect("Error parsing input file");
2830

29-
intrinsics.sort_by(|a, b| a.name.cmp(&b.name));
30-
let intrinsics = intrinsics
31+
let mut intrinsics = intrinsics
3132
.into_iter()
3233
// Not sure how we would compare intrinsic that returns void.
3334
.filter(|i| i.results.kind() != TypeKind::Void)
@@ -41,20 +42,20 @@ impl SupportedArchitectureTest for X86ArchitectureTest {
4142
.filter(|i| !cli_options.skip.contains(&i.name))
4243
.collect::<Vec<_>>();
4344

45+
intrinsics.sort_by(|a, b| a.name.cmp(&b.name));
4446
Box::new(Self {
4547
intrinsics: intrinsics,
4648
cli_options: cli_options,
4749
})
4850
}
4951

5052
fn build_c_file(&self) -> bool {
51-
// let compiler = self.cli_options.cpp_compiler.as_deref();
53+
let compiler = self.cli_options.cpp_compiler.as_deref();
5254
let target = &self.cli_options.target;
53-
// let cxx_toolchain_dir = self.cli_options.cxx_toolchain_dir.as_deref();
55+
let cxx_toolchain_dir = self.cli_options.cxx_toolchain_dir.as_deref();
5456
let c_target = "x86_64";
5557

56-
/* let intrinsics_name_list = */
57-
write_c_testfiles(
58+
let intrinsics_name_list = write_c_testfiles(
5859
&self
5960
.intrinsics
6061
.iter()
@@ -67,7 +68,12 @@ impl SupportedArchitectureTest for X86ArchitectureTest {
6768
&[],
6869
);
6970

70-
true
71+
match compiler {
72+
None => true,
73+
Some(compiler) => {
74+
compile_c_x86(&intrinsics_name_list, compiler, target, cxx_toolchain_dir)
75+
}
76+
}
7177
}
7278

7379
fn build_rust_file(&self) -> bool {

0 commit comments

Comments
 (0)