Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/codegen/src/isa/x64/mod.rs
1693 views
1
//! X86_64-bit Instruction Set Architecture.
2
3
pub use self::inst::{AtomicRmwSeqOp, EmitInfo, EmitState, Inst, args, external};
4
5
use super::{OwnedTargetIsa, TargetIsa};
6
use crate::dominator_tree::DominatorTree;
7
use crate::ir::{self, Function, Type, types};
8
#[cfg(feature = "unwind")]
9
use crate::isa::unwind::systemv;
10
use crate::isa::x64::settings as x64_settings;
11
use crate::isa::{Builder as IsaBuilder, FunctionAlignment, IsaFlagsHashKey};
12
use crate::machinst::{
13
CompiledCode, CompiledCodeStencil, MachInst, MachTextSectionBuilder, Reg, SigSet,
14
TextSectionBuilder, VCode, compile,
15
};
16
use crate::result::CodegenResult;
17
use crate::settings::{self as shared_settings, Flags};
18
use crate::{Final, MachBufferFinalized};
19
use alloc::{boxed::Box, vec::Vec};
20
use core::fmt;
21
use cranelift_control::ControlPlane;
22
use std::string::String;
23
use target_lexicon::Triple;
24
25
mod abi;
26
mod inst;
27
mod lower;
28
mod pcc;
29
pub mod settings;
30
31
pub use inst::unwind::systemv::create_cie;
32
33
/// An X64 backend.
34
pub(crate) struct X64Backend {
35
triple: Triple,
36
flags: Flags,
37
x64_flags: x64_settings::Flags,
38
}
39
40
impl X64Backend {
41
/// Create a new X64 backend with the given (shared) flags.
42
fn new_with_flags(triple: Triple, flags: Flags, x64_flags: x64_settings::Flags) -> Self {
43
Self {
44
triple,
45
flags,
46
x64_flags,
47
}
48
}
49
50
fn compile_vcode(
51
&self,
52
func: &Function,
53
domtree: &DominatorTree,
54
ctrl_plane: &mut ControlPlane,
55
) -> CodegenResult<(VCode<inst::Inst>, regalloc2::Output)> {
56
// This performs lowering to VCode, register-allocates the code, computes
57
// block layout and finalizes branches. The result is ready for binary emission.
58
let emit_info = EmitInfo::new(self.flags.clone(), self.x64_flags.clone());
59
let sigs = SigSet::new::<abi::X64ABIMachineSpec>(func, &self.flags)?;
60
let abi = abi::X64Callee::new(func, self, &self.x64_flags, &sigs)?;
61
compile::compile::<Self>(func, domtree, self, abi, emit_info, sigs, ctrl_plane)
62
}
63
}
64
65
impl TargetIsa for X64Backend {
66
fn compile_function(
67
&self,
68
func: &Function,
69
domtree: &DominatorTree,
70
want_disasm: bool,
71
ctrl_plane: &mut ControlPlane,
72
) -> CodegenResult<CompiledCodeStencil> {
73
let (vcode, regalloc_result) = self.compile_vcode(func, domtree, ctrl_plane)?;
74
75
let emit_result = vcode.emit(&regalloc_result, want_disasm, &self.flags, ctrl_plane);
76
let frame_size = emit_result.frame_size;
77
let value_labels_ranges = emit_result.value_labels_ranges;
78
let buffer = emit_result.buffer;
79
let sized_stackslot_offsets = emit_result.sized_stackslot_offsets;
80
let dynamic_stackslot_offsets = emit_result.dynamic_stackslot_offsets;
81
82
if let Some(disasm) = emit_result.disasm.as_ref() {
83
crate::trace!("disassembly:\n{}", disasm);
84
}
85
86
Ok(CompiledCodeStencil {
87
buffer,
88
frame_size,
89
vcode: emit_result.disasm,
90
value_labels_ranges,
91
sized_stackslot_offsets,
92
dynamic_stackslot_offsets,
93
bb_starts: emit_result.bb_offsets,
94
bb_edges: emit_result.bb_edges,
95
})
96
}
97
98
fn flags(&self) -> &Flags {
99
&self.flags
100
}
101
102
fn isa_flags(&self) -> Vec<shared_settings::Value> {
103
self.x64_flags.iter().collect()
104
}
105
106
fn isa_flags_hash_key(&self) -> IsaFlagsHashKey<'_> {
107
IsaFlagsHashKey(self.x64_flags.hash_key())
108
}
109
110
fn dynamic_vector_bytes(&self, _dyn_ty: Type) -> u32 {
111
16
112
}
113
114
fn name(&self) -> &'static str {
115
"x64"
116
}
117
118
fn triple(&self) -> &Triple {
119
&self.triple
120
}
121
122
#[cfg(feature = "unwind")]
123
fn emit_unwind_info(
124
&self,
125
result: &CompiledCode,
126
kind: crate::isa::unwind::UnwindInfoKind,
127
) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
128
emit_unwind_info(&result.buffer, kind)
129
}
130
131
#[cfg(feature = "unwind")]
132
fn create_systemv_cie(&self) -> Option<gimli::write::CommonInformationEntry> {
133
Some(inst::unwind::systemv::create_cie())
134
}
135
136
#[cfg(feature = "unwind")]
137
fn map_regalloc_reg_to_dwarf(&self, reg: Reg) -> Result<u16, systemv::RegisterMappingError> {
138
inst::unwind::systemv::map_reg(reg).map(|reg| reg.0)
139
}
140
141
fn text_section_builder(&self, num_funcs: usize) -> Box<dyn TextSectionBuilder> {
142
Box::new(MachTextSectionBuilder::<inst::Inst>::new(num_funcs))
143
}
144
145
fn function_alignment(&self) -> FunctionAlignment {
146
Inst::function_alignment()
147
}
148
149
fn page_size_align_log2(&self) -> u8 {
150
debug_assert_eq!(1 << 12, 0x1000);
151
12
152
}
153
154
#[cfg(feature = "disas")]
155
fn to_capstone(&self) -> Result<capstone::Capstone, capstone::Error> {
156
use capstone::prelude::*;
157
Capstone::new()
158
.x86()
159
.mode(arch::x86::ArchMode::Mode64)
160
.syntax(arch::x86::ArchSyntax::Att)
161
.detail(true)
162
.build()
163
}
164
165
fn pretty_print_reg(&self, reg: Reg, size: u8) -> String {
166
inst::regs::pretty_print_reg(reg, size)
167
}
168
169
fn has_native_fma(&self) -> bool {
170
self.x64_flags.use_fma()
171
}
172
173
fn has_round(&self) -> bool {
174
self.x64_flags.use_sse41()
175
}
176
177
fn has_x86_blendv_lowering(&self, ty: Type) -> bool {
178
// The `blendvpd`, `blendvps`, and `pblendvb` instructions are all only
179
// available from SSE 4.1 and onwards. Otherwise the i16x8 type has no
180
// equivalent instruction which only looks at the top bit for a select
181
// operation, so that always returns `false`
182
self.x64_flags.use_sse41() && ty != types::I16X8
183
}
184
185
fn has_x86_pshufb_lowering(&self) -> bool {
186
self.x64_flags.use_ssse3()
187
}
188
189
fn has_x86_pmulhrsw_lowering(&self) -> bool {
190
self.x64_flags.use_ssse3()
191
}
192
193
fn has_x86_pmaddubsw_lowering(&self) -> bool {
194
self.x64_flags.use_ssse3()
195
}
196
197
fn default_argument_extension(&self) -> ir::ArgumentExtension {
198
// This is copied/carried over from a historical piece of code in
199
// Wasmtime:
200
//
201
// https://github.com/bytecodealliance/wasmtime/blob/a018a5a9addb77d5998021a0150192aa955c71bf/crates/cranelift/src/lib.rs#L366-L374
202
//
203
// Whether or not it is still applicable here is unsure, but it's left
204
// the same as-is for now to reduce the likelihood of problems arising.
205
ir::ArgumentExtension::Uext
206
}
207
}
208
209
/// Emit unwind info for an x86 target.
210
pub fn emit_unwind_info(
211
buffer: &MachBufferFinalized<Final>,
212
kind: crate::isa::unwind::UnwindInfoKind,
213
) -> CodegenResult<Option<crate::isa::unwind::UnwindInfo>> {
214
use crate::isa::unwind::{UnwindInfo, UnwindInfoKind};
215
Ok(match kind {
216
UnwindInfoKind::SystemV => {
217
let mapper = self::inst::unwind::systemv::RegisterMapper;
218
Some(UnwindInfo::SystemV(
219
crate::isa::unwind::systemv::create_unwind_info_from_insts(
220
&buffer.unwind_info[..],
221
buffer.data().len(),
222
&mapper,
223
)?,
224
))
225
}
226
UnwindInfoKind::Windows => Some(UnwindInfo::WindowsX64(
227
crate::isa::unwind::winx64::create_unwind_info_from_insts::<
228
self::inst::unwind::winx64::RegisterMapper,
229
>(&buffer.unwind_info[..])?,
230
)),
231
_ => None,
232
})
233
}
234
235
impl fmt::Display for X64Backend {
236
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
237
f.debug_struct("MachBackend")
238
.field("name", &self.name())
239
.field("triple", &self.triple())
240
.field("flags", &format!("{}", self.flags()))
241
.finish()
242
}
243
}
244
245
/// Create a new `isa::Builder`.
246
pub(crate) fn isa_builder(triple: Triple) -> IsaBuilder {
247
IsaBuilder {
248
triple,
249
setup: x64_settings::builder(),
250
constructor: isa_constructor,
251
}
252
}
253
254
fn isa_constructor(
255
triple: Triple,
256
shared_flags: Flags,
257
builder: &shared_settings::Builder,
258
) -> CodegenResult<OwnedTargetIsa> {
259
let isa_flags = x64_settings::Flags::new(&shared_flags, builder);
260
let backend = X64Backend::new_with_flags(triple, shared_flags, isa_flags);
261
Ok(backend.wrapped())
262
}
263
264