Skip to content

Commit

Permalink
Add 128bit SSE internals for assembler
Browse files Browse the repository at this point in the history
  • Loading branch information
rahulchaphalkar committed Jan 16, 2025
1 parent 0a48682 commit 6062bbf
Show file tree
Hide file tree
Showing 10 changed files with 259 additions and 251 deletions.
4 changes: 2 additions & 2 deletions cranelift/assembler/meta/src/dsl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@
//! - compact--i.e., define an x64 instruction on a single line
//! - and a close-to-direct mapping of what we read in the x64 developer manual
pub mod encoding;
mod encoding;
mod features;
pub mod format;

pub use encoding::{rex, vex, sse, Encoding, LegacyPrefixes, Rex, Sse};
pub use encoding::{rex, vex, Encoding, LegacyPrefixes, Rex};
pub use features::Features;
pub use format::{fmt, r, rw, sxl, sxq, sxw};
pub use format::{Extension, Format, Location, Mutability, Operand, OperandKind};
Expand Down
118 changes: 0 additions & 118 deletions cranelift/assembler/meta/src/dsl/encoding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,27 +20,15 @@ pub fn vex() -> Vex {
Vex {}
}

/// SSE instructions.
#[must_use]
pub fn sse(opcode: u32) -> Sse {
Sse {
prefixes: LegacyPrefixes::NoPrefix,
opcode,
r: false,
}
}

pub enum Encoding {
Rex(Rex),
Vex(Vex),
Sse(Sse),
}
impl Encoding {
pub fn validate(&self, operands: &[Operand]) {
match self {
Encoding::Rex(rex) => rex.validate(operands),
Encoding::Vex(vex) => vex.validate(),
Encoding::Sse(sse) => sse.validate(operands),
}
}

Expand All @@ -51,7 +39,6 @@ impl fmt::Display for Encoding {
match self {
Encoding::Rex(rex) => write!(f, "{rex}"),
Encoding::Vex(_vex) => todo!(),
Encoding::Sse(sse) => write!(f, "{sse}"),
}
}
}
Expand Down Expand Up @@ -246,108 +233,3 @@ impl Vex {
todo!()
}
}

pub struct Sse {
/// Any legacy prefixes that should be included with the instruction.
pub prefixes: LegacyPrefixes,
/// The opcode of the instruction.
pub opcode: u32,
/// From the specification: "indicates that the ModR/M byte of the
/// instruction contains a register operand and an r/m operand."
pub r: bool,
}

impl Sse {
fn validate(&self, operands: &[Operand]) {
todo!()
}

#[must_use]
pub fn prefix(self, prefixes: LegacyPrefixes) -> Self {
Self { prefixes, ..self }
}

#[must_use]
pub fn r(self) -> Self {
Self { r: true, ..self }
}

/*
pub fn emit(&self, buf: &mut Vec<u8>, operands: &[Operand]) {
match self.prefix {
LegacyPrefixes::NoPrefix => {}
LegacyPrefixes::_66 => buf.push(0x66),
_ => todo!(),
}
buf.push(0x0F);
buf.push((self.opcode & 0xFF) as u8);
}
*/
}

impl From<Sse> for Encoding {
fn from(sse: Sse) -> Encoding {
Encoding::Sse(sse)
}
}

impl fmt::Display for Sse {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self.prefixes {
LegacyPrefixes::NoPrefix => {}
LegacyPrefixes::_66 => write!(f, "0x66 + ")?,
_ => unimplemented!("only 0x66 is supported for SSE instructions"),
}
write!(f, "{:#04x}", self.opcode)?;
if self.r {
write!(f, " /r")?;
}
Ok(())
}
}

/*
pub trait HasLegacyPrefix {
fn get_legacy_prefix(&self) -> &LegacyPrefixes;
}
impl HasLegacyPrefix for Rex {
fn get_legacy_prefix(&self) -> &LegacyPrefixes {
&self.prefixes
}
}
impl HasLegacyPrefix for Sse {
fn get_legacy_prefix(&self) -> &LegacyPrefixes {
&self.prefixes
}
}
pub trait HasOpcode {
fn get_opcode(&self) -> u32;
}
impl HasOpcode for Rex {
fn get_opcode(&self) -> u32 {
self.opcode
}
}
impl HasOpcode for Sse {
fn get_opcode(&self) -> u32 {
self.opcode
}
}
pub trait HasModrmByte {
fn generate_modrm_byte(&self, f: &mut Formatter);
}
impl HasModrmByte for Rex {
fn generate_modrm_byte(&self, f: &mut Formatter) {
}
}
*/
4 changes: 3 additions & 1 deletion cranelift/assembler/meta/src/dsl/format.rs
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,8 @@ impl Location {
imm8 | imm16 | imm32 => OperandKind::Imm(*self),
r8 | r16 | r32 | r64 => OperandKind::Reg(*self),
xmm => OperandKind::XmmReg(*self),
rm8 | rm16 | rm32 | rm64 | rm128 => OperandKind::RegMem(*self),
rm8 | rm16 | rm32 | rm64 => OperandKind::RegMem(*self),
rm128 => OperandKind::XmmRegMem(*self),
}
}
}
Expand Down Expand Up @@ -232,6 +233,7 @@ pub enum OperandKind {
Reg(Location),
RegMem(Location),
XmmReg(Location),
XmmRegMem(Location),
}

#[derive(Clone, Copy, Debug)]
Expand Down
155 changes: 52 additions & 103 deletions cranelift/assembler/meta/src/generate/format.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
use super::{fmtln, Formatter};
use crate::dsl::{self, LegacyPrefixes, Rex, Sse};
//use crate::dsl::encoding::{HasLegacyPrefix, HasOpcode};
use crate::dsl;

impl dsl::Format {
#[must_use]
Expand All @@ -25,19 +24,12 @@ impl dsl::Format {
self.generate_immediate(f);
}

pub fn generate_sse_encoding(&self, f: &mut Formatter, sse: &dsl::Sse) {
self.generate_legacy_prefix(f, sse);
self.generate_opcode(f, sse);
//self.generate_modrm_byte(f, sse);
}

#[allow(clippy::unused_self)]
fn generate_legacy_prefix<T: HasLegacyPrefix>(&self, f: &mut Formatter, encoding: &T) {
let prefixes = encoding.get_legacy_prefix();
if *prefixes != dsl::LegacyPrefixes::NoPrefix {
fn generate_legacy_prefix(&self, f: &mut Formatter, rex: &dsl::Rex) {
if rex.prefixes != dsl::LegacyPrefixes::NoPrefix {
f.empty_line();
f.comment("Emit legacy prefixes.");
match prefixes {
match rex.prefixes {
dsl::LegacyPrefixes::NoPrefix => unreachable!(),
dsl::LegacyPrefixes::_66 => fmtln!(f, "buf.put1(0x66);"),
dsl::LegacyPrefixes::_F0 => fmtln!(f, "buf.put1(0xf0);"),
Expand All @@ -50,15 +42,20 @@ impl dsl::Format {
}

#[allow(clippy::unused_self)]
fn generate_opcode<T: HasOpcode>(&self, f: &mut Formatter, encoding: &T) {
fn generate_opcode(&self, f: &mut Formatter, rex: &dsl::Rex) {
f.empty_line();
f.comment("Emit opcode.");
//fmtln!(f, "buf.put1(0x{:x});", rex.opcode);
fmtln!(f, "buf.put1(0x{:x});", encoding.get_opcode());
// SSE instruction opcodes can be larger than 1 byte
if rex.opcode > 0xff {
fmtln!(f, "buf.put2(0x{:x});", rex.opcode);
}
else {
fmtln!(f, "buf.put1(0x{:x});", rex.opcode);
}
}

fn generate_rex_prefix(&self, f: &mut Formatter, rex: &dsl::Rex) {
use dsl::OperandKind::{FixedReg, Imm, Reg, RegMem};
use dsl::OperandKind::{FixedReg, Imm, Reg, RegMem, XmmReg, XmmRegMem};
f.empty_line();
f.comment("Emit REX prefix.");

Expand Down Expand Up @@ -120,24 +117,32 @@ impl dsl::Format {
});
fmtln!(f, "}}");
}
/*
[XmmReg(dst), RegMem(src)] => {
[XmmRegMem(dst), XmmReg(src)] => {
fmtln!(f, "let {src} = self.{src}.enc();");
fmtln!(f, "match &self.{dst} {{");
f.indent(|f| {
fmtln!(f, "XmmMem::Xmm({dst}) => rex.emit_two_op(buf, {src}, {dst}.enc()),");
fmtln!(f, "XmmMem::Mem({dst}) => {dst}.emit_rex_prefix(rex, {src}, buf),");
});
fmtln!(f, "}}");
}
[XmmReg(dst), XmmRegMem(src)] => {
fmtln!(f, "let {dst} = self.{dst}.enc();");
fmtln!(f, "match &self.{src} {{");
f.indent(|f| {
fmtln!(f, "GprMem::Gpr({src}) => rex.emit_two_op(buf, {dst}, {src}.enc()),");
fmtln!(f, "GprMem::Mem({src}) => {src}.emit_rex_prefix(rex, {dst}, buf),");
fmtln!(f, "XmmMem::Xmm({src}) => rex.emit_two_op(buf, {dst}, {src}.enc()),");
fmtln!(f, "XmmMem::Mem({src}) => {src}.emit_rex_prefix(rex, {dst}, buf),");
});
fmtln!(f, "}}");
}
*/


unknown => todo!("unknown pattern: {unknown:?}"),
}
}

fn generate_modrm_byte(&self, f: &mut Formatter, rex: &dsl::Rex) {
use dsl::OperandKind::{FixedReg, Imm, Reg, RegMem};
use dsl::OperandKind::{FixedReg, Imm, Reg, RegMem, XmmReg, XmmRegMem};

if let [FixedReg(_), Imm(_)] = self.operands_by_kind().as_slice() {
// No need to emit a comment.
Expand Down Expand Up @@ -187,6 +192,31 @@ impl dsl::Format {
});
fmtln!(f, "}}");
}
[XmmRegMem(dst), Reg(src)] => {
fmtln!(f, "let {src} = self.{src}.enc();");
fmtln!(f, "match &self.{dst} {{");
f.indent(|f| {
fmtln!(f, "XmmMem::Xmm({dst}) => emit_modrm(buf, {src}, {dst}.enc()),");
fmtln!(
f,
"XmmMem::Mem({dst}) => emit_modrm_sib_disp(buf, off, {src}, {dst}, 0, None),"
);
});
fmtln!(f, "}}");
}
// implement pattern: [XmmReg(xmm), RegMem(rm128)]
[XmmReg(dst), XmmRegMem(src)] => {
fmtln!(f, "let {dst} = self.{dst}.enc();");
fmtln!(f, "match &self.{src} {{");
f.indent(|f| {
fmtln!(f, "XmmMem::Xmm({src}) => emit_modrm(buf, {dst}, {src}.enc()),");
fmtln!(
f,
"XmmMem::Mem({src}) => emit_modrm_sib_disp(buf, off, {dst}, {src}, 0, None),"
);
});
fmtln!(f, "}}");
}

unknown => todo!("unknown pattern: {unknown:?}"),
}
Expand All @@ -213,84 +243,3 @@ impl dsl::Format {
}
}
}

pub trait HasLegacyPrefix {
fn get_legacy_prefix(&self) -> &LegacyPrefixes;
}

impl HasLegacyPrefix for Rex {
fn get_legacy_prefix(&self) -> &LegacyPrefixes {
&self.prefixes
}
}

impl HasLegacyPrefix for Sse {
fn get_legacy_prefix(&self) -> &LegacyPrefixes {
&self.prefixes
}
}

pub trait HasOpcode {
fn get_opcode(&self) -> u32;
}

impl HasOpcode for Rex {
fn get_opcode(&self) -> u32 {
self.opcode
}
}

impl HasOpcode for Sse {
fn get_opcode(&self) -> u32 {
self.opcode
}
}

pub trait HasModrmByte {
fn generate_modrm_byte(&self, f: &mut Formatter, operands: &[dsl::Operand]);
}

impl HasModrmByte for Rex {
fn generate_modrm_byte(&self, f: &mut Formatter, operands: &[dsl::Operand]) {
use dsl::OperandKind::{FixedReg, Imm, Reg, RegMem};

if let [dsl::Operand { kind: FixedReg(_), .. }, dsl::Operand { kind: Imm(_) }] = operands {
// No need to emit a comment.
} else {
f.empty_line();
f.comment("Emit ModR/M byte.");
}

match operands {
[FixedReg(_), Imm(_)] => {
// No need to emit a ModRM byte: we know the register used.
}
[RegMem(dst), Imm(_)] => {
debug_assert!(self.digit > 0);
fmtln!(f, "let digit = 0x{:x};", self.digit);
fmtln!(f, "match &self.{dst} {{");
f.indent(|f| {
fmtln!(f, "GprMem::Gpr({dst}) => emit_modrm(buf, digit, {dst}.enc()),");
fmtln!(
f,
"GprMem::Mem({dst}) => emit_modrm_sib_disp(buf, off, digit, {dst}, 0, None),"
);
});
fmtln!(f, "}}");
}
[Reg(dst), RegMem(src)] => {
fmtln!(f, "let {dst} = self.{dst}.enc();");
fmtln!(f, "match &self.{src} {{");
f.indent(|f| {
fmtln!(f, "GprMem::Gpr({src}) => emit_modrm(buf, {dst}, {src}.enc()),");
fmtln!(
f,
"GprMem::Mem({src}) => emit_modrm_sib_disp(buf, off, {dst}, {src}, 0, None),"
);
});
fmtln!(f, "}}");
}
_ => unimplemented!("Unsupported operand combination for ModR/M byte generation"),
}
}
}
Loading

0 comments on commit 6062bbf

Please sign in to comment.