Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/isa/pulley_shared/mod.rs
1693 views
1
//! Common support compiling to either 32- or 64-bit Pulley bytecode.
2
3
mod abi;
4
mod inst;
5
mod lower;
6
mod settings;
7
8
use self::inst::EmitInfo;
9
use super::{Builder as IsaBuilder, FunctionAlignment};
10
use crate::{
11
MachTextSectionBuilder, TextSectionBuilder,
12
dominator_tree::DominatorTree,
13
ir,
14
isa::{self, IsaFlagsHashKey, OwnedTargetIsa, TargetIsa},
15
machinst::{self, CompiledCodeStencil, MachInst, SigSet, VCode},
16
result::CodegenResult,
17
settings::{self as shared_settings, Flags},
18
};
19
use alloc::boxed::Box;
20
use alloc::vec::Vec;
21
use core::fmt::Debug;
22
use core::marker::PhantomData;
23
use cranelift_control::ControlPlane;
24
use std::string::String;
25
use target_lexicon::{Architecture, Triple};
26
27
pub use settings::Flags as PulleyFlags;
28
29
/// A trait to abstract over the different kinds of Pulley targets that exist
30
/// (32- vs 64-bit).
31
pub trait PulleyTargetKind: 'static + Clone + Debug + Default + Send + Sync {
32
// Required types and methods.
33
34
fn pointer_width() -> PointerWidth;
35
36
// Provided methods. Don't overwrite.
37
38
fn name() -> &'static str {
39
match Self::pointer_width() {
40
PointerWidth::PointerWidth32 => "pulley32",
41
PointerWidth::PointerWidth64 => "pulley64",
42
}
43
}
44
}
45
46
pub enum PointerWidth {
47
PointerWidth32,
48
PointerWidth64,
49
}
50
51
impl PointerWidth {
52
pub fn bits(self) -> u8 {
53
match self {
54
PointerWidth::PointerWidth32 => 32,
55
PointerWidth::PointerWidth64 => 64,
56
}
57
}
58
59
pub fn bytes(self) -> u8 {
60
self.bits() / 8
61
}
62
}
63
64
/// A Pulley backend.
65
pub struct PulleyBackend<P>
66
where
67
P: PulleyTargetKind,
68
{
69
pulley_target: PhantomData<P>,
70
triple: Triple,
71
flags: Flags,
72
isa_flags: PulleyFlags,
73
}
74
75
impl<P> core::fmt::Debug for PulleyBackend<P>
76
where
77
P: PulleyTargetKind,
78
{
79
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80
let PulleyBackend {
81
pulley_target: _,
82
triple,
83
flags: _,
84
isa_flags: _,
85
} = self;
86
f.debug_struct("PulleyBackend")
87
.field("triple", triple)
88
.finish_non_exhaustive()
89
}
90
}
91
92
impl<P> core::fmt::Display for PulleyBackend<P>
93
where
94
P: PulleyTargetKind,
95
{
96
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
97
core::fmt::Debug::fmt(self, f)
98
}
99
}
100
101
impl<P> PulleyBackend<P>
102
where
103
P: PulleyTargetKind,
104
{
105
/// Create a new pulley backend with the given (shared) flags.
106
pub fn new_with_flags(
107
triple: Triple,
108
flags: shared_settings::Flags,
109
isa_flags: PulleyFlags,
110
) -> Self {
111
PulleyBackend {
112
pulley_target: PhantomData,
113
triple,
114
flags,
115
isa_flags,
116
}
117
}
118
119
/// This performs lowering to VCode, register-allocates the code, computes block layout and
120
/// finalizes branches. The result is ready for binary emission.
121
fn compile_vcode(
122
&self,
123
func: &ir::Function,
124
domtree: &DominatorTree,
125
ctrl_plane: &mut ControlPlane,
126
) -> CodegenResult<(VCode<inst::InstAndKind<P>>, regalloc2::Output)> {
127
let emit_info = EmitInfo::new(
128
func.signature.call_conv,
129
self.flags.clone(),
130
self.isa_flags.clone(),
131
);
132
let sigs = SigSet::new::<abi::PulleyMachineDeps<P>>(func, &self.flags)?;
133
let abi = abi::PulleyCallee::new(func, self, &self.isa_flags, &sigs)?;
134
machinst::compile::<Self>(func, domtree, self, abi, emit_info, sigs, ctrl_plane)
135
}
136
}
137
138
impl<P> TargetIsa for PulleyBackend<P>
139
where
140
P: PulleyTargetKind,
141
{
142
fn name(&self) -> &'static str {
143
P::name()
144
}
145
146
fn triple(&self) -> &Triple {
147
&self.triple
148
}
149
150
fn flags(&self) -> &Flags {
151
&self.flags
152
}
153
154
fn isa_flags(&self) -> Vec<shared_settings::Value> {
155
self.isa_flags.iter().collect()
156
}
157
158
fn isa_flags_hash_key(&self) -> IsaFlagsHashKey<'_> {
159
IsaFlagsHashKey(self.isa_flags.hash_key())
160
}
161
162
fn dynamic_vector_bytes(&self, _dynamic_ty: ir::Type) -> u32 {
163
512
164
}
165
166
fn page_size_align_log2(&self) -> u8 {
167
// Claim 64KiB pages to be conservative.
168
16
169
}
170
171
fn compile_function(
172
&self,
173
func: &ir::Function,
174
domtree: &DominatorTree,
175
want_disasm: bool,
176
ctrl_plane: &mut cranelift_control::ControlPlane,
177
) -> CodegenResult<CompiledCodeStencil> {
178
let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?;
179
180
let want_disasm =
181
want_disasm || (cfg!(feature = "trace-log") && log::log_enabled!(log::Level::Debug));
182
let emit_result = vcode.emit(&regalloc_result, want_disasm, &self.flags, ctrl_plane);
183
let frame_size = emit_result.frame_size;
184
let value_labels_ranges = emit_result.value_labels_ranges;
185
let buffer = emit_result.buffer;
186
let sized_stackslot_offsets = emit_result.sized_stackslot_offsets;
187
let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets;
188
189
if let Some(disasm) = emit_result.disasm.as_ref() {
190
log::debug!("disassembly:\n{disasm}");
191
}
192
193
Ok(CompiledCodeStencil {
194
buffer,
195
frame_size,
196
vcode: emit_result.disasm,
197
value_labels_ranges,
198
sized_stackslot_offsets,
199
dynamic_stackslot_offsets,
200
bb_starts: emit_result.bb_offsets,
201
bb_edges: emit_result.bb_edges,
202
})
203
}
204
205
fn emit_unwind_info(
206
&self,
207
_result: &crate::CompiledCode,
208
_kind: super::unwind::UnwindInfoKind,
209
) -> CodegenResult<Option<isa::unwind::UnwindInfo>> {
210
// TODO: actually support unwind info?
211
Ok(None)
212
}
213
214
fn text_section_builder(
215
&self,
216
num_labeled_funcs: usize,
217
) -> alloc::boxed::Box<dyn TextSectionBuilder> {
218
Box::new(MachTextSectionBuilder::<inst::InstAndKind<P>>::new(
219
num_labeled_funcs,
220
))
221
}
222
223
fn function_alignment(&self) -> FunctionAlignment {
224
inst::InstAndKind::<P>::function_alignment()
225
}
226
227
fn pretty_print_reg(&self, reg: crate::Reg, _size: u8) -> String {
228
format!("{reg:?}")
229
}
230
231
fn has_native_fma(&self) -> bool {
232
// The pulley interpreter does have fma opcodes.
233
true
234
}
235
236
fn has_round(&self) -> bool {
237
// The pulley interpreter does have rounding opcodes.
238
true
239
}
240
241
fn has_x86_blendv_lowering(&self, _ty: ir::Type) -> bool {
242
false
243
}
244
245
fn has_x86_pshufb_lowering(&self) -> bool {
246
false
247
}
248
249
fn has_x86_pmulhrsw_lowering(&self) -> bool {
250
false
251
}
252
253
fn has_x86_pmaddubsw_lowering(&self) -> bool {
254
false
255
}
256
257
fn default_argument_extension(&self) -> ir::ArgumentExtension {
258
ir::ArgumentExtension::None
259
}
260
}
261
262
/// Create a new Pulley ISA builder.
263
pub fn isa_builder(triple: Triple) -> IsaBuilder {
264
let constructor = match triple.architecture {
265
Architecture::Pulley32 | Architecture::Pulley32be => isa_constructor_32,
266
Architecture::Pulley64 | Architecture::Pulley64be => isa_constructor_64,
267
other => panic!("unexpected architecture {other:?}"),
268
};
269
IsaBuilder {
270
triple,
271
setup: self::settings::builder(),
272
constructor,
273
}
274
}
275
276
fn isa_constructor_32(
277
triple: Triple,
278
shared_flags: Flags,
279
builder: &shared_settings::Builder,
280
) -> CodegenResult<OwnedTargetIsa> {
281
use crate::settings::Configurable;
282
let mut builder = builder.clone();
283
builder.set("pointer_width", "pointer32").unwrap();
284
if triple.endianness().unwrap() == target_lexicon::Endianness::Big {
285
builder.enable("big_endian").unwrap();
286
}
287
let isa_flags = PulleyFlags::new(&shared_flags, &builder);
288
289
let backend =
290
PulleyBackend::<super::pulley32::Pulley32>::new_with_flags(triple, shared_flags, isa_flags);
291
Ok(backend.wrapped())
292
}
293
294
fn isa_constructor_64(
295
triple: Triple,
296
shared_flags: Flags,
297
builder: &shared_settings::Builder,
298
) -> CodegenResult<OwnedTargetIsa> {
299
use crate::settings::Configurable;
300
let mut builder = builder.clone();
301
builder.set("pointer_width", "pointer64").unwrap();
302
if triple.endianness().unwrap() == target_lexicon::Endianness::Big {
303
builder.enable("big_endian").unwrap();
304
}
305
let isa_flags = PulleyFlags::new(&shared_flags, &builder);
306
307
let backend =
308
PulleyBackend::<super::pulley64::Pulley64>::new_with_flags(triple, shared_flags, isa_flags);
309
Ok(backend.wrapped())
310
}
311
312
impl PulleyFlags {
313
fn endianness(&self) -> ir::Endianness {
314
if self.big_endian() {
315
ir::Endianness::Big
316
} else {
317
ir::Endianness::Little
318
}
319
}
320
}
321
322