wasmer_compiler_cranelift/
config.rs1use crate::compiler::CraneliftCompiler;
2use cranelift_codegen::{
3 CodegenResult,
4 isa::{TargetIsa, lookup},
5 settings::{self, Configurable},
6};
7use std::num::NonZero;
8use std::sync::Arc;
9use wasmer_compiler::{Compiler, CompilerConfig, Engine, EngineBuilder, ModuleMiddleware};
10use wasmer_types::target::{Architecture, CpuFeature, Target};
11
12#[non_exhaustive]
16#[derive(Clone, Debug)]
17pub enum CraneliftOptLevel {
18 None,
21 Speed,
23 SpeedAndSize,
26}
27
28#[derive(Debug, Clone)]
34pub struct Cranelift {
35 enable_nan_canonicalization: bool,
36 enable_verifier: bool,
37 pub(crate) enable_perfmap: bool,
38 enable_pic: bool,
39 opt_level: CraneliftOptLevel,
40 pub num_threads: NonZero<usize>,
42 pub(crate) middlewares: Vec<Arc<dyn ModuleMiddleware>>,
44}
45
46impl Cranelift {
47 pub fn new() -> Self {
50 Self {
51 enable_nan_canonicalization: false,
52 enable_verifier: false,
53 opt_level: CraneliftOptLevel::Speed,
54 enable_pic: false,
55 num_threads: std::thread::available_parallelism().unwrap_or(NonZero::new(1).unwrap()),
56 middlewares: vec![],
57 enable_perfmap: false,
58 }
59 }
60
61 pub fn canonicalize_nans(&mut self, enable: bool) -> &mut Self {
66 self.enable_nan_canonicalization = enable;
67 self
68 }
69
70 pub fn num_threads(&mut self, num_threads: NonZero<usize>) -> &mut Self {
72 self.num_threads = num_threads;
73 self
74 }
75
76 pub fn opt_level(&mut self, opt_level: CraneliftOptLevel) -> &mut Self {
78 self.opt_level = opt_level;
79 self
80 }
81
82 pub fn isa(&self, target: &Target) -> CodegenResult<Arc<dyn TargetIsa>> {
84 let mut builder =
85 lookup(target.triple().clone()).expect("construct Cranelift ISA for triple");
86 let cpu_features = target.cpu_features();
88 if target.triple().architecture == Architecture::X86_64
89 && !cpu_features.contains(CpuFeature::SSE2)
90 {
91 panic!("x86 support requires SSE2");
92 }
93 if cpu_features.contains(CpuFeature::SSE3) {
94 builder.enable("has_sse3").expect("should be valid flag");
95 }
96 if cpu_features.contains(CpuFeature::SSSE3) {
97 builder.enable("has_ssse3").expect("should be valid flag");
98 }
99 if cpu_features.contains(CpuFeature::SSE41) {
100 builder.enable("has_sse41").expect("should be valid flag");
101 }
102 if cpu_features.contains(CpuFeature::SSE42) {
103 builder.enable("has_sse42").expect("should be valid flag");
104 }
105 if cpu_features.contains(CpuFeature::POPCNT) {
106 builder.enable("has_popcnt").expect("should be valid flag");
107 }
108 if cpu_features.contains(CpuFeature::AVX) {
109 builder.enable("has_avx").expect("should be valid flag");
110 }
111 if cpu_features.contains(CpuFeature::BMI1) {
112 builder.enable("has_bmi1").expect("should be valid flag");
113 }
114 if cpu_features.contains(CpuFeature::BMI2) {
115 builder.enable("has_bmi2").expect("should be valid flag");
116 }
117 if cpu_features.contains(CpuFeature::AVX2) {
118 builder.enable("has_avx2").expect("should be valid flag");
119 }
120 if cpu_features.contains(CpuFeature::AVX512DQ) {
121 builder
122 .enable("has_avx512dq")
123 .expect("should be valid flag");
124 }
125 if cpu_features.contains(CpuFeature::AVX512VL) {
126 builder
127 .enable("has_avx512vl")
128 .expect("should be valid flag");
129 }
130 if cpu_features.contains(CpuFeature::LZCNT) {
131 builder.enable("has_lzcnt").expect("should be valid flag");
132 }
133
134 builder.finish(self.flags(target))
135 }
136
137 pub fn flags(&self, target: &Target) -> settings::Flags {
139 let mut flags = settings::builder();
140
141 flags
143 .enable("enable_probestack")
144 .expect("should be valid flag");
145
146 if matches!(target.triple().architecture, Architecture::Aarch64(_)) {
148 flags
149 .set("probestack_strategy", "inline")
150 .expect("should be valid flag");
151 }
152
153 if self.enable_pic {
154 flags.enable("is_pic").expect("should be a valid flag");
155 }
156
157 flags
160 .enable("use_colocated_libcalls")
161 .expect("should be a valid flag");
162
163 flags
166 .enable("enable_multi_ret_implicit_sret")
167 .expect("should be a valid flag");
168
169 let enable_verifier = if self.enable_verifier {
171 "true"
172 } else {
173 "false"
174 };
175 flags
176 .set("enable_verifier", enable_verifier)
177 .expect("should be valid flag");
178 flags
179 .set("enable_safepoints", "true")
180 .expect("should be valid flag");
181
182 flags
183 .set(
184 "opt_level",
185 match self.opt_level {
186 CraneliftOptLevel::None => "none",
187 CraneliftOptLevel::Speed => "speed",
188 CraneliftOptLevel::SpeedAndSize => "speed_and_size",
189 },
190 )
191 .expect("should be valid flag");
192
193 let enable_nan_canonicalization = if self.enable_nan_canonicalization {
194 "true"
195 } else {
196 "false"
197 };
198 flags
199 .set("enable_nan_canonicalization", enable_nan_canonicalization)
200 .expect("should be valid flag");
201
202 settings::Flags::new(flags)
203 }
204}
205
206impl CompilerConfig for Cranelift {
207 fn enable_pic(&mut self) {
208 self.enable_pic = true;
209 }
210
211 fn enable_verifier(&mut self) {
212 self.enable_verifier = true;
213 }
214
215 fn enable_perfmap(&mut self) {
216 self.enable_perfmap = true;
217 }
218
219 fn canonicalize_nans(&mut self, enable: bool) {
220 self.enable_nan_canonicalization = enable;
221 }
222
223 fn compiler(self: Box<Self>) -> Box<dyn Compiler> {
225 Box::new(CraneliftCompiler::new(*self))
226 }
227
228 fn push_middleware(&mut self, middleware: Arc<dyn ModuleMiddleware>) {
230 self.middlewares.push(middleware);
231 }
232}
233
234impl Default for Cranelift {
235 fn default() -> Self {
236 Self::new()
237 }
238}
239
240impl From<Cranelift> for Engine {
241 fn from(config: Cranelift) -> Self {
242 EngineBuilder::new(config).engine()
243 }
244}