Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/cranelift/assembler-x64/meta/src/dsl.rs
1692 views
1
//! Defines a domain-specific language (DSL) for describing x64 instructions.
2
//!
3
//! This language is intended to be:
4
//! - compact--i.e., define an x64 instruction on a single line, and
5
//! - a close-to-direct mapping of what we read in the x64 reference manual.
6
7
mod custom;
8
mod encoding;
9
mod features;
10
pub mod format;
11
12
pub use custom::{Custom, Customization};
13
pub use encoding::{Encoding, ModRmKind, OpcodeMod};
14
pub use encoding::{Evex, Length, Vex, VexEscape, VexPrefix, evex, vex};
15
pub use encoding::{
16
Group1Prefix, Group2Prefix, Group3Prefix, Group4Prefix, Opcodes, Prefixes, Rex, TupleType, rex,
17
};
18
pub use features::{ALL_FEATURES, Feature, Features};
19
pub use format::{Eflags, Extension, Format, Location, Mutability, Operand, OperandKind, RegClass};
20
pub use format::{align, fmt, implicit, r, rw, sxl, sxq, sxw, w};
21
22
/// Abbreviated constructor for an x64 instruction.
23
pub fn inst(
24
mnemonic: impl Into<String>,
25
format: Format,
26
encoding: impl Into<Encoding>,
27
features: impl Into<Features>,
28
) -> Inst {
29
let encoding = encoding.into();
30
encoding.validate(&format.operands);
31
Inst {
32
mnemonic: mnemonic.into(),
33
format,
34
encoding,
35
features: features.into(),
36
alternate: None,
37
has_trap: false,
38
custom: Custom::default(),
39
}
40
}
41
42
/// An x64 instruction.
43
///
44
/// Use [`inst`] to construct this within the
45
/// [`instructions`](super::instructions) module. This structure is designed to
46
/// represent all of the information for one instruction (a table row) in the
47
/// x64 _Instruction Set Reference_ or at least enough to generate code to emit
48
/// the instruction.
49
pub struct Inst {
50
/// The instruction name as represented in the x64 reference manual. This is
51
/// the pretty-printed name used for disassembly. Multiple instructions may
52
/// have the same mnemonic, though; the combination of this field and the
53
/// format name must be unique (see [`Inst::name`]).
54
pub mnemonic: String,
55
/// The instruction operands, typically represented in the "Instruction"
56
/// column of the x64 reference manual.
57
pub format: Format,
58
/// The instruction encoding, typically represented in the "Opcode" column
59
/// of the x64 reference manual.
60
pub encoding: Encoding,
61
/// The CPU features required to use this instruction; this combines the
62
/// "64-bit/32-bit Mode Support" and "CPUID Feature Flag" columns of the x64
63
/// reference manual.
64
pub features: Features,
65
/// An alternate version of this instruction, if it exists.
66
pub alternate: Option<Alternate>,
67
/// Whether or not this instruction can trap and thus needs a `TrapCode`
68
/// payload in the instruction itself.
69
pub has_trap: bool,
70
/// Whether or not this instruction uses custom, external functions
71
/// instead of Rust code generated by this crate.
72
pub custom: Custom,
73
}
74
75
impl Inst {
76
/// The unique name for this instruction.
77
///
78
/// To avoid ambiguity, this name combines the instruction mnemonic and the
79
/// format name in snake case. This is used in generated code to name the
80
/// instruction `struct` and builder functions.
81
///
82
/// In rare cases, this `<mnemonic>_<format>` scheme does not uniquely
83
/// identify an instruction in x64 ISA (e.g., some extended versions,
84
/// VEX/EVEX). In these cases, we append a minimal identifier to
85
/// the format name (e.g., `sx*`) to keep this unique.
86
#[must_use]
87
pub fn name(&self) -> String {
88
format!(
89
"{}_{}",
90
self.mnemonic.to_lowercase(),
91
self.format.name.to_lowercase()
92
)
93
}
94
95
/// Flags this instruction as being able to trap, so needs a `TrapCode` at
96
/// compile time to track this.
97
pub fn has_trap(mut self) -> Self {
98
self.has_trap = true;
99
self
100
}
101
102
/// Indicate this instruction as needing custom processing.
103
pub fn custom(mut self, custom: impl Into<Custom>) -> Self {
104
self.custom = custom.into();
105
self
106
}
107
108
/// Sets the alternate version of this instruction, if it exists.
109
pub fn alt(mut self, feature: Feature, alternate: impl Into<String>) -> Self {
110
self.alternate = Some(Alternate {
111
feature,
112
name: alternate.into(),
113
});
114
self
115
}
116
}
117
118
impl core::fmt::Display for Inst {
119
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
120
let Inst {
121
mnemonic: name,
122
format,
123
encoding,
124
features,
125
alternate,
126
has_trap,
127
custom,
128
} = self;
129
write!(f, "{name}: {format} => {encoding}")?;
130
write!(f, " [{features}]")?;
131
if let Some(alternate) = alternate {
132
write!(f, " (alternate: {alternate})")?;
133
}
134
if *has_trap {
135
write!(f, " has_trap")?;
136
}
137
if !custom.is_empty() {
138
write!(f, " custom({custom})")?;
139
}
140
Ok(())
141
}
142
}
143
144
/// An alternate version of an instruction.
145
///
146
/// Some AVX-specific context: some instructions have the same semantics in
147
/// their SSE and AVX encodings. In these cases, we use this structure to record
148
/// the name of the upgraded version of the instruction, allowing us to replace
149
/// the SSE instruction with its AVX version during lowering. For AVX, using the
150
/// VEX-encoded instruction is typically better than its legacy SSE version:
151
/// - VEX can encode three operands
152
/// - VEX allows unaligned memory access (avoids additional `MOVUPS`)
153
/// - VEX can compact byte-long prefixes into the VEX prefix
154
/// - VEX instructions zero the upper bits of XMM registers by default
155
pub struct Alternate {
156
/// Indicate the feature check to use to trigger the replacement.
157
pub feature: Feature,
158
/// The full name (see [`Inst::name`]) of the instruction used for
159
/// replacement.
160
pub name: String,
161
}
162
163
impl core::fmt::Display for Alternate {
164
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
165
write!(f, "{} => {}", self.feature, self.name)
166
}
167
}
168
169