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