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