generate def/use information

This commit is contained in:
Richard Patel 2021-08-29 04:25:39 +02:00
parent d0409f599b
commit 5833e81236
4 changed files with 186 additions and 49 deletions

View File

@ -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<Field> {
self._fields() // auto-generated
}
/// Gets the defs of an instruction.
pub fn defs(&self) -> Vec<Field> {
self._defs() // auto-generated
}
/// Gets the uses of an instruction.
pub fn uses(&self) -> Vec<Field> {
self._uses() // auto-generated
}
}
ins_impl!();

View File

@ -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) => {{

View File

@ -36,12 +36,16 @@ pub(crate) struct Field {
bits: BitRange,
signed: bool,
split: bool,
arg: String,
arg: Option<String>,
}
impl Field {
fn variant_identifier(&self) -> TokenTree {
to_rust_ident(&self.name)
fn variant_identifier(&self) -> Option<TokenTree> {
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<TokenStream> {
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<TokenStream> {
// 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<Field> {
match self.op {
Opcode::Illegal => vec![],
#match_arms
#field_match_arms
_ => todo!()
}
}
fn _defs(&self) -> Vec<Field> {
match self.op {
Opcode::Illegal => vec![],
#def_match_arms
_ => todo!()
}
}
fn _uses(&self) -> Vec<Field> {
match self.op {
Opcode::Illegal => vec![],
#use_match_arms
_ => todo!()
}
}

View File

@ -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"