From 5833e812368b6a5829062f658de2881e4af70b15 Mon Sep 17 00:00:00 2001 From: Richard Patel Date: Sun, 29 Aug 2021 04:25:39 +0200 Subject: [PATCH] generate def/use information --- disasm/src/lib.rs | 13 +++ disasm/tests/test_disasm.rs | 33 +++++++- macros/src/isa.rs | 157 +++++++++++++++++++++++++++++++----- macros/src/isa.yaml | 32 ++------ 4 files changed, 186 insertions(+), 49 deletions(-) diff --git a/disasm/src/lib.rs b/disasm/src/lib.rs index ac3cc62..70c1285 100644 --- a/disasm/src/lib.rs +++ b/disasm/src/lib.rs @@ -5,6 +5,9 @@ pub mod prelude { pub use crate::Field::*; pub use crate::Ins; pub use crate::Opcode::*; + pub use crate::{ + Bit, BranchDest, CRBit, CRField, Offset, OpaqueU, Simm, Uimm, FPR, GPR, GQR, SPR, SR, + }; } use ppc750cl_macros::{fields, ins_impl, opcodes}; @@ -89,6 +92,16 @@ impl Ins { pub fn fields(&self) -> Vec { self._fields() // auto-generated } + + /// Gets the defs of an instruction. + pub fn defs(&self) -> Vec { + self._defs() // auto-generated + } + + /// Gets the uses of an instruction. + pub fn uses(&self) -> Vec { + self._uses() // auto-generated + } } ins_impl!(); diff --git a/disasm/tests/test_disasm.rs b/disasm/tests/test_disasm.rs index c628186..27fb080 100644 --- a/disasm/tests/test_disasm.rs +++ b/disasm/tests/test_disasm.rs @@ -1,13 +1,42 @@ use ppc750cl::prelude::*; -use ppc750cl::GPR; #[test] -fn test_ins_addi() { +fn test_ins_addc() { let ins = Ins::new(0x7c002014, 0x8000_0000u32); assert_eq!(ins.op, Addc); assert_eq!(ins.fields(), vec![rD(GPR(0)), rA(GPR(0)), rB(GPR(4))]); } +#[test] +fn test_ins_addi() { + let ins = Ins::new(0x38010140, 0x8000_0000u32); + assert_eq!(ins.op, Addi); + assert_eq!( + ins.fields(), + vec![rD(GPR(0)), rA(GPR(1)), simm(Simm(0x140))] + ); + assert_eq!(ins.defs(), vec![rD(GPR(0))]); + assert_eq!(ins.uses(), vec![rA(GPR(1))]); +} + +#[test] +fn test_ins_psq_lx() { + let ins = Ins::new(0x1000000C, 0x8000_0000u32); + assert_eq!(ins.op, PsqLx); + assert_eq!( + ins.fields(), + vec![ + frD(FPR(0)), + rA(GPR(0)), + rB(GPR(0)), + ps_W(OpaqueU(0)), + ps_l(GQR(0)) + ] + ); + assert_eq!(ins.defs(), vec![frD(FPR(0))]); + assert_eq!(ins.uses(), vec![rB(GPR(0))]); +} + /* macro_rules! assert_asm { ($code:expr, $disasm:expr) => {{ diff --git a/macros/src/isa.rs b/macros/src/isa.rs index 338bb62..694614f 100644 --- a/macros/src/isa.rs +++ b/macros/src/isa.rs @@ -36,12 +36,16 @@ pub(crate) struct Field { bits: BitRange, signed: bool, split: bool, - arg: String, + arg: Option, } impl Field { - fn variant_identifier(&self) -> TokenTree { - to_rust_ident(&self.name) + fn variant_identifier(&self) -> Option { + if self.name.strip_suffix(".nz").is_none() { + Some(to_rust_ident(&self.name)) + } else { + return None; + } } fn express_value(&self, code: TokenStream) -> TokenStream { @@ -51,6 +55,47 @@ impl Field { (((#code) >> (32 - #mask_stop)) & ((1 << #mask_size) - 1)) } } + + fn express_value_self(&self) -> TokenStream { + self.express_value(quote!(self.code)) + } + + fn enum_variant_definition(&self) -> Option { + let ident = if let Some(ident) = self.variant_identifier() { + ident + } else { + return None; + }; + Some(if let Some(arg) = &self.arg { + let arg = TokenTree::Ident(Ident::new(arg, Span::call_site())); + quote! { + #ident(#arg), + } + } else { + quote! { + #ident, + } + }) + } + + fn construct_variant(&self, code: TokenStream) -> TokenStream { + let field_variant = self.variant_identifier(); + if let Some(arg) = &self.arg { + let field_arg = TokenTree::Ident(Ident::new(arg, Span::call_site())); + let value = self.express_value(code); + quote! { + Field::#field_variant(#field_arg(#value as _)) + } + } else { + quote! { + Field::#field_variant + } + } + } + + fn construct_variant_self(&self) -> TokenStream { + self.construct_variant(quote!(self.code)) + } } #[derive(Deserialize, Default)] @@ -200,14 +245,13 @@ impl Isa { pub(crate) fn gen_field_enum(&self) -> syn::Result { // Create enum variants. - let enum_variants = self.fields.iter().map(|field| { - let ident = field.variant_identifier(); - let arg = TokenTree::Ident(Ident::new(&field.arg, Span::call_site())); - quote! { - #ident(#arg), + let mut enum_variants = Vec::new(); + for field in &self.fields { + if let Some(field) = field.enum_variant_definition() { + enum_variants.push(field); } - }); - let enum_variants = TokenStream::from_iter(enum_variants); + } + let enum_variants = TokenStream::from_iter(enum_variants.into_iter()); // Create final enum. let field_enum = quote! { @@ -226,7 +270,9 @@ impl Isa { field_by_name.insert(field.name.clone(), field); } // Generate match arms for each opcode. - let mut match_arms = Vec::new(); + let mut field_match_arms = Vec::new(); + let mut def_match_arms = Vec::new(); + let mut use_match_arms = Vec::new(); for opcode in &self.opcodes { // Generate fields of opcode. // TODO Support mnemonics. @@ -235,28 +281,95 @@ impl Isa { let field: &Field = field_by_name.get(arg).ok_or_else(|| { syn::Error::new(Span::call_site(), format!("undefined field {}", arg)) })?; - let field_variant = field.variant_identifier(); - let field_arg = TokenTree::Ident(Ident::new(&field.arg, Span::call_site())); - let value = field.express_value(quote!(self.code)); - fields.extend(quote! { - Field::#field_variant(#field_arg(#value as _)), - }) + let variant = field.construct_variant_self(); + fields.extend(quote! { #variant, }) } let fields = TokenStream::from_iter(fields.into_iter()); // Emit match arm. let ident = opcode.variant_identifier()?; - match_arms.push(quote! { - #ident => vec![#fields], - }) + field_match_arms.push(quote! { + Opcode::#ident => vec![#fields], + }); + + let mut defs = Vec::new(); + for arg in &opcode.defs { + let field: &Field = field_by_name.get(arg).ok_or_else(|| { + syn::Error::new(Span::call_site(), format!("undefined field {}", arg)) + })?; + let variant = field.construct_variant_self(); + defs.extend(quote! { #variant, }) + } + let defs = TokenStream::from_iter(defs.into_iter()); + let ident = opcode.variant_identifier()?; + def_match_arms.push(quote! { + Opcode::#ident => vec![#defs], + }); + + let mut uses = Vec::new(); + let mut special_uses = Vec::new(); + for arg in &opcode.uses { + // Detect non-zero modifier. + let mut arg = arg.as_str(); + let mut non_zero = false; + if let Some(substr) = arg.strip_suffix(".nz") { + non_zero = true; + arg = substr; + } + // Get underlying field. + let field: &Field = field_by_name.get(arg).ok_or_else(|| { + syn::Error::new(Span::call_site(), format!("undefined field {}", arg)) + })?; + let variant = field.construct_variant_self(); + if non_zero { + let value = field.express_value_self(); + special_uses.extend(quote! { + if (#value) != 0 { + uses.push(#variant); + } + }) + } else { + uses.extend(quote! { + #variant, + }) + } + } + let uses = TokenStream::from_iter(uses.into_iter()); + let ident = opcode.variant_identifier()?; + let special_uses = TokenStream::from_iter(special_uses.into_iter()); + use_match_arms.push(quote! { + Opcode::#ident => { + let mut uses = vec![#uses]; + #special_uses + uses + }, + }); } - let match_arms = TokenStream::from_iter(match_arms.into_iter()); + let field_match_arms = TokenStream::from_iter(field_match_arms.into_iter()); + let def_match_arms = TokenStream::from_iter(def_match_arms.into_iter()); + let use_match_arms = TokenStream::from_iter(use_match_arms.into_iter()); // Generate final fields function. let ins_impl = quote! { impl Ins { fn _fields(&self) -> Vec { match self.op { Opcode::Illegal => vec![], - #match_arms + #field_match_arms + _ => todo!() + } + } + + fn _defs(&self) -> Vec { + match self.op { + Opcode::Illegal => vec![], + #def_match_arms + _ => todo!() + } + } + + fn _uses(&self) -> Vec { + match self.op { + Opcode::Illegal => vec![], + #use_match_arms _ => todo!() } } diff --git a/macros/src/isa.yaml b/macros/src/isa.yaml index 8f30710..b7651d4 100644 --- a/macros/src/isa.yaml +++ b/macros/src/isa.yaml @@ -103,9 +103,6 @@ fields: - name: "crm" arg: "OpaqueU" bits: "12..20" - - name: "cmpL" - arg: "OpaqueU" - bits: "10" # Paired single fields - name: "ps_l" arg: "GQR" @@ -134,6 +131,9 @@ fields: arg: "OpaqueU" desc: "Bitset for tw and twi" bits: "6..11" + - name: "xer" + - name: "ctr" + - name: "lr" # TODO Add defs/uses for modifiers. modifiers: @@ -296,7 +296,7 @@ opcodes: desc: "Compare" bitmask: 0xfc4007ff pattern: 0x7c000000 - args: [ "crfD", "cmpL", "rA", "rB" ] + args: [ "crfD", "rA", "rB" ] defs: [ "crfD" ] uses: [ "rA", "rB" ] @@ -304,7 +304,7 @@ opcodes: desc: "Compare Immediate" bitmask: 0xfc400000 pattern: 0x2c000000 - args: [ "crfD", "cmpL", "rA", "simm" ] + args: [ "crfD", "rA", "simm" ] defs: [ "crfD" ] uses: [ "rA" ] @@ -312,7 +312,7 @@ opcodes: desc: "Compare Logical" bitmask: 0xfc4007ff pattern: 0x7c000040 - args: [ "crfD", "cmpL", "rA", "rB" ] + args: [ "crfD", "rA", "rB" ] defs: [ "crfD" ] uses: [ "rA", "rB" ] @@ -320,7 +320,7 @@ opcodes: desc: "Compare Logical Immediate" bitmask: 0xfc400000 pattern: 0x28000000 - args: [ "crfD", "cmpL", "rA", "uimm" ] + args: [ "crfD", "rA", "uimm" ] defs: [ "crfD" ] uses: [ "rA" ] @@ -2005,60 +2005,42 @@ mnemonics: match: - arg: "crfD" value: 0 - - arg: "cmpL" - value: 0 - name: "cmpw" opcode: "cmp" args: [ "crfD", "rA", "rB" ] - match: - - arg: "cmpL" - value: 0 - name: "cmplw" opcode: "cmpl" args: [ "rA", "rB" ] match: - arg: "crfD" value: 0 - - arg: "cmpL" - value: 0 - name: "cmplw" opcode: "cmpl" args: [ "crfD", "rA", "rB" ] - match: - - arg: "cmpL" - value: 0 - name: "cmpwi" opcode: "cmpi" args: [ "rA", "simm" ] match: - arg: "crfD" value: 0 - - arg: "cmpL" - value: 0 - name: "cmpwi" opcode: "cmpi" args: [ "crfD", "rA", "simm" ] match: - arg: "crfD" value: 0 - - arg: "cmpL" - value: 0 - name: "cmplwi" opcode: "cmpli" args: [ "rA", "uimm" ] match: - arg: "crfD" value: 0 - - arg: "cmpL" - value: 0 - name: "cmplwi" opcode: "cmpli" args: [ "crfD", "rA", "uimm" ] match: - arg: "crfD" value: 0 - - arg: "cmpL" - value: 0 # Misc - name: "twgti"