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 std::arch::is_aarch64_feature_detected!("dotprod") {
120 isa_builder.enable("has_dotprod").unwrap();
121 }
122
123 if cfg!(target_os = "macos") {
124 isa_builder.enable("sign_return_address").unwrap();
126 isa_builder.enable("sign_return_address_with_bkey").unwrap();
128 }
129 }
130
131 #[cfg(target_arch = "s390x")]
134 {
135 let mut facility_list: [u64; 4] = [0; 4];
136 unsafe {
137 core::arch::asm!(
138 "stfle 0({})",
139 in(reg_addr) facility_list.as_mut_ptr() ,
140 inout("r0") facility_list.len() as u64 - 1 => _,
141 options(nostack)
142 );
143 }
144 let get_facility_bit = |n: usize| {
145 facility_list[n / 64] & (1 << (63 - (n % 64))) != 0
147 };
148
149 if get_facility_bit(61) {
150 isa_builder.enable("has_mie3").unwrap();
151 }
152 if get_facility_bit(84) {
153 isa_builder.enable("has_mie4").unwrap();
154 }
155 if get_facility_bit(148) {
156 isa_builder.enable("has_vxrs_ext2").unwrap();
157 }
158 if get_facility_bit(198) {
159 isa_builder.enable("has_vxrs_ext3").unwrap();
160 }
161 }
162
163 #[cfg(all(target_arch = "riscv64", target_os = "linux"))]
166 {
167 riscv::hwcap_detect(isa_builder)?;
171
172 let _ = riscv::cpuinfo_detect(isa_builder);
175 }
176
177 let _ = isa_builder;
180 Ok(())
181}
182
183pub const VERSION: &str = env!("CARGO_PKG_VERSION");
185
186#[cfg(test)]
187mod tests {
188 use super::builder;
189 use cranelift_codegen::isa::CallConv;
190 use cranelift_codegen::settings;
191
192 #[test]
193 fn test() {
194 if let Ok(isa_builder) = builder() {
195 let flag_builder = settings::builder();
196 let isa = isa_builder
197 .finish(settings::Flags::new(flag_builder))
198 .unwrap();
199
200 if cfg!(all(target_os = "macos", target_arch = "aarch64")) {
201 assert_eq!(isa.default_call_conv(), CallConv::AppleAarch64);
202 } else if cfg!(unix) {
203 assert_eq!(isa.default_call_conv(), CallConv::SystemV);
204 } else if cfg!(windows) {
205 assert_eq!(isa.default_call_conv(), CallConv::WindowsFastcall);
206 }
207
208 if cfg!(target_pointer_width = "64") {
209 assert_eq!(isa.pointer_bits(), 64);
210 } else if cfg!(target_pointer_width = "32") {
211 assert_eq!(isa.pointer_bits(), 32);
212 } else if cfg!(target_pointer_width = "16") {
213 assert_eq!(isa.pointer_bits(), 16);
214 }
215 }
216 }
217}