1#![deny(missing_docs)]
5
6use cranelift_codegen::isa;
7use cranelift_codegen::settings::Configurable;
8use target_lexicon::Triple;
9
10#[cfg(all(target_arch = "riscv64", target_os = "linux"))]
11mod riscv;
12
13pub fn builder() -> Result<isa::Builder, &'static str> {
17 builder_with_options(true)
18}
19
20pub fn builder_with_options(infer_native_flags: bool) -> Result<isa::Builder, &'static str> {
28 let mut isa_builder = isa::lookup(Triple::host()).map_err(|err| match err {
29 isa::LookupError::SupportDisabled => "support for architecture disabled at compile time",
30 isa::LookupError::Unsupported => "unsupported architecture",
31 })?;
32 if infer_native_flags {
33 self::infer_native_flags(&mut isa_builder)?;
34 }
35 Ok(isa_builder)
36}
37
38pub fn infer_native_flags(isa_builder: &mut dyn Configurable) -> Result<(), &'static str> {
46 #[cfg(target_arch = "x86_64")]
47 {
48 if !std::is_x86_feature_detected!("sse2") {
49 return Err("x86 support requires SSE2");
50 }
51
52 if std::is_x86_feature_detected!("cmpxchg16b") {
53 isa_builder.enable("has_cmpxchg16b").unwrap();
54 }
55 if std::is_x86_feature_detected!("sse3") {
56 isa_builder.enable("has_sse3").unwrap();
57 }
58 if std::is_x86_feature_detected!("ssse3") {
59 isa_builder.enable("has_ssse3").unwrap();
60 }
61 if std::is_x86_feature_detected!("sse4.1") {
62 isa_builder.enable("has_sse41").unwrap();
63 }
64 if std::is_x86_feature_detected!("sse4.2") {
65 isa_builder.enable("has_sse42").unwrap();
66 }
67 if std::is_x86_feature_detected!("popcnt") {
68 isa_builder.enable("has_popcnt").unwrap();
69 }
70 if std::is_x86_feature_detected!("avx") {
71 isa_builder.enable("has_avx").unwrap();
72 }
73 if std::is_x86_feature_detected!("avx2") {
74 isa_builder.enable("has_avx2").unwrap();
75 }
76 if std::is_x86_feature_detected!("fma") {
77 isa_builder.enable("has_fma").unwrap();
78 }
79 if std::is_x86_feature_detected!("bmi1") {
80 isa_builder.enable("has_bmi1").unwrap();
81 }
82 if std::is_x86_feature_detected!("bmi2") {
83 isa_builder.enable("has_bmi2").unwrap();
84 }
85 if std::is_x86_feature_detected!("avx512bitalg") {
86 isa_builder.enable("has_avx512bitalg").unwrap();
87 }
88 if std::is_x86_feature_detected!("avx512dq") {
89 isa_builder.enable("has_avx512dq").unwrap();
90 }
91 if std::is_x86_feature_detected!("avx512f") {
92 isa_builder.enable("has_avx512f").unwrap();
93 }
94 if std::is_x86_feature_detected!("avx512vl") {
95 isa_builder.enable("has_avx512vl").unwrap();
96 }
97 if std::is_x86_feature_detected!("avx512vbmi") {
98 isa_builder.enable("has_avx512vbmi").unwrap();
99 }
100 if std::is_x86_feature_detected!("lzcnt") {
101 isa_builder.enable("has_lzcnt").unwrap();
102 }
103 }
104
105 #[cfg(target_arch = "aarch64")]
106 {
107 if std::arch::is_aarch64_feature_detected!("lse") {
108 isa_builder.enable("has_lse").unwrap();
109 }
110
111 if std::arch::is_aarch64_feature_detected!("paca") {
112 isa_builder.enable("has_pauth").unwrap();
113 }
114
115 if std::arch::is_aarch64_feature_detected!("fp16") {
116 isa_builder.enable("has_fp16").unwrap();
117 }
118
119 if cfg!(target_os = "macos") {
120 isa_builder.enable("sign_return_address").unwrap();
122 isa_builder.enable("sign_return_address_with_bkey").unwrap();
124 }
125 }
126
127 #[cfg(all(target_arch = "s390x", target_os = "linux"))]
130 {
131 let v = unsafe { libc::getauxval(libc::AT_HWCAP) };
132 const HWCAP_S390X_VXRS_EXT2: libc::c_ulong = 32768;
133 if (v & HWCAP_S390X_VXRS_EXT2) != 0 {
134 isa_builder.enable("has_vxrs_ext2").unwrap();
135 isa_builder.enable("has_mie2").unwrap();
138 }
139 }
140
141 #[cfg(all(target_arch = "riscv64", target_os = "linux"))]
144 {
145 riscv::hwcap_detect(isa_builder)?;
149
150 let _ = riscv::cpuinfo_detect(isa_builder);
153 }
154
155 let _ = isa_builder;
158 Ok(())
159}
160
161pub const VERSION: &str = env!("CARGO_PKG_VERSION");
163
164#[cfg(test)]
165mod tests {
166 use super::builder;
167 use cranelift_codegen::isa::CallConv;
168 use cranelift_codegen::settings;
169
170 #[test]
171 fn test() {
172 if let Ok(isa_builder) = builder() {
173 let flag_builder = settings::builder();
174 let isa = isa_builder
175 .finish(settings::Flags::new(flag_builder))
176 .unwrap();
177
178 if cfg!(all(target_os = "macos", target_arch = "aarch64")) {
179 assert_eq!(isa.default_call_conv(), CallConv::AppleAarch64);
180 } else if cfg!(unix) {
181 assert_eq!(isa.default_call_conv(), CallConv::SystemV);
182 } else if cfg!(windows) {
183 assert_eq!(isa.default_call_conv(), CallConv::WindowsFastcall);
184 }
185
186 if cfg!(target_pointer_width = "64") {
187 assert_eq!(isa.pointer_bits(), 64);
188 } else if cfg!(target_pointer_width = "32") {
189 assert_eq!(isa.pointer_bits(), 32);
190 } else if cfg!(target_pointer_width = "16") {
191 assert_eq!(isa.pointer_bits(), 16);
192 }
193 }
194 }
195}