generate def/use information
This commit is contained in:
parent
d0409f599b
commit
5833e81236
|
@ -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!();
|
||||
|
|
|
@ -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) => {{
|
||||
|
|
|
@ -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!()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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"
|
||||
|
|
Loading…
Reference in New Issue