Path: blob/main/cranelift/assembler-x64/meta/src/generate/format.rs
1693 views
//! Generate format-related Rust code; this also includes generation of encoding1//! Rust code.2use super::{Formatter, fmtln};3use crate::dsl;45/// Different methods of emitting a ModR/M operand and encoding various bits and6/// pieces of information into it. The REX/VEX formats plus the operand kinds7/// dictate how exactly each instruction uses this, if at all.8#[derive(Copy, Clone)]9enum ModRmStyle {10/// This instruction does not use a ModR/M byte.11None,1213/// The R/M bits are encoded with `rm` which is a `Gpr` or `Xmm` (it does14/// not have a "mem" possibility), and the Reg/Opcode bits are encoded15/// with `reg`.16Reg { reg: ModRmReg, rm: dsl::Location },1718/// The R/M bits are encoded with `rm` which is a `GprMem` or `XmmMem`, and19/// the Reg/Opcode bits are encoded with `reg`.20RegMem {21reg: ModRmReg,22rm: dsl::Location,23evex_scaling: Option<i8>,24},2526/// Same as `RegMem` above except that this is also used for VEX-encoded27/// instructios with "/is4" which indicates that the 4th register operand28/// is encoded in a byte after the ModR/M byte.29RegMemIs4 {30reg: ModRmReg,31rm: dsl::Location,32is4: dsl::Location,33evex_scaling: Option<i8>,34},35}3637/// Different methods of encoding the Reg/Opcode bits in a ModR/M byte.38#[derive(Copy, Clone)]39enum ModRmReg {40/// A static set of bits is used.41Digit(u8),42/// A runtime-defined register is used with this field name.43Reg(dsl::Location),44}4546impl dsl::Format {47/// Re-order the Intel-style operand order to accommodate ATT-style48/// printing.49///50/// This is an unfortunate necessity to match Cranelift's current51/// disassembly, which uses AT&T-style printing. The plan is to eventually52/// transition to Intel-style printing (and avoid this awkward reordering)53/// once Cranelift has switched to using this assembler predominantly54/// (TODO).55#[must_use]56pub(crate) fn generate_att_style_operands(&self) -> String {57let ordered_ops: Vec<_> = self58.operands59.iter()60.filter(|o| !o.implicit)61.rev()62.map(|o| format!("{{{}}}", o.location))63.collect();64ordered_ops.join(", ")65}6667#[must_use]68pub(crate) fn generate_implicit_operands(&self) -> String {69let ops: Vec<_> = self70.operands71.iter()72.filter(|o| o.implicit)73.map(|o| format!("{{{}}}", o.location))74.collect();75if ops.is_empty() {76String::new()77} else {78format!(" ;; implicit: {}", ops.join(", "))79}80}8182pub(crate) fn generate_rex_encoding(&self, f: &mut Formatter, rex: &dsl::Rex) {83self.generate_prefixes(f, rex);84let style = self.generate_rex_prefix(f, rex);85rex.generate_opcodes(f, self.locations().next());86self.generate_modrm_byte(f, style);87self.generate_immediate(f, style);88}8990pub fn generate_vex_encoding(&self, f: &mut Formatter, vex: &dsl::Vex) {91let style = self.generate_vex_prefix(f, vex);92vex.generate_opcode(f);93self.generate_modrm_byte(f, style);94self.generate_immediate(f, style);95}9697pub fn generate_evex_encoding(&self, f: &mut Formatter, evex: &dsl::Evex) {98let style = self.generate_evex_prefix(f, evex);99evex.generate_opcode(f);100self.generate_modrm_byte(f, style);101self.generate_immediate(f, style);102}103104/// `buf.put1(...);`105fn generate_prefixes(&self, f: &mut Formatter, rex: &dsl::Rex) {106if !rex.opcodes.prefixes.is_empty() {107f.empty_line();108f.comment("Emit prefixes.");109}110if let Some(group1) = &rex.opcodes.prefixes.group1 {111fmtln!(f, "buf.put1({group1});");112}113if let Some(group2) = &rex.opcodes.prefixes.group2 {114fmtln!(f, "buf.put1({group2});");115}116if let Some(group3) = &rex.opcodes.prefixes.group3 {117fmtln!(f, "buf.put1({group3});");118}119if let Some(group4) = &rex.opcodes.prefixes.group4 {120fmtln!(f, "buf.put1({group4});");121}122}123124fn generate_rex_prefix(&self, f: &mut Formatter, rex: &dsl::Rex) -> ModRmStyle {125use dsl::OperandKind::{FixedReg, Imm, Mem, Reg, RegMem};126127// If this instruction has only immediates there's no rex/modrm/etc, so128// skip everything below.129match self.operands_by_kind().as_slice() {130[] | [Imm(_)] => return ModRmStyle::None,131_ => {}132}133134f.empty_line();135f.comment("Possibly emit REX prefix.");136137let find_8bit_registers =138|l: &dsl::Location| l.bits() == 8 && matches!(l.kind(), Reg(_) | RegMem(_));139let uses_8bit = self.locations().any(find_8bit_registers);140fmtln!(f, "let uses_8bit = {uses_8bit};");141fmtln!(f, "let w_bit = {};", rex.w.as_bool());142let bits = "w_bit, uses_8bit";143144let style = match self.operands_by_kind().as_slice() {145[FixedReg(dst), FixedReg(_)] | [FixedReg(dst)] | [FixedReg(dst), Imm(_)] => {146// TODO: don't emit REX byte here.147assert_eq!(rex.unwrap_digit(), None);148fmtln!(f, "let digit = 0;");149fmtln!(f, "let dst = self.{dst}.enc();");150fmtln!(f, "let rex = RexPrefix::with_digit(digit, dst, {bits});");151ModRmStyle::None152}153[Reg(dst)] => {154assert_eq!(rex.unwrap_digit(), None);155assert!(rex.opcode_mod.is_some());156fmtln!(f, "let dst = self.{dst}.enc();");157fmtln!(f, "let rex = RexPrefix::one_op(dst, {bits});");158ModRmStyle::None159}160[Reg(dst), Imm(_)] => match rex.unwrap_digit() {161Some(digit) => {162fmtln!(f, "let digit = 0x{digit:x};");163fmtln!(f, "let dst = self.{dst}.enc();");164fmtln!(f, "let rex = RexPrefix::two_op(digit, dst, {bits});");165ModRmStyle::Reg {166reg: ModRmReg::Digit(digit),167rm: *dst,168}169}170None => {171assert!(rex.opcode_mod.is_some());172fmtln!(f, "let dst = self.{dst}.enc();");173fmtln!(f, "let rex = RexPrefix::one_op(dst, {bits});");174ModRmStyle::None175}176},177[FixedReg(_), RegMem(mem)]178| [FixedReg(_), FixedReg(_), RegMem(mem)]179| [RegMem(mem), FixedReg(_)]180| [Mem(mem), Imm(_)]181| [RegMem(mem), Imm(_)]182| [RegMem(mem)]183| [FixedReg(_), FixedReg(_), FixedReg(_), FixedReg(_), Mem(mem)] => {184let digit = rex.unwrap_digit().unwrap();185fmtln!(f, "let digit = 0x{digit:x};");186fmtln!(f, "let rex = self.{mem}.as_rex_prefix(digit, {bits});");187ModRmStyle::RegMem {188reg: ModRmReg::Digit(digit),189rm: *mem,190evex_scaling: None,191}192}193[Reg(reg), RegMem(mem) | Mem(mem)]194| [Reg(reg), RegMem(mem), Imm(_) | FixedReg(_)]195| [RegMem(mem) | Mem(mem), Reg(reg)]196| [RegMem(mem) | Mem(mem), Reg(reg), Imm(_) | FixedReg(_)] => {197fmtln!(f, "let reg = self.{reg}.enc();");198fmtln!(f, "let rex = self.{mem}.as_rex_prefix(reg, {bits});");199ModRmStyle::RegMem {200reg: ModRmReg::Reg(*reg),201rm: *mem,202evex_scaling: None,203}204}205[Reg(dst), Reg(src), Imm(_)] | [Reg(dst), Reg(src)] => {206fmtln!(f, "let reg = self.{dst}.enc();");207fmtln!(f, "let rm = self.{src}.enc();");208fmtln!(f, "let rex = RexPrefix::two_op(reg, rm, {bits});");209ModRmStyle::Reg {210reg: ModRmReg::Reg(*dst),211rm: *src,212}213}214215unknown => unimplemented!("unknown pattern: {unknown:?}"),216};217218fmtln!(f, "rex.encode(buf);");219style220}221222fn generate_vex_prefix(&self, f: &mut Formatter, vex: &dsl::Vex) -> ModRmStyle {223f.empty_line();224f.comment("Emit VEX prefix.");225fmtln!(f, "let len = {:#03b};", vex.length.vex_bits());226fmtln!(f, "let pp = {:#04b};", vex.pp.map_or(0b00, |pp| pp.bits()));227fmtln!(f, "let mmmmm = {:#07b};", vex.mmmmm.unwrap().bits());228fmtln!(f, "let w = {};", vex.w.as_bool());229let bits = "len, pp, mmmmm, w";230231self.generate_vex_or_evex_prefix(f, "VexPrefix", &bits, vex.is4, None, || {232vex.unwrap_digit()233})234}235236fn generate_evex_prefix(&self, f: &mut Formatter, evex: &dsl::Evex) -> ModRmStyle {237f.empty_line();238f.comment("Emit EVEX prefix.");239let ll = evex.length.evex_bits();240fmtln!(f, "let ll = {ll:#04b};");241fmtln!(f, "let pp = {:#04b};", evex.pp.map_or(0b00, |pp| pp.bits()));242fmtln!(f, "let mmm = {:#07b};", evex.mmm.unwrap().bits());243fmtln!(f, "let w = {};", evex.w.as_bool());244// NB: when bcast is supported in the future the `evex_scaling`245// calculation for `Full` and `Half` below need to be updated.246let bcast = false;247fmtln!(f, "let bcast = {bcast};");248let bits = format!("ll, pp, mmm, w, bcast");249let is4 = false;250251let length_bytes = match evex.length {252dsl::Length::LZ | dsl::Length::LIG => unimplemented!(),253dsl::Length::L128 => 16,254dsl::Length::L256 => 32,255dsl::Length::L512 => 64,256};257258// Figure out, according to table 2-34 and 2-35 in the Intel manual,259// what the scaling factor is for 8-bit displacements to pass through to260// encoding.261let evex_scaling = Some(match evex.tuple_type {262dsl::TupleType::Full => {263assert!(!bcast);264length_bytes265}266dsl::TupleType::Half => {267assert!(!bcast);268length_bytes / 2269}270dsl::TupleType::FullMem => length_bytes,271// FIXME: according to table 2-35 this needs to take into account272// "InputSize" which isn't accounted for in our `Evex` structure at273// this time.274dsl::TupleType::Tuple1Scalar => unimplemented!(),275dsl::TupleType::Tuple1Fixed => unimplemented!(),276dsl::TupleType::Tuple2 => unimplemented!(),277dsl::TupleType::Tuple4 => unimplemented!(),278dsl::TupleType::Tuple8 => 32,279dsl::TupleType::HalfMem => length_bytes / 2,280dsl::TupleType::QuarterMem => length_bytes / 4,281dsl::TupleType::EigthMem => length_bytes / 8,282dsl::TupleType::Mem128 => 16,283dsl::TupleType::Movddup => match evex.length {284dsl::Length::LZ | dsl::Length::LIG => unimplemented!(),285dsl::Length::L128 => 8,286dsl::Length::L256 => 32,287dsl::Length::L512 => 64,288},289});290291self.generate_vex_or_evex_prefix(f, "EvexPrefix", &bits, is4, evex_scaling, || {292evex.unwrap_digit()293})294}295296/// Helper function to generate either a vex or evex prefix, mostly handling297/// all the operand formats and structures here the same between the two298/// forms.299fn generate_vex_or_evex_prefix(300&self,301f: &mut Formatter,302prefix_type: &str,303bits: &str,304is4: bool,305evex_scaling: Option<i8>,306unwrap_digit: impl Fn() -> Option<u8>,307) -> ModRmStyle {308use dsl::OperandKind::{FixedReg, Imm, Mem, Reg, RegMem};309310let style = match self.operands_by_kind().as_slice() {311[Reg(reg), Reg(vvvv), Reg(rm)] => {312assert!(!is4);313fmtln!(f, "let reg = self.{reg}.enc();");314fmtln!(f, "let vvvv = self.{vvvv}.enc();");315fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");316fmtln!(317f,318"let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"319);320ModRmStyle::Reg {321reg: ModRmReg::Reg(*reg),322rm: *rm,323}324}325[Reg(reg), Reg(vvvv), RegMem(rm)]326| [Reg(reg), Reg(vvvv), Mem(rm)]327| [Reg(reg), Reg(vvvv), RegMem(rm), Imm(_) | FixedReg(_)]328| [Reg(reg), RegMem(rm), Reg(vvvv)] => {329assert!(!is4);330fmtln!(f, "let reg = self.{reg}.enc();");331fmtln!(f, "let vvvv = self.{vvvv}.enc();");332fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");333fmtln!(334f,335"let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"336);337ModRmStyle::RegMem {338reg: ModRmReg::Reg(*reg),339rm: *rm,340evex_scaling,341}342}343[Reg(reg), Reg(vvvv), RegMem(rm), Reg(r_is4)] => {344assert!(is4);345fmtln!(f, "let reg = self.{reg}.enc();");346fmtln!(f, "let vvvv = self.{vvvv}.enc();");347fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");348fmtln!(349f,350"let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"351);352ModRmStyle::RegMemIs4 {353reg: ModRmReg::Reg(*reg),354rm: *rm,355is4: *r_is4,356evex_scaling,357}358}359[Reg(reg_or_vvvv), RegMem(rm)]360| [RegMem(rm), Reg(reg_or_vvvv)]361| [Reg(reg_or_vvvv), RegMem(rm), Imm(_)] => match unwrap_digit() {362Some(digit) => {363assert!(!is4);364let vvvv = reg_or_vvvv;365fmtln!(f, "let reg = {digit:#x};");366fmtln!(f, "let vvvv = self.{vvvv}.enc();");367fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");368fmtln!(369f,370"let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"371);372ModRmStyle::RegMem {373reg: ModRmReg::Digit(digit),374rm: *rm,375evex_scaling,376}377}378None => {379assert!(!is4);380let reg = reg_or_vvvv;381fmtln!(f, "let reg = self.{reg}.enc();");382fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");383fmtln!(f, "let prefix = {prefix_type}::two_op(reg, rm, {bits});");384ModRmStyle::RegMem {385reg: ModRmReg::Reg(*reg),386rm: *rm,387evex_scaling,388}389}390},391[Reg(reg_or_vvvv), Reg(rm)] | [Reg(reg_or_vvvv), Reg(rm), Imm(_)] => {392match unwrap_digit() {393Some(digit) => {394assert!(!is4);395let vvvv = reg_or_vvvv;396fmtln!(f, "let reg = {digit:#x};");397fmtln!(f, "let vvvv = self.{vvvv}.enc();");398fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");399fmtln!(400f,401"let prefix = {prefix_type}::three_op(reg, vvvv, rm, {bits});"402);403ModRmStyle::Reg {404reg: ModRmReg::Digit(digit),405rm: *rm,406}407}408None => {409assert!(!is4);410let reg = reg_or_vvvv;411fmtln!(f, "let reg = self.{reg}.enc();");412fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");413fmtln!(f, "let prefix = {prefix_type}::two_op(reg, rm, {bits});");414ModRmStyle::Reg {415reg: ModRmReg::Reg(*reg),416rm: *rm,417}418}419}420}421[Reg(reg), Mem(rm)] | [Mem(rm), Reg(reg)] | [RegMem(rm), Reg(reg), Imm(_)] => {422assert!(!is4);423fmtln!(f, "let reg = self.{reg}.enc();");424fmtln!(f, "let rm = self.{rm}.encode_bx_regs();");425fmtln!(f, "let prefix = {prefix_type}::two_op(reg, rm, {bits});");426ModRmStyle::RegMem {427reg: ModRmReg::Reg(*reg),428rm: *rm,429evex_scaling,430}431}432unknown => unimplemented!("unknown pattern: {unknown:?}"),433};434435fmtln!(f, "prefix.encode(buf);");436style437}438439fn generate_modrm_byte(&self, f: &mut Formatter, modrm_style: ModRmStyle) {440let operands = self.operands_by_kind();441let bytes_at_end = match operands.as_slice() {442[.., dsl::OperandKind::Imm(imm)] => imm.bytes(),443_ => match modrm_style {444ModRmStyle::RegMemIs4 { .. } => 1,445_ => 0,446},447};448449f.empty_line();450451match modrm_style {452ModRmStyle::None => f.comment("No need to emit a ModRM byte."),453_ => f.comment("Emit ModR/M byte."),454}455456match modrm_style {457ModRmStyle::None => {}458ModRmStyle::RegMem {459reg,460rm,461evex_scaling,462}463| ModRmStyle::RegMemIs4 {464reg,465rm,466is4: _,467evex_scaling,468} => {469match reg {470ModRmReg::Reg(reg) => fmtln!(f, "let reg = self.{reg}.enc();"),471ModRmReg::Digit(digit) => fmtln!(f, "let reg = {digit:#x};"),472}473fmtln!(474f,475"self.{rm}.encode_rex_suffixes(buf, reg, {bytes_at_end}, {evex_scaling:?});"476);477}478ModRmStyle::Reg { reg, rm } => {479match reg {480ModRmReg::Reg(reg) => fmtln!(f, "let reg = self.{reg}.enc();"),481ModRmReg::Digit(digit) => fmtln!(f, "let reg = {digit:#x};"),482}483fmtln!(f, "self.{rm}.encode_modrm(buf, reg);");484}485}486}487488fn generate_immediate(&self, f: &mut Formatter, modrm_style: ModRmStyle) {489use dsl::OperandKind::Imm;490match self.operands_by_kind().as_slice() {491[prefix @ .., Imm(imm)] => {492assert!(!prefix.iter().any(|o| matches!(o, Imm(_))));493f.empty_line();494f.comment("Emit immediate.");495fmtln!(f, "self.{imm}.encode(buf);");496}497unknown => {498if let ModRmStyle::RegMemIs4 { is4, .. } = modrm_style {499fmtln!(f, "buf.put1(self.{is4}.enc() << 4);");500}501502// Do nothing: no immediates expected.503assert!(!unknown.iter().any(|o| matches!(o, Imm(_))));504}505}506}507}508509impl dsl::Rex {510// `buf.put1(...);`511fn generate_opcodes(&self, f: &mut Formatter, first_op: Option<&dsl::Location>) {512f.empty_line();513f.comment("Emit opcode(s).");514if self.opcodes.escape {515fmtln!(f, "buf.put1(0x0f);");516}517if self.opcode_mod.is_some() {518let first_op = first_op.expect("Expected first operand for opcode_mod");519assert!(matches!(first_op.kind(), dsl::OperandKind::Reg(_)));520fmtln!(f, "let low_bits = self.{first_op}.enc() & 0b111;");521fmtln!(f, "buf.put1(0x{:x} | low_bits);", self.opcodes.primary);522} else {523fmtln!(f, "buf.put1(0x{:x});", self.opcodes.primary);524}525if let Some(secondary) = self.opcodes.secondary {526fmtln!(f, "buf.put1(0x{:x});", secondary);527}528}529}530531impl dsl::Vex {532// `buf.put1(...);`533fn generate_opcode(&self, f: &mut Formatter) {534f.empty_line();535f.comment("Emit opcode.");536fmtln!(f, "buf.put1(0x{:x});", self.opcode);537}538}539540impl dsl::Evex {541// `buf.put1(...);`542fn generate_opcode(&self, f: &mut Formatter) {543f.empty_line();544f.comment("Emit opcode.");545fmtln!(f, "buf.put1(0x{:x});", self.opcode);546}547}548549550