Path: blob/main/cranelift/assembler-x64/meta/src/generate/inst.rs
1693 views
use super::{Formatter, fmtln, generate_derive, generate_derive_arbitrary_bounds};1use crate::dsl;23impl dsl::Inst {4/// `struct <inst> { <op>: Reg, <op>: Reg, ... }`5pub fn generate_struct(&self, f: &mut Formatter) {6let struct_name = self.struct_name_with_generic();7let where_clause = if self.requires_generic() {8"where R: Registers"9} else {10""11};1213fmtln!(f, "/// `{self}`");14generate_derive(f);15if self.requires_generic() {16generate_derive_arbitrary_bounds(f);17}18f.add_block(&format!("pub struct {struct_name} {where_clause}"), |f| {19for k in &self.format.operands {20let loc = k.location;21let ty = k.generate_type();22fmtln!(f, "pub {loc}: {ty},");23}2425if self.has_trap {26fmtln!(f, "pub trap: TrapCode,");27}28});29}3031fn requires_generic(&self) -> bool {32self.format.uses_register()33}3435/// `<struct_name><R>`36pub(crate) fn struct_name_with_generic(&self) -> String {37let struct_name = self.name();38if self.requires_generic() {39format!("{struct_name}<R>")40} else {41struct_name42}43}4445/// `impl...`46fn generate_impl_block_start(&self) -> &str {47if self.requires_generic() {48"impl<R: Registers>"49} else {50"impl"51}52}5354/// `impl <inst> { ... }`55pub fn generate_struct_impl(&self, f: &mut Formatter) {56let impl_block = self.generate_impl_block_start();57let struct_name = self.struct_name_with_generic();58f.add_block(&format!("{impl_block} {struct_name}"), |f| {59self.generate_new_function(f);60f.empty_line();61self.generate_mnemonic_function(f);62f.empty_line();63self.generate_encode_function(f);64f.empty_line();65self.generate_visit_function(f);66f.empty_line();67self.generate_is_available_function(f);68f.empty_line();69self.generate_features_function(f);70});71}7273// `fn new(<params>) -> Self { ... }`74pub fn generate_new_function(&self, f: &mut Formatter) {75let params = comma_join(76self.format77.operands78.iter()79.map(|o| format!("{}: impl Into<{}>", o.location, o.generate_type()))80.chain(if self.has_trap {81Some("trap: impl Into<TrapCode>".to_string())82} else {83None84}),85);86fmtln!(f, "#[must_use]");87f.add_block(&format!("pub fn new({params}) -> Self"), |f| {88f.add_block("Self", |f| {89for o in &self.format.operands {90let loc = o.location;91fmtln!(f, "{loc}: {loc}.into(),");92}93if self.has_trap {94fmtln!(f, "trap: trap.into(),");95}96});97});98}99100/// `fn mnemonic(&self) -> &'static str { ... }`101pub fn generate_mnemonic_function(&self, f: &mut Formatter) {102use dsl::Customization::*;103104fmtln!(f, "#[must_use]");105fmtln!(f, "#[inline]");106f.add_block(107&format!("pub fn mnemonic(&self) -> std::borrow::Cow<'static, str>"),108|f| {109if self.custom.contains(Mnemonic) {110fmtln!(f, "crate::custom::mnemonic::{}(self)", self.name());111} else {112fmtln!(f, "std::borrow::Cow::Borrowed(\"{}\")", self.mnemonic);113}114},115);116}117118/// `fn encode(&self, ...) { ... }`119fn generate_encode_function(&self, f: &mut Formatter) {120use dsl::Customization::*;121122f.add_block(123&format!("pub fn encode(&self, buf: &mut impl CodeSink)"),124|f| {125if self.custom.contains(Encode) {126fmtln!(f, "crate::custom::encode::{}(self, buf);", self.name());127} else {128self.generate_possible_trap(f);129match &self.encoding {130dsl::Encoding::Rex(rex) => self.format.generate_rex_encoding(f, rex),131dsl::Encoding::Vex(vex) => self.format.generate_vex_encoding(f, vex),132dsl::Encoding::Evex(evex) => self.format.generate_evex_encoding(f, evex),133}134}135},136);137}138139// `buf.add_trap(...)`140fn generate_possible_trap(&self, f: &mut Formatter) {141if self.has_trap {142f.comment("Emit trap.");143fmtln!(f, "buf.add_trap(self.trap);");144} else if let Some(op) = self.format.uses_memory() {145use dsl::OperandKind::*;146f.comment("Emit trap.");147match op.kind() {148Mem(_) => {149f.add_block(150&format!("if let Some(trap_code) = self.{op}.trap_code()"),151|f| {152fmtln!(f, "buf.add_trap(trap_code);");153},154);155}156RegMem(_) => {157let ty = op.reg_class().unwrap();158f.add_block(&format!("if let {ty}Mem::Mem({op}) = &self.{op}"), |f| {159f.add_block(&format!("if let Some(trap_code) = {op}.trap_code()"), |f| {160fmtln!(f, "buf.add_trap(trap_code);");161});162});163}164_ => unreachable!(),165}166}167}168169/// `fn visit(&self, ...) { ... }`170fn generate_visit_function(&self, f: &mut Formatter) {171use dsl::{Customization::*, OperandKind::*};172let extra_generic_bound = if self.requires_generic() {173""174} else {175"<R: Registers>"176};177let visitor = if self.format.operands.is_empty() && !self.custom.contains(Visit) {178"_"179} else {180"visitor"181};182f.add_block(&format!("pub fn visit{extra_generic_bound}(&mut self, {visitor}: &mut impl RegisterVisitor<R>)"), |f| {183if self.custom.contains(Visit) {184fmtln!(f, "crate::custom::visit::{}(self, visitor)", self.name());185return;186}187for o in &self.format.operands {188let mutability = o.mutability.generate_snake_case();189let reg = o.location.reg_class();190match o.location.kind() {191Imm(_) => {192// Immediates do not need register allocation.193//194// If an instruction happens to only have immediates195// then generate a dummy use of the `visitor` variable196// to suppress unused variables warnings.197fmtln!(f, "let _ = visitor;");198}199FixedReg(loc) => {200let reg_lower = reg.unwrap().to_string().to_lowercase();201fmtln!(f, "let enc = self.{loc}.expected_enc();");202fmtln!(f, "visitor.fixed_{mutability}_{reg_lower}(&mut self.{loc}.0, enc);");203}204Reg(loc) => {205let reg_lower = reg.unwrap().to_string().to_lowercase();206fmtln!(f, "visitor.{mutability}_{reg_lower}(self.{loc}.as_mut());");207}208RegMem(loc) => {209let reg = reg.unwrap();210let reg_lower = reg.to_string().to_lowercase();211fmtln!(f, "visitor.{mutability}_{reg_lower}_mem(&mut self.{loc});");212}213Mem(loc) => {214// Note that this is always "read" because from a215// regalloc perspective when using an amode it means216// that the while a write is happening that's to217// memory, not registers.218fmtln!(f, "visitor.read_amode(&mut self.{loc});");219}220221}222}223});224}225226/// `fn is_available(&self, ...) -> bool { ... }`227fn generate_is_available_function(&self, f: &mut Formatter) {228fmtln!(f, "#[must_use]");229f.add_block(230"pub fn is_available(&self, features: &impl AvailableFeatures) -> bool",231|f| {232let expr = self.features.generate_boolean_expr("features");233fmtln!(f, "{expr}");234},235);236}237238/// `fn features(&self) -> Features { ... }`239fn generate_features_function(&self, f: &mut Formatter) {240fmtln!(f, "#[must_use]");241f.add_block("pub fn features(&self) -> &'static Features", |f| {242self.features.generate_constructor_expr(f);243});244}245246/// `impl Display for <inst> { ... }`247pub fn generate_display_impl(&self, f: &mut Formatter) {248use crate::dsl::Customization::*;249let impl_block = self.generate_impl_block_start();250let struct_name = self.struct_name_with_generic();251f.add_block(252&format!("{impl_block} std::fmt::Display for {struct_name}"),253|f| {254f.add_block(255"fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result",256|f| {257if self.custom.contains(Display) {258fmtln!(f, "crate::custom::display::{}(f, self)", self.name());259return;260}261262fmtln!(f, "let name = self.mnemonic();");263if self.format.operands.is_empty() {264fmtln!(f, "f.write_str(&name)");265return;266}267for op in self.format.operands.iter() {268let location = op.location;269let to_string = location.generate_to_string(op.extension);270fmtln!(f, "let {location} = {to_string};");271}272let ordered_ops = self.format.generate_att_style_operands();273let mut implicit_ops = self.format.generate_implicit_operands();274if self.has_trap {275fmtln!(f, "let trap = self.trap;");276if implicit_ops.is_empty() {277implicit_ops.push_str(" ;; {trap}");278} else {279implicit_ops.push_str(", {trap}");280}281}282fmtln!(f, "write!(f, \"{{name}} {ordered_ops}{implicit_ops}\")");283},284);285},286);287}288289/// `impl From<struct> for Inst { ... }`290pub fn generate_from_impl(&self, f: &mut Formatter) {291let struct_name_r = self.struct_name_with_generic();292let variant_name = self.name();293f.add_block(294&format!("impl<R: Registers> From<{struct_name_r}> for Inst<R>"),295|f| {296f.add_block(&format!("fn from(inst: {struct_name_r}) -> Self"), |f| {297fmtln!(f, "Self::{variant_name}(inst)");298});299},300);301}302}303304fn comma_join<S: Into<String>>(items: impl Iterator<Item = S>) -> String {305items.map(Into::into).collect::<Vec<_>>().join(", ")306}307308309