Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

asm: notate instruction alignment, SSE feature flags #10446

Merged
merged 2 commits into from
Mar 24, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cranelift/assembler-x64/meta/src/dsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ pub mod format;

pub use encoding::{rex, vex, Encoding, LegacyPrefix, Rex};
pub use features::{Feature, Features, ALL_FEATURES};
pub use format::{fmt, r, rw, sxl, sxq, sxw};
pub use format::{align, fmt, r, rw, sxl, sxq, sxw};
pub use format::{Extension, Format, Location, Mutability, Operand, OperandKind};

/// Abbreviated constructor for an x64 instruction.
Expand Down
26 changes: 24 additions & 2 deletions cranelift/assembler-x64/meta/src/dsl/features.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ use std::ops::BitOr;
/// let fs = Feature::_64b | Feature::compat;
/// assert_eq!(fs.to_string(), "_64b | compat");
/// ```
///
/// Duplicate features are not allowed and will cause a panic.
///
/// ```should_panic
/// # use cranelift_assembler_x64_meta::dsl::Feature;
/// let fs = Feature::_64b | Feature::_64b;
/// ```
#[derive(PartialEq)]
pub struct Features(Vec<Feature>);

Expand Down Expand Up @@ -47,11 +54,15 @@ impl fmt::Display for Features {
/// processors. It consists of two sub-modes:
/// - __64-bit mode__: uses the full 64-bit address space
/// - __compatibility mode__: allows use of legacy 32-bit code
#[derive(Clone, Copy, PartialEq)]
///
/// Other features listed here should match the __CPUID Feature Flags__ column
/// of the instruction tables of the x64 reference manual.
#[derive(Clone, Copy, Debug, PartialEq)]
#[allow(non_camel_case_types, reason = "makes DSL definitions easier to read")]
pub enum Feature {
_64b,
compat,
sse,
}

/// List all CPU features.
Expand All @@ -61,13 +72,14 @@ pub enum Feature {
/// transcribe each variant to an `enum` available in the generated layer above.
/// If this list is incomplete, we will (fortunately) see compile errors for
/// generated functions that use the missing variants.
pub const ALL_FEATURES: &[Feature] = &[Feature::_64b, Feature::compat];
pub const ALL_FEATURES: &[Feature] = &[Feature::_64b, Feature::compat, Feature::sse];

impl fmt::Display for Feature {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Feature::_64b => write!(f, "_64b"),
Feature::compat => write!(f, "compat"),
Feature::sse => write!(f, "sse"),
}
}
}
Expand All @@ -87,6 +99,16 @@ impl From<Option<Feature>> for Features {
impl BitOr for Feature {
type Output = Features;
fn bitor(self, rhs: Self) -> Self::Output {
assert_ne!(self, rhs, "duplicate feature: {self:?}");
Features(vec![self, rhs])
}
}

impl BitOr<Feature> for Features {
type Output = Features;
fn bitor(mut self, rhs: Feature) -> Self::Output {
assert!(!self.0.contains(&rhs), "duplicate feature: {rhs:?}");
self.0.push(rhs);
self
}
}
46 changes: 35 additions & 11 deletions cranelift/assembler-x64/meta/src/dsl/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,16 +37,26 @@ pub fn rw(location: Location) -> Operand {
location,
mutability: Mutability::ReadWrite,
extension: Extension::default(),
align: false,
}
}

/// An abbreviated constructor for a "read" operand.
#[must_use]
pub fn r(location: Location) -> Operand {
pub fn r(op: impl Into<Operand>) -> Operand {
let op = op.into();
assert!(op.mutability.is_read());
op
}

/// An abbreviated constructor for a memory operand that requires alignment.
pub fn align(location: Location) -> Operand {
assert!(location.uses_memory());
Operand {
location,
mutability: Mutability::Read,
extension: Extension::None,
align: true,
}
}

Expand All @@ -63,6 +73,7 @@ pub fn sxq(location: Location) -> Operand {
location,
mutability: Mutability::Read,
extension: Extension::SignExtendQuad,
align: false,
}
}

Expand All @@ -79,6 +90,7 @@ pub fn sxl(location: Location) -> Operand {
location,
mutability: Mutability::Read,
extension: Extension::SignExtendLong,
align: false,
}
}

Expand All @@ -95,6 +107,7 @@ pub fn sxw(location: Location) -> Operand {
location,
mutability: Mutability::Read,
extension: Extension::SignExtendWord,
align: false,
}
}

Expand Down Expand Up @@ -153,10 +166,11 @@ impl core::fmt::Display for Format {
/// _Instruction Set Reference_.
///
/// ```
/// # use cranelift_assembler_x64_meta::dsl::{Operand, r, rw, sxq, Location::*};
/// # use cranelift_assembler_x64_meta::dsl::{align, r, rw, sxq, Location::*};
/// assert_eq!(r(r8).to_string(), "r8");
/// assert_eq!(rw(rm16).to_string(), "rm16[rw]");
/// assert_eq!(sxq(imm32).to_string(), "imm32[sxq]");
/// assert_eq!(align(rm128).to_string(), "rm128[align]");
/// ```
#[derive(Clone, Copy, Debug)]
pub struct Operand {
Expand All @@ -166,19 +180,28 @@ pub struct Operand {
pub mutability: Mutability,
/// Some operands are sign- or zero-extended.
pub extension: Extension,
/// Some memory operands require alignment; `true` indicates that the memory
/// address used in the operand must align to the size of the operand (e.g.,
/// `m128` must be 16-byte aligned).
pub align: bool,
}

impl core::fmt::Display for Operand {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
let Self { location, mutability, extension } = self;
let Self { location, mutability, extension, align } = self;
write!(f, "{location}")?;
let has_default_mutability = matches!(mutability, Mutability::Read);
let has_default_extension = matches!(extension, Extension::None);
match (has_default_mutability, has_default_extension) {
(true, true) => {}
(true, false) => write!(f, "[{extension}]")?,
(false, true) => write!(f, "[{mutability}]")?,
(false, false) => write!(f, "[{mutability},{extension}]")?,
let mut flags = vec![];
if !matches!(mutability, Mutability::Read) {
flags.push(format!("{mutability}"));
}
if !matches!(extension, Extension::None) {
flags.push(format!("{extension}"));
}
if *align != false {
flags.push("align".to_owned());
}
if !flags.is_empty() {
write!(f, "[{}]", flags.join(","))?;
}
Ok(())
}
Expand All @@ -188,7 +211,8 @@ impl From<Location> for Operand {
fn from(location: Location) -> Self {
let mutability = Mutability::default();
let extension = Extension::default();
Self { location, mutability, extension }
let align = false;
Self { location, mutability, extension, align }
}
}

Expand Down
8 changes: 4 additions & 4 deletions cranelift/assembler-x64/meta/src/instructions/add.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::dsl::{fmt, inst, r, rex, rw, sxl, sxq};
use crate::dsl::{align, fmt, inst, r, rex, rw, sxl, sxq};
use crate::dsl::{Feature::*, Inst, Location::*};

pub fn list() -> Vec<Inst> {
Expand All @@ -21,9 +21,6 @@ pub fn list() -> Vec<Inst> {
inst("addw", fmt("RM", [rw(r16), r(rm16)]), rex([0x66, 0x3]).r(), _64b | compat),
inst("addl", fmt("RM", [rw(r32), r(rm32)]), rex(0x3).r(), _64b | compat),
inst("addq", fmt("RM", [rw(r64), r(rm64)]), rex(0x3).w().r(), _64b),
// SSE vector instructions
inst("addps", fmt("A", [rw(xmm), r(rm128)]), rex([0x0F, 0x58]).r(), _64b),
inst("addpd", fmt("A", [rw(xmm), r(rm128)]), rex([0x66, 0x0F, 0x58]).r(), _64b),
// Add with carry.
inst("adcb", fmt("I", [rw(al), r(imm8)]), rex(0x14).ib(), _64b | compat),
inst("adcw", fmt("I", [rw(ax), r(imm16)]), rex([0x66, 0x15]).iw(), _64b | compat),
Expand All @@ -43,5 +40,8 @@ pub fn list() -> Vec<Inst> {
inst("adcw", fmt("RM", [rw(r16), r(rm16)]), rex([0x66, 0x13]).r(), _64b | compat),
inst("adcl", fmt("RM", [rw(r32), r(rm32)]), rex(0x13).r(), _64b | compat),
inst("adcq", fmt("RM", [rw(r64), r(rm64)]), rex(0x13).w().r(), _64b),
// Vector instructions.
inst("addps", fmt("A", [rw(xmm), r(align(rm128))]), rex([0x0F, 0x58]).r(), _64b | compat | sse),
inst("addpd", fmt("A", [rw(xmm), r(align(rm128))]), rex([0x66, 0x0F, 0x58]).r(), _64b | compat | sse),
]
}
8 changes: 4 additions & 4 deletions cranelift/assembler-x64/meta/src/instructions/and.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::dsl::{fmt, inst, r, rex, rw, sxl, sxq};
use crate::dsl::{align, fmt, inst, r, rex, rw, sxl, sxq};
use crate::dsl::{Feature::*, Inst, Location::*};

pub fn list() -> Vec<Inst> {
Expand Down Expand Up @@ -28,8 +28,8 @@ pub fn list() -> Vec<Inst> {
inst("andw", fmt("RM", [rw(r16), r(rm16)]), rex([0x66, 0x23]).r(), _64b | compat),
inst("andl", fmt("RM", [rw(r32), r(rm32)]), rex(0x23).r(), _64b | compat),
inst("andq", fmt("RM", [rw(r64), r(rm64)]), rex(0x23).w().r(), _64b),
// SSE vector instructions
inst("andps", fmt("A", [rw(xmm), r(rm128)]), rex([0x0F, 0x54]).r(), _64b),
inst("andpd", fmt("A", [rw(xmm), r(rm128)]), rex([0x66, 0x0F, 0x54]).r(), _64b),
// Vector instructions.
inst("andps", fmt("A", [rw(xmm), r(align(rm128))]), rex([0x0F, 0x54]).r(), _64b | compat | sse),
inst("andpd", fmt("A", [rw(xmm), r(align(rm128))]), rex([0x66, 0x0F, 0x54]).r(), _64b | compat | sse),
]
}
8 changes: 4 additions & 4 deletions cranelift/assembler-x64/meta/src/instructions/or.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::dsl::{fmt, inst, r, rex, rw, sxl, sxq};
use crate::dsl::{align, fmt, inst, r, rex, rw, sxl, sxq};
use crate::dsl::{Feature::*, Inst, Location::*};

pub fn list() -> Vec<Inst> {
Expand All @@ -21,8 +21,8 @@ pub fn list() -> Vec<Inst> {
inst("orw", fmt("RM", [rw(r16), r(rm16)]), rex([0x66, 0x0B]).r(), _64b | compat),
inst("orl", fmt("RM", [rw(r32), r(rm32)]), rex(0x0B).r(), _64b | compat),
inst("orq", fmt("RM", [rw(r64), r(rm64)]), rex(0x0B).w().r(), _64b),
// SSE vector instructions
inst("orps", fmt("A", [rw(xmm), r(rm128)]), rex([0x0F, 0x56]).r(), _64b),
inst("orpd", fmt("A", [rw(xmm), r(rm128)]), rex([0x66, 0x0F, 0x56]).r(), _64b),
// Vector instructions.
inst("orps", fmt("A", [rw(xmm), r(align(rm128))]), rex([0x0F, 0x56]).r(), _64b | compat | sse),
inst("orpd", fmt("A", [rw(xmm), r(align(rm128))]), rex([0x66, 0x0F, 0x56]).r(), _64b | compat | sse),
]
}
8 changes: 4 additions & 4 deletions cranelift/assembler-x64/meta/src/instructions/sub.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::dsl::{fmt, inst, r, rex, rw, sxl, sxq};
use crate::dsl::{align, fmt, inst, r, rex, rw, sxl, sxq};
use crate::dsl::{Feature::*, Inst, Location::*};

pub fn list() -> Vec<Inst> {
Expand All @@ -21,9 +21,6 @@ pub fn list() -> Vec<Inst> {
inst("subw", fmt("RM", [rw(r16), r(rm16)]), rex([0x66, 0x2B]).r(), _64b | compat),
inst("subl", fmt("RM", [rw(r32), r(rm32)]), rex(0x2B).r(), _64b | compat),
inst("subq", fmt("RM", [rw(r64), r(rm64)]), rex(0x2B).w().r(), _64b),
// SSE vector instructions
inst("subps", fmt("A", [rw(xmm), r(rm128)]), rex([0x0F, 0x5C]).r(), _64b),
inst("subpd", fmt("A", [rw(xmm), r(rm128)]), rex([0x66, 0x0F, 0x5C]).r(), _64b),
// Subtract with borrow.
inst("sbbb", fmt("I", [rw(al), r(imm8)]), rex(0x1C).ib(), _64b | compat),
inst("sbbw", fmt("I", [rw(ax), r(imm16)]), rex([0x66, 0x1D]).iw(), _64b | compat),
Expand All @@ -43,5 +40,8 @@ pub fn list() -> Vec<Inst> {
inst("sbbw", fmt("RM", [rw(r16), r(rm16)]), rex([0x66, 0x1B]).r(), _64b | compat),
inst("sbbl", fmt("RM", [rw(r32), r(rm32)]), rex(0x1B).r(), _64b | compat),
inst("sbbq", fmt("RM", [rw(r64), r(rm64)]), rex(0x1B).w().r(), _64b),
// Vector instructions.
inst("subps", fmt("A", [rw(xmm), r(align(rm128))]), rex([0x0F, 0x5C]).r(), _64b | compat | sse),
inst("subpd", fmt("A", [rw(xmm), r(align(rm128))]), rex([0x66, 0x0F, 0x5C]).r(), _64b | compat | sse),
]
}
8 changes: 4 additions & 4 deletions cranelift/assembler-x64/meta/src/instructions/xor.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use crate::dsl::{fmt, inst, r, rex, rw, sxl, sxq};
use crate::dsl::{align, fmt, inst, r, rex, rw, sxl, sxq};
use crate::dsl::{Feature::*, Inst, Location::*};

pub fn list() -> Vec<Inst> {
Expand All @@ -21,8 +21,8 @@ pub fn list() -> Vec<Inst> {
inst("xorw", fmt("RM", [rw(r16), r(rm16)]), rex([0x66, 0x33]).r(), _64b | compat),
inst("xorl", fmt("RM", [rw(r32), r(rm32)]), rex(0x33).r(), _64b | compat),
inst("xorq", fmt("RM", [rw(r64), r(rm64)]), rex(0x33).w().r(), _64b),
// SSE vector instructions
inst("xorps", fmt("A", [rw(xmm), r(rm128)]), rex([0x0F, 0x57]).r(), _64b),
inst("xorpd", fmt("A", [rw(xmm), r(rm128)]), rex([0x66, 0x0F, 0x57]).r(), _64b),
// Vector instructions.
inst("xorps", fmt("A", [rw(xmm), r(align(rm128))]), rex([0x0F, 0x57]).r(), _64b | compat | sse),
inst("xorpd", fmt("A", [rw(xmm), r(align(rm128))]), rex([0x66, 0x0F, 0x57]).r(), _64b | compat | sse),
]
}
24 changes: 16 additions & 8 deletions cranelift/codegen/meta/src/gen_asm.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,14 @@ pub fn rust_param_raw(op: &Operand) -> String {
format!("u{bits}")
}
}
OperandKind::RegMem(rm) => match rm.bits() {
128 => "&XmmMemAligned".to_string(),
_ => "&GprMem".to_string(),
},
OperandKind::RegMem(rm) => {
let reg = match rm.bits() {
128 => "Xmm",
_ => "Gpr",
};
let aligned = if op.align { "Aligned" } else { "" };
format!("&{reg}Mem{aligned}")
}
OperandKind::Reg(r) => match r.bits() {
128 => "Xmm".to_string(),
_ => "Gpr".to_string(),
Expand Down Expand Up @@ -203,10 +207,14 @@ pub fn isle_param_raw(op: &Operand) -> String {
_ => "Gpr".to_string(),
},
OperandKind::FixedReg(_) => "Gpr".to_string(),
OperandKind::RegMem(rm) => match rm.bits() {
128 => "XmmMemAligned".to_string(),
_ => "GprMem".to_string(),
},
OperandKind::RegMem(rm) => {
let reg = match rm.bits() {
128 => "Xmm",
_ => "Gpr",
};
let aligned = if op.align { "Aligned" } else { "" };
format!("{reg}Mem{aligned}")
}
}
}

Expand Down
3 changes: 2 additions & 1 deletion cranelift/codegen/src/isa/x64/inst/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,11 @@ impl Inst {

Inst::External { inst } => {
use cranelift_assembler_x64::Feature::*;
let features = smallvec![];
let mut features = smallvec![];
for f in inst.features() {
match f {
_64b | compat => {}
sse => features.push(InstructionSet::SSE),
}
}
features
Expand Down
Loading