Path: blob/main/cranelift/assembler-x64/meta/src/dsl.rs
1692 views
//! Defines a domain-specific language (DSL) for describing x64 instructions.1//!2//! This language is intended to be:3//! - compact--i.e., define an x64 instruction on a single line, and4//! - a close-to-direct mapping of what we read in the x64 reference manual.56mod custom;7mod encoding;8mod features;9pub mod format;1011pub use custom::{Custom, Customization};12pub use encoding::{Encoding, ModRmKind, OpcodeMod};13pub use encoding::{Evex, Length, Vex, VexEscape, VexPrefix, evex, vex};14pub use encoding::{15Group1Prefix, Group2Prefix, Group3Prefix, Group4Prefix, Opcodes, Prefixes, Rex, TupleType, rex,16};17pub use features::{ALL_FEATURES, Feature, Features};18pub use format::{Eflags, Extension, Format, Location, Mutability, Operand, OperandKind, RegClass};19pub use format::{align, fmt, implicit, r, rw, sxl, sxq, sxw, w};2021/// Abbreviated constructor for an x64 instruction.22pub fn inst(23mnemonic: impl Into<String>,24format: Format,25encoding: impl Into<Encoding>,26features: impl Into<Features>,27) -> Inst {28let encoding = encoding.into();29encoding.validate(&format.operands);30Inst {31mnemonic: mnemonic.into(),32format,33encoding,34features: features.into(),35alternate: None,36has_trap: false,37custom: Custom::default(),38}39}4041/// An x64 instruction.42///43/// Use [`inst`] to construct this within the44/// [`instructions`](super::instructions) module. This structure is designed to45/// represent all of the information for one instruction (a table row) in the46/// x64 _Instruction Set Reference_ or at least enough to generate code to emit47/// the instruction.48pub struct Inst {49/// The instruction name as represented in the x64 reference manual. This is50/// the pretty-printed name used for disassembly. Multiple instructions may51/// have the same mnemonic, though; the combination of this field and the52/// format name must be unique (see [`Inst::name`]).53pub mnemonic: String,54/// The instruction operands, typically represented in the "Instruction"55/// column of the x64 reference manual.56pub format: Format,57/// The instruction encoding, typically represented in the "Opcode" column58/// of the x64 reference manual.59pub encoding: Encoding,60/// The CPU features required to use this instruction; this combines the61/// "64-bit/32-bit Mode Support" and "CPUID Feature Flag" columns of the x6462/// reference manual.63pub features: Features,64/// An alternate version of this instruction, if it exists.65pub alternate: Option<Alternate>,66/// Whether or not this instruction can trap and thus needs a `TrapCode`67/// payload in the instruction itself.68pub has_trap: bool,69/// Whether or not this instruction uses custom, external functions70/// instead of Rust code generated by this crate.71pub custom: Custom,72}7374impl Inst {75/// The unique name for this instruction.76///77/// To avoid ambiguity, this name combines the instruction mnemonic and the78/// format name in snake case. This is used in generated code to name the79/// instruction `struct` and builder functions.80///81/// In rare cases, this `<mnemonic>_<format>` scheme does not uniquely82/// identify an instruction in x64 ISA (e.g., some extended versions,83/// VEX/EVEX). In these cases, we append a minimal identifier to84/// the format name (e.g., `sx*`) to keep this unique.85#[must_use]86pub fn name(&self) -> String {87format!(88"{}_{}",89self.mnemonic.to_lowercase(),90self.format.name.to_lowercase()91)92}9394/// Flags this instruction as being able to trap, so needs a `TrapCode` at95/// compile time to track this.96pub fn has_trap(mut self) -> Self {97self.has_trap = true;98self99}100101/// Indicate this instruction as needing custom processing.102pub fn custom(mut self, custom: impl Into<Custom>) -> Self {103self.custom = custom.into();104self105}106107/// Sets the alternate version of this instruction, if it exists.108pub fn alt(mut self, feature: Feature, alternate: impl Into<String>) -> Self {109self.alternate = Some(Alternate {110feature,111name: alternate.into(),112});113self114}115}116117impl core::fmt::Display for Inst {118fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {119let Inst {120mnemonic: name,121format,122encoding,123features,124alternate,125has_trap,126custom,127} = self;128write!(f, "{name}: {format} => {encoding}")?;129write!(f, " [{features}]")?;130if let Some(alternate) = alternate {131write!(f, " (alternate: {alternate})")?;132}133if *has_trap {134write!(f, " has_trap")?;135}136if !custom.is_empty() {137write!(f, " custom({custom})")?;138}139Ok(())140}141}142143/// An alternate version of an instruction.144///145/// Some AVX-specific context: some instructions have the same semantics in146/// their SSE and AVX encodings. In these cases, we use this structure to record147/// the name of the upgraded version of the instruction, allowing us to replace148/// the SSE instruction with its AVX version during lowering. For AVX, using the149/// VEX-encoded instruction is typically better than its legacy SSE version:150/// - VEX can encode three operands151/// - VEX allows unaligned memory access (avoids additional `MOVUPS`)152/// - VEX can compact byte-long prefixes into the VEX prefix153/// - VEX instructions zero the upper bits of XMM registers by default154pub struct Alternate {155/// Indicate the feature check to use to trigger the replacement.156pub feature: Feature,157/// The full name (see [`Inst::name`]) of the instruction used for158/// replacement.159pub name: String,160}161162impl core::fmt::Display for Alternate {163fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {164write!(f, "{} => {}", self.feature, self.name)165}166}167168169