Skip to content

Commit 128fd2e

Browse files
feat: update building C code for x86 architecture.
Notes: 1. chunk_info has been moved to `common/mod.rs` since it will be needed for all architectures
1 parent 259367b commit 128fd2e

File tree

5 files changed

+141
-10
lines changed

5 files changed

+141
-10
lines changed

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

Lines changed: 1 addition & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ use std::fs::{self, File};
1010
use rayon::prelude::*;
1111

1212
use crate::arm::config::POLY128_OSTREAM_DEF;
13-
use crate::common::SupportedArchitectureTest;
13+
use crate::common::{SupportedArchitectureTest, chunk_info};
1414
use crate::common::cli::ProcessedCli;
1515
use crate::common::compare::compare_outputs;
1616
use crate::common::gen_c::{write_main_cpp, write_mod_cpp};
@@ -28,13 +28,6 @@ pub struct ArmArchitectureTest {
2828
cli_options: ProcessedCli,
2929
}
3030

31-
fn chunk_info(intrinsic_count: usize) -> (usize, usize) {
32-
let available_parallelism = std::thread::available_parallelism().unwrap().get();
33-
let chunk_size = intrinsic_count.div_ceil(Ord::min(available_parallelism, intrinsic_count));
34-
35-
(chunk_size, intrinsic_count.div_ceil(chunk_size))
36-
}
37-
3831
impl SupportedArchitectureTest for ArmArchitectureTest {
3932
fn create(cli_options: ProcessedCli) -> Box<Self> {
4033
let a32 = cli_options.target.contains("v7");

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,3 +22,10 @@ pub trait SupportedArchitectureTest {
2222
fn build_rust_file(&self) -> bool;
2323
fn compare_outputs(&self) -> bool;
2424
}
25+
26+
pub fn chunk_info(intrinsic_count: usize) -> (usize, usize) {
27+
let available_parallelism = std::thread::available_parallelism().unwrap().get();
28+
let chunk_size = intrinsic_count.div_ceil(Ord::min(available_parallelism, intrinsic_count));
29+
30+
(chunk_size, intrinsic_count.div_ceil(chunk_size))
31+
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use crate::common::cli::ProcessedCli;
2+
use crate::common::compile_c::{CompilationCommandBuilder, CppCompilation};
3+
4+
pub fn build_cpp_compilation(config: &ProcessedCli) -> Option<CppCompilation> {
5+
let cpp_compiler = config.cpp_compiler.as_ref()?;
6+
7+
// -ffp-contract=off emulates Rust's approach of not fusing separate mul-add operations
8+
let mut command = CompilationCommandBuilder::new()
9+
.add_arch_flags(vec![
10+
"avx",
11+
"avx2",
12+
"avx512f",
13+
"avx512cd",
14+
"avx512dq",
15+
"avx512vl",
16+
"avx512bw",
17+
"avx512bf16",
18+
"avx512bitalg",
19+
"lzcnt",
20+
"popcnt",
21+
"adx",
22+
"aes",
23+
])
24+
.set_compiler(cpp_compiler)
25+
.set_target(&config.target)
26+
.set_opt_level("2")
27+
.set_cxx_toolchain_dir(config.cxx_toolchain_dir.as_deref())
28+
.set_project_root("c_programs")
29+
.add_extra_flags(vec!["-ffp-contract=off", "-Wno-narrowing"]);
30+
31+
if !cpp_compiler.contains("clang") {
32+
command = command.add_extra_flag("-flax-vector-conversions");
33+
}
34+
35+
let mut cpp_compiler = command.into_cpp_compilation();
36+
37+
Some(cpp_compiler)
38+
}
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
pub fn build_notices(line_prefix: &str) -> String {
2+
format!(
3+
"\
4+
{line_prefix}This is a transient test file, not intended for distribution. Some aspects of the
5+
{line_prefix}test are derived from an XML specification, published under the same license as the
6+
{line_prefix}`intrinsic-test` crate.\n
7+
"
8+
)
9+
}
10+
11+
// Format f16 values (and vectors containing them) in a way that is consistent with C.
12+
pub const F16_FORMATTING_DEF: &str = r#"
13+
#[repr(transparent)]
14+
struct Hex<T>(T);
15+
"#;
16+
17+
pub const X86_CONFIGURATIONS: &str = r#"
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))]
24+
#![feature(fmt_helpers_for_derive)]
25+
"#;

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

Lines changed: 70 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,21 @@
1+
mod compile;
2+
mod config;
13
mod constraint;
24
mod intrinsic;
35
mod types;
46
mod xml_parser;
57

8+
use std::fs::{self, File};
9+
use rayon::prelude::*;
10+
611
use crate::common::cli::ProcessedCli;
712
use crate::common::intrinsic::{Intrinsic, IntrinsicDefinition};
813
use crate::common::intrinsic_helpers::TypeKind;
9-
use crate::common::SupportedArchitectureTest;
14+
use crate::common::{SupportedArchitectureTest, chunk_info};
15+
use crate::common::gen_c::{write_main_cpp, write_mod_cpp};
1016
use intrinsic::X86IntrinsicType;
1117
use xml_parser::get_xml_intrinsics;
18+
use config::build_notices;
1219

1320
pub struct X86ArchitectureTest {
1421
intrinsics: Vec<Intrinsic<X86IntrinsicType>>,
@@ -42,7 +49,68 @@ impl SupportedArchitectureTest for X86ArchitectureTest {
4249
}
4350

4451
fn build_c_file(&self) -> bool {
45-
todo!("build_c_file in X86ArchitectureTest is not implemented")
52+
let c_target = "aarch64";
53+
let platform_headers = &["arm_neon.h", "arm_acle.h", "arm_fp16.h"];
54+
55+
let (chunk_size, chunk_count) = chunk_info(self.intrinsics.len());
56+
57+
let cpp_compiler_wrapped = compile::build_cpp_compilation(&self.cli_options);
58+
59+
let notice = &build_notices("// ");
60+
fs::create_dir_all("c_programs").unwrap();
61+
self.intrinsics
62+
.par_chunks(chunk_size)
63+
.enumerate()
64+
.map(|(i, chunk)| {
65+
let c_filename = format!("c_programs/mod_{i}.cpp");
66+
let mut file = File::create(&c_filename).unwrap();
67+
write_mod_cpp(&mut file, notice, c_target, platform_headers, chunk).unwrap();
68+
69+
// compile this cpp file into a .o file.
70+
//
71+
// This is done because `cpp_compiler_wrapped` is None when
72+
// the --generate-only flag is passed
73+
if let Some(cpp_compiler) = cpp_compiler_wrapped.as_ref() {
74+
let output = cpp_compiler
75+
.compile_object_file(&format!("mod_{i}.cpp"), &format!("mod_{i}.o"))?;
76+
assert!(output.status.success(), "{output:?}");
77+
}
78+
79+
Ok(())
80+
})
81+
.collect::<Result<(), std::io::Error>>()
82+
.unwrap();
83+
84+
let mut file = File::create("c_programs/main.cpp").unwrap();
85+
write_main_cpp(
86+
&mut file,
87+
c_target,
88+
"\n",
89+
self.intrinsics.iter().map(|i| i.name.as_str()),
90+
)
91+
.unwrap();
92+
93+
// This is done because `cpp_compiler_wrapped` is None when
94+
// the --generate-only flag is passed
95+
if let Some(cpp_compiler) = cpp_compiler_wrapped.as_ref() {
96+
// compile this cpp file into a .o file
97+
info!("compiling main.cpp");
98+
let output = cpp_compiler
99+
.compile_object_file("main.cpp", "intrinsic-test-programs.o")
100+
.unwrap();
101+
assert!(output.status.success(), "{output:?}");
102+
103+
let object_files = (0..chunk_count)
104+
.map(|i| format!("mod_{i}.o"))
105+
.chain(["intrinsic-test-programs.o".to_owned()]);
106+
107+
let output = cpp_compiler
108+
.link_executable(object_files, "intrinsic-test-programs")
109+
.unwrap();
110+
assert!(output.status.success(), "{output:?}");
111+
}
112+
113+
true
46114
}
47115

48116
fn build_rust_file(&self) -> bool {

0 commit comments

Comments
 (0)